]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #94839 - TaKO8Ki:suggest-using-double-colon-for-struct-field-type...
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>
Fri, 11 Mar 2022 19:29:47 +0000 (20:29 +0100)
committerGitHub <noreply@github.com>
Fri, 11 Mar 2022 19:29:47 +0000 (20:29 +0100)
Suggest using double colon when a struct field type include single colon

#92685

770 files changed:
Cargo.lock
Cargo.toml
compiler/rustc_ast/src/util/literal.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_passes/Cargo.toml
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_ast_passes/src/lib.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_borrowck/Cargo.toml
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_borrowck/src/diagnostics/move_errors.rs
compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
compiler/rustc_borrowck/src/location.rs
compiler/rustc_borrowck/src/nll.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/type_check/free_region_relations.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_codegen_cranelift/src/abi/comments.rs
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
compiler/rustc_codegen_gcc/src/common.rs
compiler/rustc_codegen_gcc/src/consts.rs
compiler/rustc_codegen_gcc/src/context.rs
compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
compiler/rustc_codegen_llvm/src/attributes.rs
compiler/rustc_codegen_llvm/src/back/lto.rs
compiler/rustc_codegen_llvm/src/common.rs
compiler/rustc_codegen_llvm/src/consts.rs
compiler/rustc_codegen_llvm/src/context.rs
compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
compiler/rustc_codegen_llvm/src/intrinsic.rs
compiler/rustc_codegen_llvm/src/llvm_util.rs
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
compiler/rustc_codegen_ssa/src/traits/consts.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/const_eval/machine.rs
compiler/rustc_const_eval/src/const_eval/mod.rs
compiler/rustc_const_eval/src/interpret/cast.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/intern.rs
compiler/rustc_const_eval/src/interpret/intrinsics.rs
compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/operator.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/check_consts/ops.rs
compiler/rustc_data_structures/Cargo.toml
compiler/rustc_data_structures/src/intern.rs
compiler/rustc_data_structures/src/lib.rs
compiler/rustc_data_structures/src/small_c_str.rs
compiler/rustc_data_structures/src/small_str.rs [new file with mode: 0644]
compiler/rustc_data_structures/src/small_str/tests.rs [new file with mode: 0644]
compiler/rustc_data_structures/src/transitive_relation.rs
compiler/rustc_data_structures/src/transitive_relation/tests.rs
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/diagnostic_builder.rs
compiler/rustc_errors/src/emitter.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_expand/src/lib.rs
compiler/rustc_expand/src/mbe.rs
compiler/rustc_expand/src/mbe/macro_check.rs
compiler/rustc_expand/src/mbe/macro_parser.rs
compiler/rustc_expand/src/mbe/macro_rules.rs
compiler/rustc_expand/src/mbe/metavar_expr.rs [new file with mode: 0644]
compiler/rustc_expand/src/mbe/quoted.rs
compiler/rustc_expand/src/mbe/transcribe.rs
compiler/rustc_feature/src/accepted.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_hir/src/hir_id.rs
compiler/rustc_hir/src/lib.rs
compiler/rustc_index/src/bit_set.rs
compiler/rustc_infer/src/infer/free_regions.rs
compiler/rustc_infer/src/infer/glb.rs
compiler/rustc_infer/src/infer/higher_ranked/mod.rs
compiler/rustc_infer/src/infer/lattice.rs
compiler/rustc_infer/src/infer/lub.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/levels.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_macros/src/newtype.rs
compiler/rustc_metadata/src/native_libs.rs
compiler/rustc_middle/src/arena.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/middle/region.rs
compiler/rustc_middle/src/mir/coverage.rs
compiler/rustc_middle/src/mir/interpret/allocation.rs
compiler/rustc_middle/src/mir/interpret/error.rs
compiler/rustc_middle/src/mir/interpret/mod.rs
compiler/rustc_middle/src/mir/interpret/queries.rs
compiler/rustc_middle/src/mir/interpret/value.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/pretty.rs
compiler/rustc_middle/src/mir/tcx.rs
compiler/rustc_middle/src/mir/visit.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/thir/visit.rs
compiler/rustc_middle/src/ty/closure.rs
compiler/rustc_middle/src/ty/codec.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_mir_build/src/build/cfg.rs
compiler/rustc_mir_build/src/build/expr/as_constant.rs
compiler/rustc_mir_build/src/build/expr/into.rs
compiler/rustc_mir_build/src/build/misc.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_mir_build/src/thir/pattern/check_match.rs
compiler/rustc_mir_dataflow/src/move_paths/mod.rs
compiler/rustc_mir_transform/Cargo.toml
compiler/rustc_mir_transform/src/check_unsafety.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/coverage/graph.rs
compiler/rustc_mir_transform/src/instcombine.rs
compiler/rustc_mir_transform/src/simplify_try.rs
compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
compiler/rustc_monomorphize/src/collector.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/parse.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_target/src/lib.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/fulfill.rs
compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/normalize.rs
compiler/rustc_typeck/src/check/cast.rs
compiler/rustc_typeck/src/check/check.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/method/suggest.rs
compiler/rustc_typeck/src/check/mod.rs
compiler/rustc_typeck/src/check/upvar.rs
compiler/rustc_typeck/src/expr_use_visitor.rs
library/alloc/src/alloc.rs
library/alloc/src/borrow.rs
library/alloc/src/boxed.rs
library/alloc/src/collections/binary_heap.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/map/entry.rs
library/alloc/src/collections/btree/map/tests.rs
library/alloc/src/collections/btree/node.rs
library/alloc/src/collections/btree/set.rs
library/alloc/src/collections/btree/set/tests.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/fmt.rs
library/alloc/src/lib.rs
library/alloc/src/rc/tests.rs
library/alloc/src/slice.rs
library/alloc/src/string.rs
library/alloc/src/sync.rs
library/alloc/src/sync/tests.rs
library/alloc/src/tests.rs
library/alloc/src/vec/mod.rs
library/alloc/tests/boxed.rs
library/alloc/tests/fmt.rs
library/alloc/tests/linked_list.rs
library/alloc/tests/slice.rs
library/alloc/tests/str.rs
library/alloc/tests/string.rs
library/alloc/tests/vec.rs
library/alloc/tests/vec_deque.rs
library/core/benches/num/flt2dec/mod.rs
library/core/benches/num/flt2dec/strategy/grisu.rs
library/core/src/any.rs
library/core/src/array/mod.rs
library/core/src/ascii.rs
library/core/src/cell.rs
library/core/src/char/convert.rs
library/core/src/char/methods.rs
library/core/src/clone.rs
library/core/src/convert/mod.rs
library/core/src/fmt/mod.rs
library/core/src/future/into_future.rs
library/core/src/hint.rs
library/core/src/iter/adapters/map.rs
library/core/src/iter/mod.rs
library/core/src/iter/sources/once.rs
library/core/src/iter/sources/once_with.rs
library/core/src/iter/traits/collect.rs
library/core/src/iter/traits/double_ended.rs
library/core/src/iter/traits/iterator.rs
library/core/src/lib.rs
library/core/src/macros/mod.rs
library/core/src/marker.rs
library/core/src/num/dec2flt/mod.rs
library/core/src/num/error.rs
library/core/src/num/int_macros.rs
library/core/src/num/mod.rs
library/core/src/num/nonzero.rs
library/core/src/num/uint_macros.rs
library/core/src/ops/index.rs
library/core/src/ops/range.rs
library/core/src/option.rs
library/core/src/panic/panic_info.rs
library/core/src/panicking.rs
library/core/src/pin.rs
library/core/src/primitive_docs.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/ptr/non_null.rs
library/core/src/ptr/unique.rs
library/core/src/result.rs
library/core/src/slice/index.rs
library/core/src/slice/iter.rs
library/core/src/slice/mod.rs
library/core/src/str/mod.rs
library/core/src/str/traits.rs
library/core/src/sync/atomic.rs
library/core/src/time.rs
library/core/src/unit.rs
library/core/tests/any.rs
library/core/tests/cell.rs
library/core/tests/fmt/builders.rs
library/core/tests/fmt/mod.rs
library/core/tests/fmt/num.rs
library/core/tests/iter/traits/iterator.rs
library/core/tests/lazy.rs
library/core/tests/lib.rs
library/core/tests/num/dec2flt/mod.rs
library/core/tests/num/dec2flt/parse.rs
library/core/tests/num/flt2dec/mod.rs
library/core/tests/num/flt2dec/random.rs
library/core/tests/ptr.rs
library/core/tests/result.rs
library/portable-simd/crates/core_simd/examples/nbody.rs
library/proc_macro/src/lib.rs
library/std/src/alloc.rs
library/std/src/backtrace/tests.rs
library/std/src/collections/hash/map.rs
library/std/src/collections/hash/map/tests.rs
library/std/src/collections/hash/set.rs
library/std/src/collections/hash/set/tests.rs
library/std/src/collections/mod.rs
library/std/src/env.rs
library/std/src/error.rs
library/std/src/error/tests.rs
library/std/src/ffi/c_str.rs
library/std/src/ffi/c_str/tests.rs
library/std/src/fs.rs
library/std/src/fs/tests.rs
library/std/src/io/buffered/bufreader.rs
library/std/src/io/error.rs
library/std/src/io/error/repr_bitpacked.rs
library/std/src/io/error/tests.rs
library/std/src/io/mod.rs
library/std/src/io/stdio.rs
library/std/src/keyword_docs.rs
library/std/src/lib.rs
library/std/src/net/addr/tests.rs
library/std/src/net/tcp.rs
library/std/src/net/tcp/tests.rs
library/std/src/net/udp.rs
library/std/src/net/udp/tests.rs
library/std/src/os/unix/fs.rs
library/std/src/os/unix/net/addr.rs
library/std/src/os/unix/net/ancillary.rs
library/std/src/os/unix/net/datagram.rs
library/std/src/os/unix/net/listener.rs
library/std/src/os/unix/net/stream.rs
library/std/src/os/unix/net/tests.rs
library/std/src/panicking.rs
library/std/src/path.rs
library/std/src/path/tests.rs
library/std/src/primitive_docs.rs
library/std/src/process.rs
library/std/src/process/tests.rs
library/std/src/sync/mod.rs
library/std/src/sync/mpsc/mod.rs
library/std/src/sync/mpsc/shared.rs
library/std/src/sync/mutex/tests.rs
library/std/src/sync/poison.rs
library/std/src/sync/rwlock/tests.rs
library/std/src/sys/sgx/abi/mod.rs
library/std/src/sys/sgx/abi/usercalls/mod.rs
library/std/src/sys/sgx/abi/usercalls/raw.rs
library/std/src/sys/sgx/net.rs
library/std/src/sys/sgx/os.rs
library/std/src/sys/sgx/stdio.rs
library/std/src/sys/solid/mod.rs
library/std/src/sys/solid/net.rs
library/std/src/sys/solid/os.rs
library/std/src/sys/unix/fs.rs
library/std/src/sys/unix/net.rs
library/std/src/sys/unix/os_str/tests.rs
library/std/src/sys/unix/process/process_fuchsia.rs
library/std/src/sys/unix/process/process_unix.rs
library/std/src/sys/unix/process/process_vxworks.rs
library/std/src/sys/unix/rand.rs
library/std/src/sys/unix/rwlock.rs
library/std/src/sys/windows/mod.rs
library/std/src/sys/windows/os.rs
library/std/src/sys/windows/process/tests.rs
library/std/src/sys/windows/thread_parker.rs
library/std/src/sys_common/backtrace.rs
library/std/src/sys_common/net/tests.rs
library/std/src/sys_common/thread_parker/generic.rs
library/std/src/sys_common/wtf8.rs
library/std/src/sys_common/wtf8/tests.rs
library/std/src/thread/mod.rs
library/std/src/thread/scoped.rs
library/std/src/thread/tests.rs
library/std/src/time.rs
library/std/src/time/tests.rs
library/test/src/cli.rs
library/test/src/console.rs
library/test/src/formatters/junit.rs
library/test/src/formatters/pretty.rs
library/test/src/formatters/terse.rs
library/test/src/helpers/concurrency.rs
library/test/src/helpers/exit_code.rs
library/test/src/lib.rs
library/test/src/term/terminfo/parm.rs
library/test/src/term/terminfo/parm/tests.rs
library/test/src/term/terminfo/parser/compiled.rs
library/test/src/test_result.rs
library/unwind/src/libunwind.rs
src/bootstrap/Cargo.toml
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/builder/tests.rs
src/bootstrap/config.rs
src/bootstrap/configure.py
src/bootstrap/flags.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/setup.rs
src/bootstrap/test.rs
src/bootstrap/util.rs
src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
src/doc/rustdoc/book.toml
src/doc/rustdoc/src/SUMMARY.md
src/doc/rustdoc/src/advanced-features.md
src/doc/rustdoc/src/command-line-arguments.md
src/doc/rustdoc/src/deprecated-features.md [new file with mode: 0644]
src/doc/rustdoc/src/documentation-tests.md [deleted file]
src/doc/rustdoc/src/how-to-read-rustdoc.md
src/doc/rustdoc/src/how-to-write-documentation.md
src/doc/rustdoc/src/linking-to-items-by-name.md [deleted file]
src/doc/rustdoc/src/lints.md
src/doc/rustdoc/src/passes.md [deleted file]
src/doc/rustdoc/src/the-doc-attribute.md [deleted file]
src/doc/rustdoc/src/unstable-features.md
src/doc/rustdoc/src/website-features.md [deleted file]
src/doc/rustdoc/src/what-to-include.md [deleted file]
src/doc/rustdoc/src/write-documentation/documentation-tests.md [new file with mode: 0644]
src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md [new file with mode: 0644]
src/doc/rustdoc/src/write-documentation/the-doc-attribute.md [new file with mode: 0644]
src/doc/rustdoc/src/write-documentation/what-to-include.md [new file with mode: 0644]
src/doc/unstable-book/src/compiler-flags/sanitizer.md
src/doc/unstable-book/src/language-features/box-patterns.md
src/librustdoc/Cargo.toml
src/librustdoc/clean/mod.rs
src/librustdoc/clean/utils.rs
src/librustdoc/doctest.rs
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/sources.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/js/main.js
src/librustdoc/markdown.rs
src/llvm-project
src/test/assembly/sparc-struct-abi.rs
src/test/assembly/target-feature-multiple.rs
src/test/codegen/abi-sysv64.rs
src/test/codegen/abi-x86-interrupt.rs
src/test/codegen/frame-pointer.rs
src/test/codegen/inline-hint.rs
src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
src/test/codegen/target-feature-overrides.rs
src/test/mir-opt/combine_clone_of_primitives.rs [new file with mode: 0644]
src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff [new file with mode: 0644]
src/test/mir-opt/inline/inline_generator.main.Inline.diff
src/test/mir-opt/inline/issue_78442.bar.Inline.diff
src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
src/test/rustdoc-gui/docblock-table-overflow.goml
src/test/rustdoc-gui/hash-item-expansion.goml
src/test/rustdoc-gui/impl-default-expansion.goml
src/test/rustdoc-gui/mobile.goml
src/test/rustdoc-gui/source-code-page.goml
src/test/rustdoc-gui/toggle-docs-mobile.goml
src/test/rustdoc-gui/toggle-docs.goml
src/test/rustdoc/const-generics/generic_const_exprs.rs
src/test/rustdoc/duplicate_impls/issue-33054.rs
src/test/rustdoc/generic-associated-types/issue-94683.rs [new file with mode: 0644]
src/test/rustdoc/rfc-2632-const-trait-impl.rs [new file with mode: 0644]
src/test/ui/associated-consts/defaults-cyclic-fail.rs
src/test/ui/associated-types/issue-59324.rs
src/test/ui/associated-types/issue-59324.stderr
src/test/ui/async-await/await-into-future.rs
src/test/ui/async-await/edition-deny-async-fns-2015.stderr
src/test/ui/async-await/suggest-switching-edition-on-await-cargo.rs [new file with mode: 0644]
src/test/ui/async-await/suggest-switching-edition-on-await-cargo.stderr [new file with mode: 0644]
src/test/ui/async-await/suggest-switching-edition-on-await.rs
src/test/ui/async-await/suggest-switching-edition-on-await.stderr
src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr
src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr
src/test/ui/borrowck/borrowck-move-by-capture.stderr
src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr
src/test/ui/borrowck/copy-suggestion-region-vid.rs [new file with mode: 0644]
src/test/ui/borrowck/copy-suggestion-region-vid.stderr [new file with mode: 0644]
src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr
src/test/ui/borrowck/issue-88434-minimal-example.rs
src/test/ui/borrowck/issue-88434-minimal-example.stderr
src/test/ui/borrowck/issue-88434-removal-index-should-be-less.rs
src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
src/test/ui/cast/fat-ptr-cast.rs
src/test/ui/cast/fat-ptr-cast.stderr
src/test/ui/check-cfg/well-known-names.rs
src/test/ui/check-cfg/well-known-values.rs
src/test/ui/check-cfg/well-known-values.stderr
src/test/ui/closures/2229_closure_analysis/match/issue-88331.stderr
src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr
src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs
src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs
src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs
src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs
src/test/ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/issue-85848.rs
src/test/ui/const-generics/generic_const_exprs/issue-94287.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-79674.rs
src/test/ui/consts/auxiliary/const_fn_lib.rs
src/test/ui/consts/const-block-const-bound.rs
src/test/ui/consts/const-eval/const-eval-query-stack.rs
src/test/ui/consts/const-eval/const_fn_ptr.stderr
src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
src/test/ui/consts/const-eval/issue-49296.rs
src/test/ui/consts/const-eval/issue-49296.stderr
src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs
src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs
src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr
src/test/ui/consts/const-fn.rs
src/test/ui/consts/const-match-check.eval1.stderr
src/test/ui/consts/const-match-check.eval2.stderr
src/test/ui/consts/const-match-check.matchck.stderr
src/test/ui/consts/const_fn_trait_bound.gated.stderr [deleted file]
src/test/ui/consts/const_fn_trait_bound.rs [deleted file]
src/test/ui/consts/const_fn_trait_bound.stock.stderr [deleted file]
src/test/ui/consts/drop_box.rs [new file with mode: 0644]
src/test/ui/consts/drop_box.stderr [new file with mode: 0644]
src/test/ui/consts/issue-37550-1.rs
src/test/ui/consts/issue-37550-1.stderr [deleted file]
src/test/ui/consts/issue-37550.rs
src/test/ui/consts/issue-46553.rs
src/test/ui/consts/issue-56164.rs
src/test/ui/consts/issue-56164.stderr
src/test/ui/consts/issue-88071.rs
src/test/ui/consts/issue-94675.rs [new file with mode: 0644]
src/test/ui/consts/issue-94675.stderr [new file with mode: 0644]
src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs [deleted file]
src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr [deleted file]
src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
src/test/ui/consts/min_const_fn/cast_errors.rs [deleted file]
src/test/ui/consts/min_const_fn/cast_errors.stderr [deleted file]
src/test/ui/consts/min_const_fn/cast_fn.rs [new file with mode: 0644]
src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs
src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr
src/test/ui/consts/min_const_fn/min_const_fn.rs
src/test/ui/consts/min_const_fn/min_const_fn.stderr
src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr [deleted file]
src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs [deleted file]
src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr [deleted file]
src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs [deleted file]
src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr [deleted file]
src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
src/test/ui/consts/offset_from_ub.rs
src/test/ui/consts/offset_from_ub.stderr
src/test/ui/consts/offset_ub.stderr
src/test/ui/consts/unstable-const-fn-in-libcore.rs
src/test/ui/consts/unstable-const-fn-in-libcore.stderr
src/test/ui/debuginfo/debuginfo-box-with-large-allocator.rs [new file with mode: 0644]
src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs
src/test/ui/deprecation/deprecation-in-staged-api.rs [deleted file]
src/test/ui/deprecation/deprecation-in-staged-api.stderr [deleted file]
src/test/ui/deprecation/feature-gate-deprecated_suggestion.rs [new file with mode: 0644]
src/test/ui/deprecation/feature-gate-deprecated_suggestion.stderr [new file with mode: 0644]
src/test/ui/deprecation/rustc_deprecation-in-future.rs [deleted file]
src/test/ui/deprecation/rustc_deprecation-in-future.stderr [deleted file]
src/test/ui/deprecation/staged-deprecation-in-future.rs [new file with mode: 0644]
src/test/ui/deprecation/staged-deprecation-in-future.stderr [new file with mode: 0644]
src/test/ui/deprecation/suggestion.fixed
src/test/ui/deprecation/suggestion.rs
src/test/ui/deprecation/suggestion.stderr
src/test/ui/editions/async-block-2015.rs
src/test/ui/editions/async-block-2015.stderr
src/test/ui/empty/empty-attributes.rs
src/test/ui/empty/empty-attributes.stderr
src/test/ui/empty/empty-never-array.stderr
src/test/ui/error-codes/E0004-2.stderr
src/test/ui/error-codes/E0004.stderr
src/test/ui/error-codes/E0005.stderr
src/test/ui/error-codes/E0297.stderr
src/test/ui/error-codes/E0507.stderr
src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr
src/test/ui/feature-gates/feature-gate-rustc-attrs-1.rs
src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr
src/test/ui/feature-gates/feature-gate-test_unstable_lint.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-test_unstable_lint.stderr [new file with mode: 0644]
src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.rs [deleted file]
src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.stderr [deleted file]
src/test/ui/generic-associated-types/issue-90729.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-91139.migrate.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-91139.rs
src/test/ui/generic-associated-types/issue-93341.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-93342.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr [deleted file]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
src/test/ui/impl-trait/issues/issue-79099.stderr
src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs
src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr
src/test/ui/issues/issue-17337.rs
src/test/ui/issues/issue-21596.stderr
src/test/ui/issues/issue-23036.rs
src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr
src/test/ui/issues/issue-61108.stderr
src/test/ui/issues/issue-64559.stderr
src/test/ui/issues/issue-87707.rs
src/test/ui/issues/issue-87707.run.stderr
src/test/ui/lint/auxiliary/inherited_stability.rs
src/test/ui/lint/auxiliary/lint_output_format.rs
src/test/ui/lint/auxiliary/lint_stability.rs
src/test/ui/lint/auxiliary/lint_stability_fields.rs
src/test/ui/lint/lint-stability-2.rs
src/test/ui/lint/lint-stability-deprecated.rs
src/test/ui/lint/lint-stability-fields-deprecated.rs
src/test/ui/lint/lint-stability-fields.rs
src/test/ui/lint/lint-stability.rs
src/test/ui/lint/must_not_suspend/gated.rs
src/test/ui/lint/must_not_suspend/gated.stderr
src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs [new file with mode: 0644]
src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr [new file with mode: 0644]
src/test/ui/loops/issue-82916.stderr
src/test/ui/lto/lto-duplicate-symbols.stderr
src/test/ui/macros/auxiliary/unstable-macros.rs
src/test/ui/macros/macro-stability.rs
src/test/ui/macros/macro-stability.stderr
src/test/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs [new file with mode: 0644]
src/test/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs [new file with mode: 0644]
src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs [new file with mode: 0644]
src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr [new file with mode: 0644]
src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs [new file with mode: 0644]
src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr [new file with mode: 0644]
src/test/ui/match/match_non_exhaustive.stderr
src/test/ui/methods/issues/issue-94581.rs [new file with mode: 0644]
src/test/ui/methods/issues/issue-94581.stderr [new file with mode: 0644]
src/test/ui/methods/method-call-err-msg.rs
src/test/ui/methods/method-call-err-msg.stderr
src/test/ui/mismatched_types/cast-rfc0401.rs
src/test/ui/mismatched_types/cast-rfc0401.stderr
src/test/ui/mismatched_types/issue-36053-2.rs
src/test/ui/mismatched_types/issue-36053-2.stderr
src/test/ui/moves/issue-46099-move-in-macro.stderr
src/test/ui/moves/move-fn-self-receiver.stderr
src/test/ui/moves/move-in-guard-2.stderr
src/test/ui/nll/issue-55825-const-fn.rs
src/test/ui/nll/issue-55825-const-fn.stderr [deleted file]
src/test/ui/nll/lint-no-err.rs [new file with mode: 0644]
src/test/ui/nll/lint-no-err.stderr [new file with mode: 0644]
src/test/ui/nll/match-guards-always-borrow.stderr
src/test/ui/on-unimplemented/impl-substs.rs [new file with mode: 0644]
src/test/ui/on-unimplemented/impl-substs.stderr [new file with mode: 0644]
src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
src/test/ui/pattern/usefulness/empty-match.normal.stderr
src/test/ui/pattern/usefulness/floats.stderr
src/test/ui/pattern/usefulness/guards.stderr
src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
src/test/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr
src/test/ui/pattern/usefulness/issue-15129.stderr
src/test/ui/pattern/usefulness/issue-2111.stderr
src/test/ui/pattern/usefulness/issue-30240.stderr
src/test/ui/pattern/usefulness/issue-3096-1.stderr
src/test/ui/pattern/usefulness/issue-3096-2.stderr
src/test/ui/pattern/usefulness/issue-31561.stderr
src/test/ui/pattern/usefulness/issue-35609.stderr
src/test/ui/pattern/usefulness/issue-3601.stderr
src/test/ui/pattern/usefulness/issue-39362.stderr
src/test/ui/pattern/usefulness/issue-40221.stderr
src/test/ui/pattern/usefulness/issue-4321.stderr
src/test/ui/pattern/usefulness/issue-50900.stderr
src/test/ui/pattern/usefulness/issue-56379.stderr
src/test/ui/pattern/usefulness/issue-72377.stderr
src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs
src/test/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr
src/test/ui/pattern/usefulness/match-arm-statics-2.stderr
src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
src/test/ui/pattern/usefulness/match-non-exhaustive.stderr
src/test/ui/pattern/usefulness/match-privately-empty.stderr
src/test/ui/pattern/usefulness/match-slice-patterns.stderr
src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs
src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr
src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr
src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr
src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
src/test/ui/pattern/usefulness/stable-gated-patterns.stderr
src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr
src/test/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr
src/test/ui/pattern/usefulness/type_polymorphic_byte_str_literals.stderr
src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr
src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr
src/test/ui/rfc-2005-default-binding-mode/slice.stderr
src/test/ui/rfc-2008-non-exhaustive/enum.stderr
src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-chain.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-pass.rs
src/test/ui/rfc-2632-const-trait-impl/const-closures.rs
src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs
src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs
src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs
src/test/ui/rfc-2632-const-trait-impl/generic-bound.rs
src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs
src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr
src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs
src/test/ui/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs
src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
src/test/ui/rfc-2632-const-trait-impl/issue-92111.rs
src/test/ui/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs
src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs
src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs
src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs
src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs
src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs
src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr
src/test/ui/stability-attribute/auxiliary/lint-stability.rs
src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs
src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.rs
src/test/ui/stability-attribute/stability-attribute-non-staged-force-unstable.stderr
src/test/ui/stability-attribute/stability-attribute-non-staged.rs
src/test/ui/stability-attribute/stability-attribute-non-staged.stderr
src/test/ui/stability-attribute/stability-attribute-sanity-4.rs
src/test/ui/stability-attribute/stability-attribute-sanity-4.stderr
src/test/ui/stability-attribute/stability-attribute-sanity.rs
src/test/ui/stability-attribute/stability-attribute-sanity.stderr
src/test/ui/str/str-idx.stderr
src/test/ui/str/str-mut-idx.stderr
src/test/ui/suggestions/borrow-for-loop-head.stderr
src/test/ui/suggestions/for-i-in-vec.stderr
src/test/ui/suggestions/option-content-move2.stderr
src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.rs [new file with mode: 0644]
src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.stderr [new file with mode: 0644]
src/test/ui/tuple/wrong_argument_ice-4.rs [new file with mode: 0644]
src/test/ui/tuple/wrong_argument_ice-4.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
src/test/ui/type-alias-impl-trait/issue-53096.rs
src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs
src/test/ui/type-alias-impl-trait/issue-89686.rs
src/test/ui/type-alias-impl-trait/issue-89686.stderr
src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr
src/test/ui/type-alias-impl-trait/structural-match.rs
src/test/ui/type-alias-impl-trait/structural-match.stderr
src/test/ui/unboxed-closures/issue-53448.rs
src/test/ui/unboxed-closures/issue-53448.stderr [deleted file]
src/test/ui/uninhabited/uninhabited-irrefutable.rs
src/test/ui/uninhabited/uninhabited-irrefutable.stderr
src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs [new file with mode: 0644]
src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs [new file with mode: 0644]
src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs [new file with mode: 0644]
src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr [new file with mode: 0644]
src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs [new file with mode: 0644]
src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr [new file with mode: 0644]
src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs [new file with mode: 0644]
src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr [new file with mode: 0644]
src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs [new file with mode: 0644]
src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr [new file with mode: 0644]
src/tools/cargo
src/tools/clippy/Cargo.toml
src/tools/clippy/clippy_dev/Cargo.toml
src/tools/clippy/clippy_lints/Cargo.toml
src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
src/tools/clippy/clippy_lints/src/redundant_clone.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
src/tools/clippy/clippy_utils/src/consts.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
src/tools/linkchecker/main.rs
src/tools/miri
src/tools/rust-analyzer
src/tools/rustdoc-gui/tester.js
src/tools/rustfmt/Cargo.toml
src/tools/tidy/src/bins.rs
src/tools/tidy/src/deps.rs
src/tools/tidy/src/error_codes_check.rs
src/tools/tidy/src/features.rs
src/tools/tidy/src/primitive_docs.rs
src/tools/tidy/src/style.rs
src/tools/tidy/src/target_specific_tests.rs
src/tools/unicode-table-generator/src/main.rs
src/tools/unicode-table-generator/src/unicode_download.rs
src/tools/unstable-book-gen/src/main.rs
src/tools/x/src/main.rs
triagebot.toml

index 2ee9a872d3ee244a0ab1e5b32175a2d3db2fc355..4d7b62e9c559fb65ed536d392a425c67becddbd9 100644 (file)
@@ -337,7 +337,7 @@ dependencies = [
  "humantime 2.0.1",
  "ignore",
  "im-rc",
- "itertools 0.10.1",
+ "itertools",
  "jobserver",
  "lazy_static",
  "lazycell",
@@ -345,7 +345,6 @@ dependencies = [
  "libgit2-sys",
  "log",
  "memchr",
- "num_cpus",
  "opener",
  "openssl",
  "os_info",
@@ -442,7 +441,7 @@ dependencies = [
  "flate2",
  "git2",
  "glob",
- "itertools 0.10.1",
+ "itertools",
  "lazy_static",
  "remove_dir_all",
  "serde_json",
@@ -560,7 +559,7 @@ dependencies = [
  "chalk-ir",
  "ena",
  "indexmap",
- "itertools 0.10.1",
+ "itertools",
  "petgraph",
  "rustc-hash",
  "tracing",
@@ -624,7 +623,7 @@ dependencies = [
  "filetime",
  "futures 0.3.19",
  "if_chain",
- "itertools 0.10.1",
+ "itertools",
  "num_cpus",
  "parking_lot",
  "quote",
@@ -647,7 +646,7 @@ dependencies = [
  "cargo_metadata",
  "clap 2.34.0",
  "indoc",
- "itertools 0.10.1",
+ "itertools",
  "opener",
  "regex",
  "shell-escape",
@@ -661,7 +660,7 @@ dependencies = [
  "cargo_metadata",
  "clippy_utils",
  "if_chain",
- "itertools 0.10.1",
+ "itertools",
  "pulldown-cmark",
  "quine-mc_cluskey",
  "regex-syntax",
@@ -1503,9 +1502,9 @@ dependencies = [
 
 [[package]]
 name = "git2"
-version = "0.13.23"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a8057932925d3a9d9e4434ea016570d37420ddb1ceed45a174d577f24ed6700"
+checksum = "6e7d3b96ec1fcaa8431cf04a4f1ef5caafe58d5cf7bcc31f09c1626adddb0ffe"
 dependencies = [
  "bitflags",
  "libc",
@@ -1518,9 +1517,9 @@ dependencies = [
 
 [[package]]
 name = "git2-curl"
-version = "0.14.1"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "883539cb0ea94bab3f8371a98cd8e937bbe9ee7c044499184aa4c17deb643a50"
+checksum = "1ee51709364c341fbb6fe2a385a290fb9196753bdde2fc45447d27cd31b11b13"
 dependencies = [
  "curl",
  "git2",
@@ -1783,15 +1782,6 @@ dependencies = [
  "cfg-if 1.0.0",
 ]
 
-[[package]]
-name = "itertools"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
-dependencies = [
- "either",
-]
-
 [[package]]
 name = "itertools"
 version = "0.10.1"
@@ -1984,9 +1974,9 @@ dependencies = [
 
 [[package]]
 name = "libgit2-sys"
-version = "0.12.24+1.3.0"
+version = "0.13.1+1.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddbd6021eef06fb289a8f54b3c2acfdd85ff2a585dfbb24b8576325373d2152c"
+checksum = "43e598aa7a4faedf1ea1b4608f582b06f0f40211eec551b7ef36019ae3f62def"
 dependencies = [
  "cc",
  "libc",
@@ -2282,9 +2272,9 @@ dependencies = [
 
 [[package]]
 name = "minifier"
-version = "0.0.42"
+version = "0.0.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55a1388517eda8a68875243b650c26997e055a33d82571b5a0349129faef7d99"
+checksum = "d81352bda6f4d04af1720afaa762054f66e16caffd93c1f86461a1c0ac4e695e"
 dependencies = [
  "macro-utils",
 ]
@@ -3138,7 +3128,7 @@ dependencies = [
  "futures 0.3.19",
  "heck",
  "home",
- "itertools 0.10.1",
+ "itertools",
  "jsonrpc-core",
  "lazy_static",
  "log",
@@ -3180,7 +3170,7 @@ dependencies = [
  "derive-new",
  "env_logger 0.9.0",
  "fst",
- "itertools 0.10.1",
+ "itertools",
  "json",
  "lazy_static",
  "log",
@@ -3411,7 +3401,7 @@ dependencies = [
 name = "rustc_ast_passes"
 version = "0.0.0"
 dependencies = [
- "itertools 0.10.1",
+ "itertools",
  "rustc_ast",
  "rustc_ast_pretty",
  "rustc_attr",
@@ -3454,7 +3444,7 @@ name = "rustc_borrowck"
 version = "0.0.0"
 dependencies = [
  "either",
- "itertools 0.10.1",
+ "itertools",
  "polonius-engine",
  "rustc_const_eval",
  "rustc_data_structures",
@@ -3536,7 +3526,7 @@ version = "0.0.0"
 dependencies = [
  "bitflags",
  "cc",
- "itertools 0.10.1",
+ "itertools",
  "jobserver",
  "libc",
  "object 0.28.1",
@@ -4019,7 +4009,7 @@ name = "rustc_mir_transform"
 version = "0.0.0"
 dependencies = [
  "coverage_test_macros",
- "itertools 0.10.1",
+ "itertools",
  "rustc_ast",
  "rustc_attr",
  "rustc_const_eval",
@@ -4419,7 +4409,7 @@ dependencies = [
  "askama",
  "atty",
  "expect-test",
- "itertools 0.10.1",
+ "itertools",
  "minifier",
  "pulldown-cmark",
  "rayon",
@@ -4501,7 +4491,7 @@ dependencies = [
  "env_logger 0.8.4",
  "getopts",
  "ignore",
- "itertools 0.9.0",
+ "itertools",
  "lazy_static",
  "log",
  "regex",
@@ -5181,7 +5171,7 @@ checksum = "744e9ed5b352340aa47ce033716991b5589e23781acb97cad37d4ea70560f55b"
 dependencies = [
  "combine",
  "indexmap",
- "itertools 0.10.1",
+ "itertools",
  "kstring",
  "serde",
 ]
index cae48d795178388cbb4ee8487207a4d096fb7d55..4e78399606445837adb68b0d7b0789c77a218a03 100644 (file)
@@ -1,4 +1,5 @@
 [workspace]
+default-members = ["src/bootstrap"]
 members = [
   "src/bootstrap",
   "compiler/rustc",
index 231dd72af2c7d9100b6f50515823ffa3cdddf57f..9c18f55c03b4d28c091bf6cc411f215e7fc05c91 100644 (file)
@@ -23,7 +23,7 @@ pub enum LitError {
 
 impl LitKind {
     /// Converts literal token into a semantic literal.
-    fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
+    pub fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
         let token::Lit { kind, symbol, suffix } = lit;
         if suffix.is_some() && !kind.may_have_suffix() {
             return Err(LitError::InvalidSuffix);
index 940887280b9c18437f28152aeaa1ad9930eece8c..7a272308fb051af3e51861a78d23e8ff22369900 100644 (file)
@@ -2064,17 +2064,13 @@ fn lower_poly_trait_ref(
                 )),
                 _ => None,
             });
-            if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes, .. } =
-                itctx
-            {
+            if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes } = itctx {
                 capturable_lifetimes.extend(lt_def_names.clone());
             }
 
             let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow());
 
-            if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes, .. } =
-                itctx
-            {
+            if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes } = itctx {
                 for param in lt_def_names {
                     capturable_lifetimes.remove(&param);
                 }
index 45b70420338ddd98a77d14b17dc5393d466be8fe..22742b2adbd4fc3448c10c69f4ad7aa0b45b1908 100644 (file)
@@ -4,7 +4,7 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
-itertools = "0.10"
+itertools = "0.10.1"
 tracing = "0.1"
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_attr = { path = "../rustc_attr" }
index 0cf73178d679d09dd3c0c3cac4a89ab1069ced04..8f0b12cb4feef17d86420aa2181b40a9b63c2746 100644 (file)
@@ -64,8 +64,8 @@ struct AstValidator<'a> {
     /// certain positions.
     is_assoc_ty_bound_banned: bool,
 
-    /// Used to allow `let` expressions in certain syntactic locations.
-    is_let_allowed: bool,
+    /// See [ForbiddenLetReason]
+    forbidden_let_reason: Option<ForbiddenLetReason>,
 
     lint_buffer: &'a mut LintBuffer,
 }
@@ -103,20 +103,28 @@ fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
         self.is_tilde_const_allowed = old;
     }
 
-    fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
-        let old = mem::replace(&mut self.is_let_allowed, allowed);
+    fn with_let_management(
+        &mut self,
+        forbidden_let_reason: Option<ForbiddenLetReason>,
+        f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
+    ) {
+        let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
         f(self, old);
-        self.is_let_allowed = old;
+        self.forbidden_let_reason = old;
     }
 
     /// Emits an error banning the `let` expression provided in the given location.
-    fn ban_let_expr(&self, expr: &'a Expr) {
+    fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
         let sess = &self.session;
         if sess.opts.unstable_features.is_nightly_build() {
-            sess.struct_span_err(expr.span, "`let` expressions are not supported here")
-                .note("only supported directly in conditions of `if`- and `while`-expressions")
-                .note("as well as when nested within `&&` and parentheses in those conditions")
-                .emit();
+            let err = "`let` expressions are not supported here";
+            let mut diag = sess.struct_span_err(expr.span, err);
+            diag.note("only supported directly in conditions of `if` and `while` expressions");
+            diag.note("as well as when nested within `&&` and parentheses in those conditions");
+            if let ForbiddenLetReason::ForbiddenWithOr(span) = forbidden_let_reason {
+                diag.span_note(span, "`||` operators are not allowed in let chain expressions");
+            }
+            diag.emit();
         } else {
             sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
                 .note("variable declaration using `let` is a statement")
@@ -988,39 +996,48 @@ fn visit_attribute(&mut self, attr: &Attribute) {
     }
 
     fn visit_expr(&mut self, expr: &'a Expr) {
-        self.with_let_allowed(false, |this, let_allowed| match &expr.kind {
-            ExprKind::If(cond, then, opt_else) => {
-                this.visit_block(then);
-                walk_list!(this, visit_expr, opt_else);
-                this.with_let_allowed(true, |this, _| this.visit_expr(cond));
-                return;
-            }
-            ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
-            ExprKind::Match(expr, arms) => {
-                this.visit_expr(expr);
-                for arm in arms {
-                    this.visit_expr(&arm.body);
-                    this.visit_pat(&arm.pat);
-                    walk_list!(this, visit_attribute, &arm.attrs);
-                    if let Some(ref guard) = arm.guard {
-                        if let ExprKind::Let(_, ref expr, _) = guard.kind {
-                            this.with_let_allowed(true, |this, _| this.visit_expr(expr));
+        self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
+            match &expr.kind {
+                ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
+                    let forbidden_let_reason = Some(ForbiddenLetReason::ForbiddenWithOr(*span));
+                    this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(lhs));
+                    this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(rhs));
+                }
+                ExprKind::If(cond, then, opt_else) => {
+                    this.visit_block(then);
+                    walk_list!(this, visit_expr, opt_else);
+                    this.with_let_management(None, |this, _| this.visit_expr(cond));
+                    return;
+                }
+                ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
+                    this.ban_let_expr(expr, elem);
+                },
+                ExprKind::Match(scrutinee, arms) => {
+                    this.visit_expr(scrutinee);
+                    for arm in arms {
+                        this.visit_expr(&arm.body);
+                        this.visit_pat(&arm.pat);
+                        walk_list!(this, visit_attribute, &arm.attrs);
+                        if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
+                            this.with_let_management(None, |this, _| {
+                                this.visit_expr(guard_expr)
+                            });
                             return;
                         }
                     }
                 }
+                ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
+                    this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
+                    return;
+                }
+                ExprKind::While(cond, then, opt_label) => {
+                    walk_list!(this, visit_label, opt_label);
+                    this.visit_block(then);
+                    this.with_let_management(None, |this, _| this.visit_expr(cond));
+                    return;
+                }
+                _ => visit::walk_expr(this, expr),
             }
-            ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
-                this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
-                return;
-            }
-            ExprKind::While(cond, then, opt_label) => {
-                walk_list!(this, visit_label, opt_label);
-                this.visit_block(then);
-                this.with_let_allowed(true, |this, _| this.visit_expr(cond));
-                return;
-            }
-            _ => visit::walk_expr(this, expr),
         });
     }
 
@@ -1772,10 +1789,19 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
         is_tilde_const_allowed: false,
         is_impl_trait_banned: false,
         is_assoc_ty_bound_banned: false,
-        is_let_allowed: false,
+        forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
         lint_buffer: lints,
     };
     visit::walk_crate(&mut validator, krate);
 
     validator.has_proc_macro_decls
 }
+
+/// Used to forbid `let` expressions in certain syntactic locations.
+#[derive(Clone, Copy)]
+enum ForbiddenLetReason {
+    /// A let chain with the `||` operator
+    ForbiddenWithOr(Span),
+    /// `let` is not valid and the source environment is not important
+    GenericForbidden,
+}
index 570ec45557dea7ad1c1e599427978e6e5471fb28..097bd07c74ce8a5ba6dca07e3f11d9bb113c423e 100644 (file)
@@ -437,13 +437,6 @@ macro_rules! gate_modifier { ($($name:literal => $feature:ident)*) => {
                 )
                 .emit();
             }
-        } else {
-            if attr.has_name(sym::deprecated) {
-                self.sess
-                    .struct_span_err(attr.span, "`#[deprecated]` cannot be used in staged API")
-                    .span_label(attr.span, "use `#[rustc_deprecated]` instead")
-                    .emit();
-            }
         }
     }
 
index 876dd7f757c5a8c0f08023fb0fd7b3094547256e..9d52c32885db0232735272b69e08aa119763e6b4 100644 (file)
@@ -4,11 +4,13 @@
 //!
 //! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
 
-#![feature(iter_is_partitioned)]
+#![allow(rustc::potential_query_instability)]
 #![feature(box_patterns)]
+#![feature(if_let_guard)]
+#![feature(iter_is_partitioned)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![recursion_limit = "256"]
-#![allow(rustc::potential_query_instability)]
 
 pub mod ast_validation;
 pub mod feature_gate;
index 061fee7f569af40f85962dd0823394ea3058c703..613320087d2ddc33d4087b30a8dba03885bb59ef 100644 (file)
@@ -664,6 +664,7 @@ fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(Dep
 {
     let mut depr: Option<(Deprecation, Span)> = None;
     let diagnostic = &sess.parse_sess.span_diagnostic;
+    let is_rustc = sess.features_untracked().staged_api;
 
     'outer: for attr in attrs_iter {
         if !(attr.has_name(sym::deprecated) || attr.has_name(sym::rustc_deprecated)) {
@@ -728,17 +729,31 @@ fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(Dep
                                     continue 'outer;
                                 }
                             }
-                            sym::note if attr.has_name(sym::deprecated) => {
+                            sym::note => {
                                 if !get(mi, &mut note) {
                                     continue 'outer;
                                 }
                             }
+                            // FIXME(jhpratt) remove this after a bootstrap occurs. Emitting an
+                            // error specific to the renaming would be a good idea as well.
                             sym::reason if attr.has_name(sym::rustc_deprecated) => {
                                 if !get(mi, &mut note) {
                                     continue 'outer;
                                 }
                             }
-                            sym::suggestion if attr.has_name(sym::rustc_deprecated) => {
+                            sym::suggestion => {
+                                if !sess.features_untracked().deprecated_suggestion {
+                                    let mut diag = sess.struct_span_err(
+                                        mi.span,
+                                        "suggestions on deprecated items are unstable",
+                                    );
+                                    if sess.is_nightly_build() {
+                                        diag.help("add `#![feature(deprecated_suggestion)]` to the crate root");
+                                    }
+                                    // FIXME(jhpratt) change this to an actual tracking issue
+                                    diag.note("see #XXX for more details").emit();
+                                }
+
                                 if !get(mi, &mut suggestion) {
                                     continue 'outer;
                                 }
@@ -752,7 +767,7 @@ fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(Dep
                                         if attr.has_name(sym::deprecated) {
                                             &["since", "note"]
                                         } else {
-                                            &["since", "reason", "suggestion"]
+                                            &["since", "note", "suggestion"]
                                         },
                                     ),
                                 );
@@ -775,24 +790,22 @@ fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(Dep
             }
         }
 
-        if suggestion.is_some() && attr.has_name(sym::deprecated) {
-            unreachable!("only allowed on rustc_deprecated")
-        }
-
-        if attr.has_name(sym::rustc_deprecated) {
+        if is_rustc {
             if since.is_none() {
                 handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
                 continue;
             }
 
             if note.is_none() {
-                struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'").emit();
+                struct_span_err!(diagnostic, attr.span, E0543, "missing 'note'").emit();
                 continue;
             }
         }
 
-        let is_since_rustc_version = attr.has_name(sym::rustc_deprecated);
-        depr = Some((Deprecation { since, note, suggestion, is_since_rustc_version }, attr.span));
+        depr = Some((
+            Deprecation { since, note, suggestion, is_since_rustc_version: is_rustc },
+            attr.span,
+        ));
     }
 
     depr
index eb2fdbd07967d029f83f5ea2bbfdfef2a9141cb7..0b531623ba6f5e3f08683e14949caedecf6b7d3f 100644 (file)
@@ -8,7 +8,7 @@ doctest = false
 
 [dependencies]
 either = "1.5.0"
-itertools = "0.10"
+itertools = "0.10.1"
 tracing = "0.1"
 polonius-engine = "0.13.0"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
index 684a3ced5a0700725ab43d86dc20ce920cec2d3a..1cbca58ca2590f3ed28ae1d1088efb0984533f4c 100644 (file)
@@ -1,5 +1,5 @@
 use either::Either;
-use rustc_const_eval::util::{CallDesugaringKind, CallKind};
+use rustc_const_eval::util::CallKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
@@ -17,7 +17,7 @@
 };
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
 use rustc_span::symbol::sym;
-use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
+use rustc_span::{BytePos, MultiSpan, Span};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::TraitEngineExt as _;
 
@@ -195,144 +195,19 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                     is_loop_move = true;
                 }
 
-                if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
-                    let place_name = self
-                        .describe_place(moved_place.as_ref())
-                        .map(|n| format!("`{}`", n))
-                        .unwrap_or_else(|| "value".to_owned());
-                    match kind {
-                        CallKind::FnCall { fn_trait_id, .. }
-                            if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
-                        {
-                            err.span_label(
-                                fn_call_span,
-                                &format!(
-                                    "{} {}moved due to this call{}",
-                                    place_name, partially_str, loop_message
-                                ),
-                            );
-                            err.span_note(
-                                var_span,
-                                "this value implements `FnOnce`, which causes it to be moved when called",
-                            );
-                        }
-                        CallKind::Operator { self_arg, .. } => {
-                            let self_arg = self_arg.unwrap();
-                            err.span_label(
-                                fn_call_span,
-                                &format!(
-                                    "{} {}moved due to usage in operator{}",
-                                    place_name, partially_str, loop_message
-                                ),
-                            );
-                            if self.fn_self_span_reported.insert(fn_span) {
-                                err.span_note(
-                                    // Check whether the source is accessible
-                                    if self
-                                        .infcx
-                                        .tcx
-                                        .sess
-                                        .source_map()
-                                        .span_to_snippet(self_arg.span)
-                                        .is_ok()
-                                    {
-                                        self_arg.span
-                                    } else {
-                                        fn_call_span
-                                    },
-                                    "calling this operator moves the left-hand side",
-                                );
-                            }
-                        }
-                        CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
-                            let self_arg = self_arg.unwrap();
-                            if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
-                                err.span_label(
-                                    fn_call_span,
-                                    &format!(
-                                        "{} {}moved due to this implicit call to `.into_iter()`{}",
-                                        place_name, partially_str, loop_message
-                                    ),
-                                );
-                                let sess = self.infcx.tcx.sess;
-                                let ty = used_place.ty(self.body, self.infcx.tcx).ty;
-                                // If we have a `&mut` ref, we need to reborrow.
-                                if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
-                                    // If we are in a loop this will be suggested later.
-                                    if !is_loop_move {
-                                        err.span_suggestion_verbose(
-                                            move_span.shrink_to_lo(),
-                                            &format!(
-                                                "consider creating a fresh reborrow of {} here",
-                                                self.describe_place(moved_place.as_ref())
-                                                    .map(|n| format!("`{}`", n))
-                                                    .unwrap_or_else(
-                                                        || "the mutable reference".to_string()
-                                                    ),
-                                            ),
-                                            "&mut *".to_string(),
-                                            Applicability::MachineApplicable,
-                                        );
-                                    }
-                                } else if let Ok(snippet) =
-                                    sess.source_map().span_to_snippet(move_span)
-                                {
-                                    err.span_suggestion(
-                                        move_span,
-                                        "consider borrowing to avoid moving into the for loop",
-                                        format!("&{}", snippet),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
-                            } else {
-                                err.span_label(
-                                    fn_call_span,
-                                    &format!(
-                                        "{} {}moved due to this method call{}",
-                                        place_name, partially_str, loop_message
-                                    ),
-                                );
-                            }
-                            if is_option_or_result && maybe_reinitialized_locations.is_empty() {
-                                err.span_suggestion_verbose(
-                                    fn_call_span.shrink_to_lo(),
-                                    "consider calling `.as_ref()` to borrow the type's contents",
-                                    "as_ref().".to_string(),
-                                    Applicability::MachineApplicable,
-                                );
-                            }
-                            // Avoid pointing to the same function in multiple different
-                            // error messages.
-                            if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span)
-                            {
-                                err.span_note(
-                                        self_arg.span,
-                                        &format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
-                                    );
-                            }
-                        }
-                        // Other desugarings takes &self, which cannot cause a move
-                        _ => unreachable!(),
-                    }
-                } else {
-                    err.span_label(
-                        move_span,
-                        format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
-                    );
-                    // If the move error occurs due to a loop, don't show
-                    // another message for the same span
-                    if loop_message.is_empty() {
-                        move_spans.var_span_label(
-                            &mut err,
-                            format!(
-                                "variable {}moved due to use{}",
-                                partially_str,
-                                move_spans.describe()
-                            ),
-                            "moved",
-                        );
-                    }
-                }
+                self.explain_captures(
+                    &mut err,
+                    span,
+                    move_span,
+                    move_spans,
+                    *moved_place,
+                    Some(used_place),
+                    partially_str,
+                    loop_message,
+                    move_msg,
+                    is_loop_move,
+                    maybe_reinitialized_locations.is_empty(),
+                );
 
                 if let (UseSpans::PatUse(span), []) =
                     (move_spans, &maybe_reinitialized_locations[..])
@@ -448,8 +323,16 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                                 self.mir_hir_id(),
                                 rustc_infer::traits::ObligationCauseCode::MiscObligation,
                             );
-                            fulfill_cx.register_bound(&infcx, self.param_env, ty, copy_did, cause);
-                            let errors = fulfill_cx.select_where_possible(&infcx);
+                            fulfill_cx.register_bound(
+                                &infcx,
+                                self.param_env,
+                                // Erase any region vids from the type, which may not be resolved
+                                infcx.tcx.erase_regions(ty),
+                                copy_did,
+                                cause,
+                            );
+                            // Select all, including ambiguous predicates
+                            let errors = fulfill_cx.select_all_or_error(&infcx);
 
                             // Only emit suggestion if all required predicates are on generic
                             errors
index 754856043b3b52a2ead6b50751526dca021b464f..164ebfed0f7959306de31dc8a6f2373d4502701f 100644 (file)
@@ -1,11 +1,12 @@
 //! Borrow checker diagnostics.
 
-use rustc_const_eval::util::call_kind;
-use rustc_errors::Diagnostic;
+use rustc_const_eval::util::{call_kind, CallDesugaringKind};
+use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
 use rustc_hir::GeneratorKind;
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::{
     AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
     Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
@@ -13,8 +14,9 @@
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
-use rustc_span::{symbol::sym, Span};
+use rustc_span::{symbol::sym, Span, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
+use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
 
 use super::borrow_set::BorrowData;
 use super::MirBorrowckCtxt;
@@ -482,9 +484,7 @@ pub(super) fn borrowed_content_source(
             BorrowedContentSource::DerefSharedRef
         }
     }
-}
 
-impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
     /// name where required.
     pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
@@ -995,4 +995,173 @@ pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<
         let span = self.body.source_info(borrow.reserve_location).span;
         self.borrow_spans(span, borrow.reserve_location)
     }
+
+    fn explain_captures(
+        &mut self,
+        err: &mut Diagnostic,
+        span: Span,
+        move_span: Span,
+        move_spans: UseSpans<'tcx>,
+        moved_place: Place<'tcx>,
+        used_place: Option<PlaceRef<'tcx>>,
+        partially_str: &str,
+        loop_message: &str,
+        move_msg: &str,
+        is_loop_move: bool,
+        maybe_reinitialized_locations_is_empty: bool,
+    ) {
+        if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
+            let place_name = self
+                .describe_place(moved_place.as_ref())
+                .map(|n| format!("`{}`", n))
+                .unwrap_or_else(|| "value".to_owned());
+            match kind {
+                CallKind::FnCall { fn_trait_id, .. }
+                    if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
+                {
+                    err.span_label(
+                        fn_call_span,
+                        &format!(
+                            "{} {}moved due to this call{}",
+                            place_name, partially_str, loop_message
+                        ),
+                    );
+                    err.span_note(
+                        var_span,
+                        "this value implements `FnOnce`, which causes it to be moved when called",
+                    );
+                }
+                CallKind::Operator { self_arg, .. } => {
+                    let self_arg = self_arg.unwrap();
+                    err.span_label(
+                        fn_call_span,
+                        &format!(
+                            "{} {}moved due to usage in operator{}",
+                            place_name, partially_str, loop_message
+                        ),
+                    );
+                    if self.fn_self_span_reported.insert(fn_span) {
+                        err.span_note(
+                            // Check whether the source is accessible
+                            if self
+                                .infcx
+                                .tcx
+                                .sess
+                                .source_map()
+                                .span_to_snippet(self_arg.span)
+                                .is_ok()
+                            {
+                                self_arg.span
+                            } else {
+                                fn_call_span
+                            },
+                            "calling this operator moves the left-hand side",
+                        );
+                    }
+                }
+                CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
+                    let self_arg = self_arg.unwrap();
+                    if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
+                        let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
+                        let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
+                            Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
+                                type_known_to_meet_bound_modulo_regions(
+                                    &infcx,
+                                    self.param_env,
+                                    infcx.tcx.mk_imm_ref(
+                                        infcx.tcx.lifetimes.re_erased,
+                                        infcx.tcx.erase_regions(ty),
+                                    ),
+                                    def_id,
+                                    DUMMY_SP,
+                                )
+                            }),
+                            _ => false,
+                        };
+                        if suggest {
+                            err.span_suggestion_verbose(
+                                move_span.shrink_to_lo(),
+                                &format!(
+                                    "consider iterating over a slice of the `{}`'s content to \
+                                     avoid moving into the `for` loop",
+                                    ty,
+                                ),
+                                "&".to_string(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+
+                        err.span_label(
+                            fn_call_span,
+                            &format!(
+                                "{} {}moved due to this implicit call to `.into_iter()`{}",
+                                place_name, partially_str, loop_message
+                            ),
+                        );
+                        // If we have a `&mut` ref, we need to reborrow.
+                        if let Some(ty::Ref(_, _, hir::Mutability::Mut)) = used_place
+                            .map(|used_place| used_place.ty(self.body, self.infcx.tcx).ty.kind())
+                        {
+                            // If we are in a loop this will be suggested later.
+                            if !is_loop_move {
+                                err.span_suggestion_verbose(
+                                    move_span.shrink_to_lo(),
+                                    &format!(
+                                        "consider creating a fresh reborrow of {} here",
+                                        self.describe_place(moved_place.as_ref())
+                                            .map(|n| format!("`{}`", n))
+                                            .unwrap_or_else(|| "the mutable reference".to_string()),
+                                    ),
+                                    "&mut *".to_string(),
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                        }
+                    } else {
+                        err.span_label(
+                            fn_call_span,
+                            &format!(
+                                "{} {}moved due to this method call{}",
+                                place_name, partially_str, loop_message
+                            ),
+                        );
+                    }
+                    if is_option_or_result && maybe_reinitialized_locations_is_empty {
+                        err.span_suggestion_verbose(
+                            fn_call_span.shrink_to_lo(),
+                            "consider calling `.as_ref()` to borrow the type's contents",
+                            "as_ref().".to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                    // Avoid pointing to the same function in multiple different
+                    // error messages.
+                    if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
+                        err.span_note(
+                            self_arg.span,
+                            &format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
+                        );
+                    }
+                }
+                // Other desugarings takes &self, which cannot cause a move
+                _ => {}
+            }
+        } else {
+            if move_span != span || !loop_message.is_empty() {
+                err.span_label(
+                    move_span,
+                    format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
+                );
+            }
+            // If the move error occurs due to a loop, don't show
+            // another message for the same span
+            if loop_message.is_empty() {
+                move_spans.var_span_label(
+                    err,
+                    format!("variable {}moved due to use{}", partially_str, move_spans.describe()),
+                    "moved",
+                );
+            }
+        }
+    }
 }
index 19091569b4d27de36eea5664281fc9ad8cb76bbf..f76ec031aa9e258e6dc5b8ae35a826d050596d1a 100644 (file)
@@ -1,15 +1,12 @@
-use rustc_const_eval::util::CallDesugaringKind;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
-use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::*;
 use rustc_middle::ty;
 use rustc_mir_dataflow::move_paths::{
     IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
 };
-use rustc_span::{sym, Span, DUMMY_SP};
-use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
+use rustc_span::{sym, Span};
 
-use crate::diagnostics::{CallKind, UseSpans};
+use crate::diagnostics::UseSpans;
 use crate::prefixes::PrefixSet;
 use crate::MirBorrowckCtxt;
 
@@ -409,34 +406,10 @@ fn report_cannot_move_from_borrowed_content(
                 ".as_ref()".to_string(),
                 Applicability::MaybeIncorrect,
             );
-        } else if let Some(UseSpans::FnSelfUse {
-            kind:
-                CallKind::Normal { desugaring: Some((CallDesugaringKind::ForLoopIntoIter, _)), .. },
-            ..
-        }) = use_spans
-        {
-            let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
-                Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
-                    type_known_to_meet_bound_modulo_regions(
-                        &infcx,
-                        self.param_env,
-                        infcx
-                            .tcx
-                            .mk_imm_ref(infcx.tcx.lifetimes.re_erased, infcx.tcx.erase_regions(ty)),
-                        def_id,
-                        DUMMY_SP,
-                    )
-                }),
-                _ => false,
-            };
-            if suggest {
-                err.span_suggestion_verbose(
-                    span.shrink_to_lo(),
-                    &format!("consider iterating over a slice of the `{}`'s content", ty),
-                    "&".to_string(),
-                    Applicability::MaybeIncorrect,
-                );
-            }
+        } else if let Some(use_spans) = use_spans {
+            self.explain_captures(
+                &mut err, span, span, use_spans, move_place, None, "", "", "", false, true,
+            );
         }
         err
     }
@@ -491,11 +464,6 @@ fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, sp
                 self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
 
                 use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc));
-                use_spans.var_span_label(
-                    err,
-                    format!("move occurs due to use{}", use_spans.describe()),
-                    "moved",
-                );
             }
         }
     }
index 610798c7c05c85a427acf611ae57bcaf3a1018fb..c77bbeb86e5864506f999b48ed6566373d8e9135 100644 (file)
@@ -220,8 +220,8 @@ pub(crate) fn report_mutability_error(
             PlaceRef {
                 local,
                 projection:
-                    [
-                        proj_base @ ..,
+                    &[
+                        ref proj_base @ ..,
                         ProjectionElem::Deref,
                         ProjectionElem::Field(field, _),
                         ProjectionElem::Deref,
@@ -342,7 +342,7 @@ pub(crate) fn report_mutability_error(
                     Applicability::MachineApplicable,
                 );
                 let tcx = self.infcx.tcx;
-                if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() {
+                if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
                     self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
                 }
             }
@@ -382,7 +382,7 @@ pub(crate) fn report_mutability_error(
                 let tcx = self.infcx.tcx;
                 if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
                 {
-                    if let ty::Closure(id, _) = ty.kind() {
+                    if let ty::Closure(id, _) = *ty.kind() {
                         self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
                     }
                 }
@@ -687,7 +687,7 @@ fn is_error_in_trait(&self, local: Local) -> (bool, Option<Span>) {
     fn show_mutating_upvar(
         &self,
         tcx: TyCtxt<'_>,
-        id: &hir::def_id::DefId,
+        id: hir::def_id::DefId,
         the_place_err: PlaceRef<'tcx>,
         err: &mut Diagnostic,
     ) {
@@ -701,7 +701,7 @@ fn show_mutating_upvar(
                 let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
                 let root_hir_id = upvar_id.var_path.hir_id;
                 // we have an origin for this closure kind starting at this root variable so it's safe to unwrap here
-                let captured_places = tables.closure_min_captures[id].get(&root_hir_id).unwrap();
+                let captured_places = tables.closure_min_captures[&id].get(&root_hir_id).unwrap();
 
                 let origin_projection = closure_kind_origin
                     .projections
@@ -1083,7 +1083,7 @@ fn is_closure_or_generator(ty: Ty<'_>) -> bool {
 fn get_mut_span_in_struct_field<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
-    field: &mir::Field,
+    field: mir::Field,
 ) -> Option<Span> {
     // Expect our local to be a reference to a struct of some kind.
     if let ty::Ref(_, ty, _) = ty.kind()
index d378a2cbea3e19dedeb5c1aead21582dab987dd5..c89da5514fd154e474a6a4a89853dad62d4d0d80 100644 (file)
@@ -100,7 +100,7 @@ pub fn to_location(&self, index: LocationIndex) -> RichLocation {
 }
 
 impl LocationIndex {
-    fn is_start(&self) -> bool {
+    fn is_start(self) -> bool {
         // even indices are start points; odd indices are mid points
         (self.index() % 2) == 0
     }
index 6fd9f4954a6cc869694e13b4700aa31f451f1939..03b4a6ea98354f71ccbd5294b7bbaaa08e49761e 100644 (file)
@@ -85,7 +85,7 @@ fn populate_polonius_move_facts(
 ) {
     all_facts
         .path_is_var
-        .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(v, &m)| (m, v)));
+        .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
 
     for (child, move_path) in move_data.move_paths.iter_enumerated() {
         if let Some(parent) = move_path.parent {
@@ -135,7 +135,7 @@ fn populate_polonius_move_facts(
         }
     }
 
-    for (local, &path) in move_data.rev_lookup.iter_locals_enumerated() {
+    for (local, path) in move_data.rev_lookup.iter_locals_enumerated() {
         if body.local_kind(local) != LocalKind::Arg {
             // Non-arguments start out deinitialised; we simulate this with an
             // initial move:
@@ -226,7 +226,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
                      fr1={:?}, fr2={:?}",
                     fr1, fr2
                 );
-                all_facts.known_placeholder_subset.push((*fr1, *fr2));
+                all_facts.known_placeholder_subset.push((fr1, fr2));
             }
         }
     }
index fa9fe905256f5ac6daf84d49b27ebf43583b238d..20f54d04777603f626cccef71c2b6cb6f2f7740a 100644 (file)
@@ -942,14 +942,14 @@ fn try_promote_type_test(
 
             debug!("try_promote_type_test: ur={:?}", ur);
 
-            let non_local_ub = self.universal_region_relations.non_local_upper_bounds(&ur);
+            let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
             debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub);
 
             // This is slightly too conservative. To show T: '1, given `'2: '1`
             // and `'3: '1` we only need to prove that T: '2 *or* T: '3, but to
             // avoid potential non-determinism we approximate this by requiring
             // T: '1 and T: '2.
-            for &upper_bound in non_local_ub {
+            for upper_bound in non_local_ub {
                 debug_assert!(self.universal_regions.is_universal_region(upper_bound));
                 debug_assert!(!self.universal_regions.is_local_free_region(upper_bound));
 
@@ -1588,12 +1588,12 @@ fn try_propagate_universal_region_error(
                 // always will.)  We'll call them `shorter_fr+` -- they're ever
                 // so slightly larger than `shorter_fr`.
                 let shorter_fr_plus =
-                    self.universal_region_relations.non_local_upper_bounds(&shorter_fr);
+                    self.universal_region_relations.non_local_upper_bounds(shorter_fr);
                 debug!(
                     "try_propagate_universal_region_error: shorter_fr_plus={:?}",
                     shorter_fr_plus
                 );
-                for &&fr in &shorter_fr_plus {
+                for fr in shorter_fr_plus {
                     // Push the constraint `fr-: shorter_fr+`
                     propagated_outlives_requirements.push(ClosureOutlivesRequirement {
                         subject: ClosureOutlivesSubject::Region(fr_minus),
index 9a028147a4b60a2db2648e3fb91e223bc26d4bbb..2e7798beb64845406f8d96c27ef64705a277bc29 100644 (file)
@@ -99,10 +99,9 @@ fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
     crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
         assert!(self.universal_regions.is_universal_region(fr1));
         assert!(self.universal_regions.is_universal_region(fr2));
-        *self
-            .inverse_outlives
-            .postdom_upper_bound(&fr1, &fr2)
-            .unwrap_or(&self.universal_regions.fr_static)
+        self.inverse_outlives
+            .postdom_upper_bound(fr1, fr2)
+            .unwrap_or(self.universal_regions.fr_static)
     }
 
     /// Finds an "upper bound" for `fr` that is not local. In other
@@ -110,7 +109,7 @@ fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
     /// outlives `fr` and (b) is not local.
     ///
     /// (*) If there are multiple competing choices, we return all of them.
-    crate fn non_local_upper_bounds<'a>(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> {
+    crate fn non_local_upper_bounds<'a>(&'a self, fr: RegionVid) -> Vec<RegionVid> {
         debug!("non_local_upper_bound(fr={:?})", fr);
         let res = self.non_local_bounds(&self.inverse_outlives, fr);
         assert!(!res.is_empty(), "can't find an upper bound!?");
@@ -120,7 +119,7 @@ fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
     /// Returns the "postdominating" bound of the set of
     /// `non_local_upper_bounds` for the given region.
     crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
-        let upper_bounds = self.non_local_upper_bounds(&fr);
+        let upper_bounds = self.non_local_upper_bounds(fr);
 
         // In case we find more than one, reduce to one for
         // convenience.  This is to prevent us from generating more
@@ -130,7 +129,7 @@ fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
         debug!("non_local_bound: post_dom={:?}", post_dom);
 
         post_dom
-            .and_then(|&post_dom| {
+            .and_then(|post_dom| {
                 // If the mutual immediate postdom is not local, then
                 // there is no non-local result we can return.
                 if !self.universal_regions.is_local_free_region(post_dom) {
@@ -150,7 +149,7 @@ fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
     /// one. See `TransitiveRelation::postdom_upper_bound` for details.
     crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
         debug!("non_local_lower_bound(fr={:?})", fr);
-        let lower_bounds = self.non_local_bounds(&self.outlives, &fr);
+        let lower_bounds = self.non_local_bounds(&self.outlives, fr);
 
         // In case we find more than one, reduce to one for
         // convenience.  This is to prevent us from generating more
@@ -159,7 +158,7 @@ fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
 
         debug!("non_local_bound: post_dom={:?}", post_dom);
 
-        post_dom.and_then(|&post_dom| {
+        post_dom.and_then(|post_dom| {
             // If the mutual immediate postdom is not local, then
             // there is no non-local result we can return.
             if !self.universal_regions.is_local_free_region(post_dom) {
@@ -176,11 +175,11 @@ fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
     fn non_local_bounds<'a>(
         &self,
         relation: &'a TransitiveRelation<RegionVid>,
-        fr0: &'a RegionVid,
-    ) -> Vec<&'a RegionVid> {
+        fr0: RegionVid,
+    ) -> Vec<RegionVid> {
         // This method assumes that `fr0` is one of the universally
         // quantified region variables.
-        assert!(self.universal_regions.is_universal_region(*fr0));
+        assert!(self.universal_regions.is_universal_region(fr0));
 
         let mut external_parents = vec![];
         let mut queue = vec![fr0];
@@ -188,7 +187,7 @@ fn non_local_bounds<'a>(
         // Keep expanding `fr` into its parents until we reach
         // non-local regions.
         while let Some(fr) = queue.pop() {
-            if !self.universal_regions.is_local_free_region(*fr) {
+            if !self.universal_regions.is_local_free_region(fr) {
                 external_parents.push(fr);
                 continue;
             }
@@ -205,17 +204,17 @@ fn non_local_bounds<'a>(
     ///
     /// This will only ever be true for universally quantified regions.
     crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
-        self.outlives.contains(&fr1, &fr2)
+        self.outlives.contains(fr1, fr2)
     }
 
     /// Returns a vector of free regions `x` such that `fr1: x` is
     /// known to hold.
-    crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> {
-        self.outlives.reachable_from(&fr1)
+    crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<RegionVid> {
+        self.outlives.reachable_from(fr1)
     }
 
     /// Returns the _non-transitive_ set of known `outlives` constraints between free regions.
-    crate fn known_outlives(&self) -> impl Iterator<Item = (&RegionVid, &RegionVid)> {
+    crate fn known_outlives(&self) -> impl Iterator<Item = (RegionVid, RegionVid)> + '_ {
         self.outlives.base_edges()
     }
 }
index fdbf95591c8b838fd1d4dd330d0bcb236d94b960..95018e51b0e7a551480a4936f9fe8da197ef9122 100644 (file)
@@ -1198,7 +1198,7 @@ fn relate_type_and_user_type(
                 tcx,
                 self.param_env,
                 proj,
-                |this, field, &()| {
+                |this, field, ()| {
                     let ty = this.field_ty(tcx, field);
                     self.normalize(ty, locations)
                 },
index 5fbaed7283a6781400a2ca0628cc731ae49edb8e..37d2679c10d70af2f21316bf404ecbd29eecf4a8 100644 (file)
@@ -82,8 +82,14 @@ pub(super) fn add_local_place_comments<'tcx>(
         return;
     }
     let TyAndLayout { ty, layout } = place.layout();
-    let rustc_target::abi::Layout { size, align, abi: _, variants: _, fields: _, largest_niche: _ } =
-        layout;
+    let rustc_target::abi::LayoutS {
+        size,
+        align,
+        abi: _,
+        variants: _,
+        fields: _,
+        largest_niche: _,
+    } = layout.0.0;
 
     let (kind, extra) = match *place.inner() {
         CPlaceInner::Var(place_local, var) => {
index 66adc1a2ce96db56d7f00affe884d53db3ddf1af..aff3603303a98ff8f90120303d3804bbac681487 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_errors::ErrorGuaranteed;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{
-    read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
+    read_target_uint, AllocId, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
 };
 use rustc_middle::ty::ConstKind;
 use rustc_span::DUMMY_SP;
@@ -202,7 +202,7 @@ pub(crate) fn codegen_const_value<'tcx>(
                             &mut fx.constants_cx,
                             fx.module,
                             alloc_id,
-                            alloc.mutability,
+                            alloc.inner().mutability,
                         );
                         let local_data_id =
                             fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
@@ -257,11 +257,15 @@ pub(crate) fn codegen_const_value<'tcx>(
 
 pub(crate) fn pointer_for_allocation<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
-    alloc: &'tcx Allocation,
+    alloc: ConstAllocation<'tcx>,
 ) -> crate::pointer::Pointer {
     let alloc_id = fx.tcx.create_memory_alloc(alloc);
-    let data_id =
-        data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, alloc.mutability);
+    let data_id = data_id_for_alloc_id(
+        &mut fx.constants_cx,
+        &mut *fx.module,
+        alloc_id,
+        alloc.inner().mutability,
+    );
 
     let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
     if fx.clif_comments.enabled() {
@@ -361,7 +365,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                 let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
                     module
                         .declare_anonymous_data(
-                            alloc.mutability == rustc_hir::Mutability::Mut,
+                            alloc.inner().mutability == rustc_hir::Mutability::Mut,
                             false,
                         )
                         .unwrap()
@@ -386,6 +390,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
         }
 
         let mut data_ctx = DataContext::new();
+        let alloc = alloc.inner();
         data_ctx.set_align(alloc.align.bytes());
 
         if let Some(section_name) = section_name {
@@ -429,7 +434,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                     continue;
                 }
                 GlobalAlloc::Memory(target_alloc) => {
-                    data_id_for_alloc_id(cx, module, alloc_id, target_alloc.mutability)
+                    data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability)
                 }
                 GlobalAlloc::Static(def_id) => {
                     if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
index 4dfb13476c287f7bbe06692b3025f9547097db60..6489b96be4b2d037e212ba7b650c7adfab7bd02f 100644 (file)
@@ -1070,7 +1070,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
         };
 
         raw_eq, (v lhs_ref, v rhs_ref) {
-            let size = fx.layout_of(substs.type_at(0)).layout.size;
+            let size = fx.layout_of(substs.type_at(0)).layout.size();
             // FIXME add and use emit_small_memcmp
             let is_eq_value =
                 if size == Size::ZERO {
index 4153bc08e8ad4f3c9f40845f3098b0ebd8e9f622..49022ebd3e26fd19dfd4ec31b914b123ce1303fb 100644 (file)
@@ -159,7 +159,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 let idx_bytes = match idx_const {
                     ConstValue::ByRef { alloc, offset } => {
                         let size = Size::from_bytes(4 * ret_lane_count /* size_of([u32; ret_lane_count]) */);
-                        alloc.get_bytes(fx, alloc_range(offset, size)).unwrap()
+                        alloc.inner().get_bytes(fx, alloc_range(offset, size)).unwrap()
                     }
                     _ => unreachable!("{:?}", idx_const),
                 };
index 5851826147dfac9fd5cedacf1d9120f406be702b..d1ff15367c3c183025a8fb92fe9d50f07f083a87 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::ScalarInt;
 use rustc_middle::ty::layout::{TyAndLayout, LayoutOf};
-use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
+use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
 use rustc_span::Symbol;
 use rustc_target::abi::{self, HasDataLayout, Pointer, Size};
 
@@ -26,18 +26,6 @@ pub fn const_bytes(&self, bytes: &[u8]) -> RValue<'gcc> {
         bytes_in_context(self, bytes)
     }
 
-    fn const_cstr(&self, symbol: Symbol, _null_terminated: bool) -> LValue<'gcc> {
-        // TODO(antoyo): handle null_terminated.
-        if let Some(&value) = self.const_cstr_cache.borrow().get(&symbol) {
-            return value;
-        }
-
-        let global = self.global_string(symbol.as_str());
-
-        self.const_cstr_cache.borrow_mut().insert(symbol, global);
-        global
-    }
-
     fn global_string(&self, string: &str) -> LValue<'gcc> {
         // TODO(antoyo): handle non-null-terminated strings.
         let string = self.context.new_string_literal(&*string);
@@ -171,8 +159,12 @@ fn const_real(&self, _t: Type<'gcc>, _val: f64) -> RValue<'gcc> {
     }
 
     fn const_str(&self, s: Symbol) -> (RValue<'gcc>, RValue<'gcc>) {
-        let len = s.as_str().len();
-        let cs = self.const_ptrcast(self.const_cstr(s, false).get_address(None),
+        let s_str = s.as_str();
+        let str_global = *self.const_str_cache.borrow_mut().entry(s).or_insert_with(|| {
+            self.global_string(s_str)
+        });
+        let len = s_str.len();
+        let cs = self.const_ptrcast(str_global.get_address(None),
             self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self, true)),
         );
         (cs, self.const_usize(len as u64))
@@ -230,6 +222,7 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) ->
                     match self.tcx.global_alloc(alloc_id) {
                         GlobalAlloc::Memory(alloc) => {
                             let init = const_alloc_to_gcc(self, alloc);
+                            let alloc = alloc.inner();
                             let value =
                                 match alloc.mutability {
                                     Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
@@ -262,21 +255,21 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) ->
         }
     }
 
-    fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value {
+    fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value {
         const_alloc_to_gcc(self, alloc)
     }
 
-    fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: &Allocation, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> {
-        assert_eq!(alloc.align, layout.align.abi);
+    fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: ConstAllocation<'tcx>, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> {
+        assert_eq!(alloc.inner().align, layout.align.abi);
         let ty = self.type_ptr_to(layout.gcc_type(self, true));
         let value =
             if layout.size == Size::ZERO {
-                let value = self.const_usize(alloc.align.bytes());
+                let value = self.const_usize(alloc.inner().align.bytes());
                 self.context.new_cast(None, value, ty)
             }
             else {
                 let init = const_alloc_to_gcc(self, alloc);
-                let base_addr = self.static_addr_of(init, alloc.align, None);
+                let base_addr = self.static_addr_of(init, alloc.inner().align, None);
 
                 let array = self.const_bitcast(base_addr, self.type_i8p());
                 let value = self.context.new_array_access(None, array, self.const_usize(offset.bytes())).get_address(None);
index ddc2b88191bd0e8e032d05e1220579ec09071fe7..d53b15159fa44d3d135a56e3fdcff90c576b7a53 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::mir::interpret::{self, Allocation, ErrorHandled, Scalar as InterpScalar, read_target_uint};
+use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint};
 use rustc_span::Span;
 use rustc_span::def_id::DefId;
 use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange};
@@ -284,7 +284,8 @@ pub fn get_static(&self, def_id: DefId) -> LValue<'gcc> {
     }
 }
 
-pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: &Allocation) -> RValue<'gcc> {
+pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAllocation<'tcx>) -> RValue<'gcc> {
+    let alloc = alloc.inner();
     let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
     let dl = cx.data_layout();
     let pointer_size = dl.pointer_size.bytes() as usize;
@@ -338,7 +339,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: &Alloca
     cx.const_struct(&llvals, true)
 }
 
-pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, &'tcx Allocation), ErrorHandled> {
+pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> {
     let alloc = cx.tcx.eval_static_initializer(def_id)?;
     Ok((const_alloc_to_gcc(cx, alloc), alloc))
 }
index dfcd1b6231216cb49acc361bdb83e054a43e058d..6c1dce969f0f5eed9ec997d4f5af26629c0b33f7 100644 (file)
@@ -85,7 +85,7 @@ pub struct CodegenCx<'gcc, 'tcx> {
     pub const_globals: RefCell<FxHashMap<RValue<'gcc>, RValue<'gcc>>>,
 
     /// Cache of constant strings,
-    pub const_cstr_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
+    pub const_str_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
 
     /// Cache of globals.
     pub globals: RefCell<FxHashMap<String, RValue<'gcc>>>,
@@ -195,7 +195,7 @@ pub fn new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>,
             function_instances: Default::default(),
             vtables: Default::default(),
             const_globals: Default::default(),
-            const_cstr_cache: Default::default(),
+            const_str_cache: Default::default(),
             globals: Default::default(),
             scalar_types: Default::default(),
             types: Default::default(),
index 572ac559d09dfb89fb5842cab86c7903d900dae7..ef213f5636907811ad4c0354e1e99153f5dfe287 100644 (file)
@@ -272,20 +272,20 @@ fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'t
                     use rustc_target::abi::Abi::*;
                     let tp_ty = substs.type_at(0);
                     let layout = self.layout_of(tp_ty).layout;
-                    let _use_integer_compare = match layout.abi {
+                    let _use_integer_compare = match layout.abi() {
                         Scalar(_) | ScalarPair(_, _) => true,
                         Uninhabited | Vector { .. } => false,
                         Aggregate { .. } => {
                             // For rusty ABIs, small aggregates are actually passed
                             // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
                             // so we re-use that same threshold here.
-                            layout.size <= self.data_layout().pointer_size * 2
+                            layout.size() <= self.data_layout().pointer_size * 2
                         }
                     };
 
                     let a = args[0].immediate();
                     let b = args[1].immediate();
-                    if layout.size.bytes() == 0 {
+                    if layout.size().bytes() == 0 {
                         self.const_bool(true)
                     }
                     /*else if use_integer_compare {
@@ -301,7 +301,7 @@ fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'t
                         let void_ptr_type = self.context.new_type::<*const ()>();
                         let a_ptr = self.bitcast(a, void_ptr_type);
                         let b_ptr = self.bitcast(b, void_ptr_type);
-                        let n = self.context.new_cast(None, self.const_usize(layout.size.bytes()), self.sizet_type);
+                        let n = self.context.new_cast(None, self.const_usize(layout.size().bytes()), self.sizet_type);
                         let builtin = self.context.get_builtin_function("memcmp");
                         let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]);
                         self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
index 6fd836946ffb464d88a417b8b4f0064129d2d46a..101da0012cb4b0d8fe33d2401db69cf8ef03082a 100644 (file)
@@ -1,6 +1,7 @@
 //! Set and unset common attributes on LLVM values.
 
 use rustc_codegen_ssa::traits::*;
+use rustc_data_structures::small_str::SmallStr;
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::{self, TyCtxt};
@@ -377,13 +378,12 @@ pub fn from_fn_attrs<'ll, 'tcx>(
         }
     }
 
-    if !function_features.is_empty() {
-        let global_features = cx.tcx.global_backend_features(()).iter().map(|s| &s[..]);
-        let val = global_features
-            .chain(function_features.iter().map(|s| &s[..]))
-            .intersperse(",")
-            .collect::<String>();
-        to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &val));
+    let global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str());
+    let function_features = function_features.iter().map(|s| s.as_str());
+    let target_features =
+        global_features.chain(function_features).intersperse(",").collect::<SmallStr<1024>>();
+    if !target_features.is_empty() {
+        to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features));
     }
 
     attributes::apply_to_llfn(llfn, Function, &to_add);
index 6afa649b6de325a19b40e8df10619b1002f371fd..0f5b1c08ec2dc707920b85ec45c08aac2bde8193 100644 (file)
@@ -317,7 +317,7 @@ fn fat_lto(
             info!("linking {:?}", name);
             let data = bc_decoded.data();
             linker.add(data).map_err(|()| {
-                let msg = format!("failed to load bc of {:?}", name);
+                let msg = format!("failed to load bitcode of module {:?}", name);
                 write::llvm_err(diag_handler, &msg)
             })?;
             serialized_bitcode.push(bc_decoded);
index 9d34734f4e59ac83845cb0f947c5789f656e4071..b10e74625dadc81edc4c04bb18f4213a387553e8 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::*;
 use rustc_middle::bug;
-use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
+use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::ScalarInt;
 use rustc_span::symbol::Symbol;
@@ -106,32 +106,6 @@ pub fn const_bytes(&self, bytes: &[u8]) -> &'ll Value {
         bytes_in_context(self.llcx, bytes)
     }
 
-    fn const_cstr(&self, s: Symbol, null_terminated: bool) -> &'ll Value {
-        unsafe {
-            if let Some(&llval) = self.const_cstr_cache.borrow().get(&s) {
-                return llval;
-            }
-
-            let s_str = s.as_str();
-            let sc = llvm::LLVMConstStringInContext(
-                self.llcx,
-                s_str.as_ptr() as *const c_char,
-                s_str.len() as c_uint,
-                !null_terminated as Bool,
-            );
-            let sym = self.generate_local_symbol_name("str");
-            let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| {
-                bug!("symbol `{}` is already defined", sym);
-            });
-            llvm::LLVMSetInitializer(g, sc);
-            llvm::LLVMSetGlobalConstant(g, True);
-            llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
-
-            self.const_cstr_cache.borrow_mut().insert(s, g);
-            g
-        }
-    }
-
     pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
         unsafe {
             assert_eq!(idx as c_uint as u64, idx);
@@ -204,9 +178,23 @@ fn const_real(&self, t: &'ll Type, val: f64) -> &'ll Value {
     }
 
     fn const_str(&self, s: Symbol) -> (&'ll Value, &'ll Value) {
-        let len = s.as_str().len();
+        let s_str = s.as_str();
+        let str_global = *self.const_str_cache.borrow_mut().entry(s).or_insert_with(|| {
+            let sc = self.const_bytes(s_str.as_bytes());
+            let sym = self.generate_local_symbol_name("str");
+            let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| {
+                bug!("symbol `{}` is already defined", sym);
+            });
+            unsafe {
+                llvm::LLVMSetInitializer(g, sc);
+                llvm::LLVMSetGlobalConstant(g, True);
+                llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
+            }
+            g
+        });
+        let len = s_str.len();
         let cs = consts::ptrcast(
-            self.const_cstr(s, false),
+            str_global,
             self.type_ptr_to(self.layout_of(self.tcx.types.str_).llvm_type(self)),
         );
         (cs, self.const_usize(len as u64))
@@ -249,6 +237,7 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) ->
                 let (base_addr, base_addr_space) = match self.tcx.global_alloc(alloc_id) {
                     GlobalAlloc::Memory(alloc) => {
                         let init = const_alloc_to_llvm(self, alloc);
+                        let alloc = alloc.inner();
                         let value = match alloc.mutability {
                             Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
                             _ => self.static_addr_of(init, alloc.align, None),
@@ -285,24 +274,25 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) ->
         }
     }
 
-    fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value {
+    fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value {
         const_alloc_to_llvm(self, alloc)
     }
 
     fn from_const_alloc(
         &self,
         layout: TyAndLayout<'tcx>,
-        alloc: &Allocation,
+        alloc: ConstAllocation<'tcx>,
         offset: Size,
     ) -> PlaceRef<'tcx, &'ll Value> {
-        assert_eq!(alloc.align, layout.align.abi);
+        let alloc_align = alloc.inner().align;
+        assert_eq!(alloc_align, layout.align.abi);
         let llty = self.type_ptr_to(layout.llvm_type(self));
         let llval = if layout.size == Size::ZERO {
-            let llval = self.const_usize(alloc.align.bytes());
+            let llval = self.const_usize(alloc_align.bytes());
             unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
         } else {
             let init = const_alloc_to_llvm(self, alloc);
-            let base_addr = self.static_addr_of(init, alloc.align, None);
+            let base_addr = self.static_addr_of(init, alloc_align, None);
 
             let llval = unsafe {
                 llvm::LLVMRustConstInBoundsGEP2(
index c98720944c9769c32b03460d94d1e29238914377..7d3fe43eeab17d3f0bff7ca7ea88952a8b02d2f1 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::interpret::{
-    read_target_uint, Allocation, ErrorHandled, GlobalAlloc, InitChunk, Pointer,
+    read_target_uint, Allocation, ConstAllocation, ErrorHandled, GlobalAlloc, InitChunk, Pointer,
     Scalar as InterpScalar,
 };
 use rustc_middle::mir::mono::MonoItem;
@@ -25,7 +25,8 @@
 use std::ops::Range;
 use tracing::debug;
 
-pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
+pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value {
+    let alloc = alloc.inner();
     let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
     let dl = cx.data_layout();
     let pointer_size = dl.pointer_size.bytes() as usize;
@@ -127,7 +128,7 @@ fn append_chunks_of_init_and_uninit_bytes<'ll, 'a, 'b>(
 pub fn codegen_static_initializer<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     def_id: DefId,
-) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> {
+) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> {
     let alloc = cx.tcx.eval_static_initializer(def_id)?;
     Ok((const_alloc_to_llvm(cx, alloc), alloc))
 }
@@ -370,6 +371,7 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
                 // Error has already been reported
                 return;
             };
+            let alloc = alloc.inner();
 
             let g = self.get_static(def_id);
 
index f102becf2bdba125ef1c0496fc8836ea5066aec5..52e03e0ad3d6b963d02e331a4216dac6fb986543 100644 (file)
@@ -55,7 +55,7 @@ pub struct CodegenCx<'ll, 'tcx> {
     pub vtables:
         RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>,
     /// Cache of constant strings,
-    pub const_cstr_cache: RefCell<FxHashMap<Symbol, &'ll Value>>,
+    pub const_str_cache: RefCell<FxHashMap<Symbol, &'ll Value>>,
 
     /// Reverse-direction for const ptrs cast from globals.
     ///
@@ -415,7 +415,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             codegen_unit,
             instances: Default::default(),
             vtables: Default::default(),
-            const_cstr_cache: Default::default(),
+            const_str_cache: Default::default(),
             const_unsized: Default::default(),
             const_globals: Default::default(),
             statics_to_rauw: RefCell::new(Vec::new()),
index b2879ef4aea11af5846388c24f27efee5aa391a3..98ba38356a4c30c8cafcd806115ebff394581817 100644 (file)
@@ -90,7 +90,7 @@ fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
     /// call. Since the function is never called, all other `CodeRegion`s can be
     /// added as `unreachable_region`s.
     fn define_unused_fn(&self, def_id: DefId) {
-        let instance = declare_unused_fn(self, &def_id);
+        let instance = declare_unused_fn(self, def_id);
         codegen_unused_fn_and_counter(self, instance);
         add_unused_function_coverage(self, instance, def_id);
     }
@@ -184,12 +184,12 @@ fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeReg
     }
 }
 
-fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: &DefId) -> Instance<'tcx> {
+fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance<'tcx> {
     let tcx = cx.tcx;
 
     let instance = Instance::new(
-        *def_id,
-        InternalSubsts::for_item(tcx, *def_id, |param, _| {
+        def_id,
+        InternalSubsts::for_item(tcx, def_id, |param, _| {
             if let ty::GenericParamDefKind::Lifetime = param.kind {
                 tcx.lifetimes.re_erased.into()
             } else {
index 89fc89800373714a41cc27bfc39d704226e76b17..a6e4878e5b3615abc7aaa897a46c0a07770d5632 100644 (file)
@@ -617,7 +617,9 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll
         ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
             pointer_or_reference_metadata(cx, t, pointee_type, unique_type_id)
         }
-        ty::Adt(def, _) if def.is_box() => {
+        // Box<T, A> may have a non-ZST allocator A. In that case, we
+        // cannot treat Box<T, A> as just an owned alias of `*mut T`.
+        ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => {
             pointer_or_reference_metadata(cx, t, t.boxed_ty(), unique_type_id)
         }
         ty::FnDef(..) | ty::FnPtr(_) => subroutine_type_metadata(cx, unique_type_id),
index e7c13e793d92e3150cca00f3d9b8f33243d73989..7f804ab5e6347aad8a5e9a4809420c65990b77c5 100644 (file)
@@ -300,34 +300,34 @@ fn codegen_intrinsic_call(
                 use abi::Abi::*;
                 let tp_ty = substs.type_at(0);
                 let layout = self.layout_of(tp_ty).layout;
-                let use_integer_compare = match layout.abi {
+                let use_integer_compare = match layout.abi() {
                     Scalar(_) | ScalarPair(_, _) => true,
                     Uninhabited | Vector { .. } => false,
                     Aggregate { .. } => {
                         // For rusty ABIs, small aggregates are actually passed
                         // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
                         // so we re-use that same threshold here.
-                        layout.size <= self.data_layout().pointer_size * 2
+                        layout.size() <= self.data_layout().pointer_size * 2
                     }
                 };
 
                 let a = args[0].immediate();
                 let b = args[1].immediate();
-                if layout.size.bytes() == 0 {
+                if layout.size().bytes() == 0 {
                     self.const_bool(true)
                 } else if use_integer_compare {
-                    let integer_ty = self.type_ix(layout.size.bits());
+                    let integer_ty = self.type_ix(layout.size().bits());
                     let ptr_ty = self.type_ptr_to(integer_ty);
                     let a_ptr = self.bitcast(a, ptr_ty);
-                    let a_val = self.load(integer_ty, a_ptr, layout.align.abi);
+                    let a_val = self.load(integer_ty, a_ptr, layout.align().abi);
                     let b_ptr = self.bitcast(b, ptr_ty);
-                    let b_val = self.load(integer_ty, b_ptr, layout.align.abi);
+                    let b_val = self.load(integer_ty, b_ptr, layout.align().abi);
                     self.icmp(IntPredicate::IntEQ, a_val, b_val)
                 } else {
                     let i8p_ty = self.type_i8p();
                     let a_ptr = self.bitcast(a, i8p_ty);
                     let b_ptr = self.bitcast(b, i8p_ty);
-                    let n = self.const_usize(layout.size.bytes());
+                    let n = self.const_usize(layout.size().bytes());
                     let cmp = self.call_intrinsic("memcmp", &[a_ptr, b_ptr, n]);
                     self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
                 }
index e9d13a4ebaf8cb775162de4b198f660d5c8214f3..4b324740a1f837fae411d86717b8c7b3e59ebe05 100644 (file)
@@ -527,8 +527,9 @@ pub(crate) fn should_use_new_llvm_pass_manager(user_opt: &Option<bool>, target_a
     // The new pass manager is enabled by default for LLVM >= 13.
     // This matches Clang, which also enables it since Clang 13.
 
-    // FIXME: There are some perf issues with the new pass manager
-    // when targeting s390x, so it is temporarily disabled for that
-    // arch, see https://github.com/rust-lang/rust/issues/89609
-    user_opt.unwrap_or_else(|| target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0))
+    // There are some perf issues with the new pass manager when targeting
+    // s390x with LLVM 13, so enable the new pass manager only with LLVM 14.
+    // See https://github.com/rust-lang/rust/issues/89609.
+    let min_version = if target_arch == "s390x" { 14 } else { 13 };
+    user_opt.unwrap_or_else(|| llvm_util::get_version() >= (min_version, 0, 0))
 }
index 8bbf25ce030f8f14a95f9a50cda465c83caa836b..87d0680bf6f308fa8427b7919e61872f87a76676 100644 (file)
@@ -9,7 +9,7 @@ test = false
 [dependencies]
 bitflags = "1.2.1"
 cc = "1.0.69"
-itertools = "0.10"
+itertools = "0.10.1"
 tracing = "0.1"
 libc = "0.2.50"
 jobserver = "0.1.22"
index 37e84046901f695ee1533b906ea63ed225bc736d..62a297937d40c66c2856fa5746f67f6123e64cb2 100644 (file)
@@ -427,7 +427,7 @@ fn msvc_enum_fallback<'tcx>(
 
             // calculate the range of values for the dataful variant
             let dataful_discriminant_range =
-                dataful_variant_layout.largest_niche.unwrap().scalar.valid_range;
+                dataful_variant_layout.largest_niche().unwrap().scalar.valid_range;
 
             let min = dataful_discriminant_range.start;
             let min = tag.value.size(&tcx).truncate(min);
index 5260b7cc33120e0e36c05d3d79eb0ad537b7d317..918f36841695a194a5af533997f87e52cb2c2532 100644 (file)
@@ -1,6 +1,6 @@
 use super::BackendTypes;
 use crate::mir::place::PlaceRef;
-use rustc_middle::mir::interpret::{Allocation, Scalar};
+use rustc_middle::mir::interpret::{ConstAllocation, Scalar};
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_span::Symbol;
 use rustc_target::abi::{self, Size};
@@ -26,13 +26,13 @@ pub trait ConstMethods<'tcx>: BackendTypes {
     fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
     fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;
 
-    fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value;
+    fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value;
 
     fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
     fn from_const_alloc(
         &self,
         layout: TyAndLayout<'tcx>,
-        alloc: &Allocation,
+        alloc: ConstAllocation<'tcx>,
         offset: Size,
     ) -> PlaceRef<'tcx, Self::Value>;
 
index dad572741049b1aac840648f1865fb5418a068ff..df809e8270195862ffd27ceb39b81fa4f20011c5 100644 (file)
@@ -367,7 +367,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
                             "the raw bytes of the constant ({}",
                             display_allocation(
                                 *ecx.tcx,
-                                ecx.tcx.global_alloc(alloc_id).unwrap_memory()
+                                ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner()
                             )
                         ));
                     },
index ac25cfd057c17ed1bc7b77d265fe4a08104d084b..92f4d3a6772444d79638249261ddcbc8fd7aa48c 100644 (file)
@@ -18,8 +18,8 @@
 use rustc_target::spec::abi::Abi;
 
 use crate::interpret::{
-    self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, OpTy,
-    PlaceTy, Scalar, StackPopUnwind,
+    self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
+    OpTy, PlaceTy, Scalar, StackPopUnwind,
 };
 
 use super::error::*;
@@ -475,13 +475,14 @@ fn stack_mut<'a>(
     fn before_access_global(
         memory_extra: &MemoryExtra,
         alloc_id: AllocId,
-        allocation: &Allocation,
+        alloc: ConstAllocation<'tcx>,
         static_def_id: Option<DefId>,
         is_write: bool,
     ) -> InterpResult<'tcx> {
+        let alloc = alloc.inner();
         if is_write {
             // Write access. These are never allowed, but we give a targeted error message.
-            if allocation.mutability == Mutability::Not {
+            if alloc.mutability == Mutability::Not {
                 Err(err_ub!(WriteToReadOnly(alloc_id)).into())
             } else {
                 Err(ConstEvalErrKind::ModifiedGlobal.into())
@@ -504,7 +505,7 @@ fn before_access_global(
                 // But make sure we never accept a read from something mutable, that would be
                 // unsound. The reason is that as the content of this allocation may be different
                 // now and at run-time, so if we permit reading now we might return the wrong value.
-                assert_eq!(allocation.mutability, Mutability::Not);
+                assert_eq!(alloc.mutability, Mutability::Not);
                 Ok(())
             }
         }
index 724f92243d07ee73116b46cfd0c5c6ffa18fe68a..c49c5ecac267607290081dee62f6264761fcba78 100644 (file)
@@ -183,7 +183,7 @@ pub(crate) fn deref_const<'tcx>(
     let mplace = ecx.deref_operand(&op).unwrap();
     if let Some(alloc_id) = mplace.ptr.provenance {
         assert_eq!(
-            tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().mutability,
+            tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().inner().mutability,
             Mutability::Not,
             "deref_const cannot be used with mutable allocations as \
             that could allow pattern matching to observe mutable statics",
index e2c4eb1dadc83facbfe202c929681901e4ad2ced..5be0a183cf6b40300685b951120cf339abee7cca 100644 (file)
@@ -97,7 +97,7 @@ pub fn cast(
         Ok(())
     }
 
-    fn misc_cast(
+    pub fn misc_cast(
         &self,
         src: &ImmTy<'tcx, M::PointerTag>,
         cast_ty: Ty<'tcx>,
@@ -139,7 +139,7 @@ fn misc_cast(
                 if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
                     assert!(src.layout.is_zst());
                     let discr_layout = self.layout_of(discr.ty)?;
-                    return Ok(self.cast_from_scalar(discr.val, discr_layout, cast_ty).into());
+                    return Ok(self.cast_from_int_like(discr.val, discr_layout, cast_ty).into());
                 }
             }
             Variants::Multiple { .. } => {}
@@ -169,17 +169,17 @@ fn misc_cast(
             }
         }
 
-        // # The remaining source values are scalar.
+        // # The remaining source values are scalar and "int-like".
 
         // For all remaining casts, we either
         // (a) cast a raw ptr to usize, or
         // (b) cast from an integer-like (including bool, char, enums).
         // In both cases we want the bits.
         let bits = src.to_scalar()?.to_bits(src.layout.size)?;
-        Ok(self.cast_from_scalar(bits, src.layout, cast_ty).into())
+        Ok(self.cast_from_int_like(bits, src.layout, cast_ty).into())
     }
 
-    pub(super) fn cast_from_scalar(
+    fn cast_from_int_like(
         &self,
         v: u128, // raw bits (there is no ScalarTy so we separate data+layout)
         src_layout: TyAndLayout<'tcx>,
index 45ac3cd1f84a60315ebd5df0d3cd519631eb1a69..a8a57e6990ffdd221c10094582eb23c8743a3583 100644 (file)
@@ -164,7 +164,7 @@ pub enum StackPopCleanup {
 }
 
 /// State of a local variable including a memoized layout
-#[derive(Clone, PartialEq, Eq, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, HashStable)]
 pub struct LocalState<'tcx, Tag: Provenance = AllocId> {
     pub value: LocalValue<Tag>,
     /// Don't modify if `Some`, this is only used to prevent computing the layout twice
@@ -714,6 +714,7 @@ pub fn size_and_align_of_mplace(
         self.size_and_align_of(&mplace.meta, &mplace.layout)
     }
 
+    #[instrument(skip(self, body, return_place, return_to_block), level = "debug")]
     pub fn push_stack_frame(
         &mut self,
         instance: ty::Instance<'tcx>,
@@ -721,6 +722,7 @@ pub fn push_stack_frame(
         return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
         return_to_block: StackPopCleanup,
     ) -> InterpResult<'tcx> {
+        debug!("body: {:#?}", body);
         // first push a stack frame so we have access to the local substs
         let pre_frame = Frame {
             body,
@@ -824,6 +826,7 @@ pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx>
     /// `Drop` impls for any locals that have been initialized at this point.
     /// The cleanup block ends with a special `Resume` terminator, which will
     /// cause us to continue unwinding.
+    #[instrument(skip(self), level = "debug")]
     pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx> {
         info!(
             "popping stack frame ({})",
@@ -876,6 +879,8 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
             return Ok(());
         }
 
+        debug!("locals: {:#?}", frame.locals);
+
         // Cleanup: deallocate all locals that are backed by an allocation.
         for local in &frame.locals {
             self.deallocate_local(local.value)?;
@@ -935,6 +940,7 @@ pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> {
         Ok(())
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn deallocate_local(&mut self, local: LocalValue<M::PointerTag>) -> InterpResult<'tcx> {
         if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
             // All locals have a backing allocation, even if the allocation is empty
index 2096addb9f78629103a074503f4a9e5362f6de3d..fa8151a1f3c3df9d0623b910f01d8a28d5f36892 100644 (file)
 
 use rustc_ast::Mutability;
 
-use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, ValueVisitor};
+use super::{
+    AllocId, Allocation, ConstAllocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy,
+    ValueVisitor,
+};
 use crate::const_eval;
 
 pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine<
@@ -131,8 +134,8 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
         alloc.mutability = Mutability::Not;
     };
     // link the alloc id to the actual allocation
-    let alloc = tcx.intern_const_alloc(alloc);
     leftover_allocations.extend(alloc.relocations().iter().map(|&(_, alloc_id)| alloc_id));
+    let alloc = tcx.intern_const_alloc(alloc);
     tcx.set_alloc_id_memory(alloc_id, alloc);
     None
 }
@@ -356,6 +359,8 @@ pub fn intern_const_alloc_recursive<
     // pointers, ... So we can't intern them according to their type rules
 
     let mut todo: Vec<_> = leftover_allocations.iter().cloned().collect();
+    debug!(?todo);
+    debug!("dead_alloc_map: {:#?}", ecx.memory.dead_alloc_map);
     while let Some(alloc_id) = todo.pop() {
         if let Some((_, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) {
             // We can't call the `intern_shallow` method here, as its logic is tailored to safe
@@ -393,7 +398,7 @@ pub fn intern_const_alloc_recursive<
             }
             let alloc = tcx.intern_const_alloc(alloc);
             tcx.set_alloc_id_memory(alloc_id, alloc);
-            for &(_, alloc_id) in alloc.relocations().iter() {
+            for &(_, alloc_id) in alloc.inner().relocations().iter() {
                 if leftover_allocations.insert(alloc_id) {
                     todo.push(alloc_id);
                 }
@@ -425,7 +430,7 @@ pub fn intern_with_temp_alloc(
             &mut InterpCx<'mir, 'tcx, M>,
             &PlaceTy<'tcx, M::PointerTag>,
         ) -> InterpResult<'tcx, ()>,
-    ) -> InterpResult<'tcx, &'tcx Allocation> {
+    ) -> InterpResult<'tcx, ConstAllocation<'tcx>> {
         let dest = self.allocate(layout, MemoryKind::Stack)?;
         f(self, &dest.into())?;
         let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1;
index bf7e811c76f8edc4dfa228d5f8a26de4d08a2f73..a39ef22ec0834a561304aeba5fa0ac5ba668e71f 100644 (file)
@@ -56,7 +56,7 @@ fn numeric_intrinsic<Tag>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<T
         sym::type_name => {
             ensure_monomorphic_enough(tcx, tp_ty)?;
             let alloc = type_name::alloc_type_name(tcx, tp_ty);
-            ConstValue::Slice { data: alloc, start: 0, end: alloc.len() }
+            ConstValue::Slice { data: alloc, start: 0, end: alloc.inner().len() }
         }
         sym::needs_drop => {
             ensure_monomorphic_enough(tcx, tp_ty)?;
@@ -219,48 +219,11 @@ pub fn emulate_intrinsic(
             sym::saturating_add | sym::saturating_sub => {
                 let l = self.read_immediate(&args[0])?;
                 let r = self.read_immediate(&args[1])?;
-                let is_add = intrinsic_name == sym::saturating_add;
-                let (val, overflowed, _ty) = self.overflowing_binary_op(
-                    if is_add { BinOp::Add } else { BinOp::Sub },
+                let val = self.saturating_arith(
+                    if intrinsic_name == sym::saturating_add { BinOp::Add } else { BinOp::Sub },
                     &l,
                     &r,
                 )?;
-                let val = if overflowed {
-                    let size = l.layout.size;
-                    let num_bits = size.bits();
-                    if l.layout.abi.is_signed() {
-                        // For signed ints the saturated value depends on the sign of the first
-                        // term since the sign of the second term can be inferred from this and
-                        // the fact that the operation has overflowed (if either is 0 no
-                        // overflow can occur)
-                        let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
-                        let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
-                        if first_term_positive {
-                            // Negative overflow not possible since the positive first term
-                            // can only increase an (in range) negative term for addition
-                            // or corresponding negated positive term for subtraction
-                            Scalar::from_uint(
-                                (1u128 << (num_bits - 1)) - 1, // max positive
-                                Size::from_bits(num_bits),
-                            )
-                        } else {
-                            // Positive overflow not possible for similar reason
-                            // max negative
-                            Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
-                        }
-                    } else {
-                        // unsigned
-                        if is_add {
-                            // max unsigned
-                            Scalar::from_uint(size.unsigned_int_max(), Size::from_bits(num_bits))
-                        } else {
-                            // underflow to 0
-                            Scalar::from_uint(0u128, Size::from_bits(num_bits))
-                        }
-                    }
-                } else {
-                    val
-                };
                 self.write_scalar(val, dest)?;
             }
             sym::discriminant_value => {
@@ -344,53 +307,57 @@ pub fn emulate_intrinsic(
                 self.write_pointer(offset_ptr, dest)?;
             }
             sym::ptr_offset_from => {
-                let a = self.read_immediate(&args[0])?.to_scalar()?;
-                let b = self.read_immediate(&args[1])?.to_scalar()?;
+                let a = self.read_pointer(&args[0])?;
+                let b = self.read_pointer(&args[1])?;
 
                 // Special case: if both scalars are *equal integers*
                 // and not null, we pretend there is an allocation of size 0 right there,
                 // and their offset is 0. (There's never a valid object at null, making it an
                 // exception from the exception.)
                 // This is the dual to the special exception for offset-by-0
-                // in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`).
-                //
-                // Control flow is weird because we cannot early-return (to reach the
-                // `go_to_block` at the end).
-                let done = if let (Ok(a), Ok(b)) = (a.try_to_int(), b.try_to_int()) {
-                    let a = a.try_to_machine_usize(*self.tcx).unwrap();
-                    let b = b.try_to_machine_usize(*self.tcx).unwrap();
-                    if a == b && a != 0 {
+                // in the inbounds pointer offset operation (see `ptr_offset_inbounds` below).
+                match (self.memory.ptr_try_get_alloc(a), self.memory.ptr_try_get_alloc(b)) {
+                    (Err(a), Err(b)) if a == b && a != 0 => {
+                        // Both are the same non-null integer.
                         self.write_scalar(Scalar::from_machine_isize(0, self), dest)?;
-                        true
-                    } else {
-                        false
                     }
-                } else {
-                    false
-                };
-
-                if !done {
-                    // General case: we need two pointers.
-                    let a = self.scalar_to_ptr(a);
-                    let b = self.scalar_to_ptr(b);
-                    let (a_alloc_id, a_offset, _) = self.memory.ptr_get_alloc(a)?;
-                    let (b_alloc_id, b_offset, _) = self.memory.ptr_get_alloc(b)?;
-                    if a_alloc_id != b_alloc_id {
-                        throw_ub_format!(
-                            "ptr_offset_from cannot compute offset of pointers into different \
-                            allocations.",
-                        );
+                    (Err(offset), _) | (_, Err(offset)) => {
+                        throw_ub!(DanglingIntPointer(offset, CheckInAllocMsg::OffsetFromTest));
+                    }
+                    (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) => {
+                        // Both are pointers. They must be into the same allocation.
+                        if a_alloc_id != b_alloc_id {
+                            throw_ub_format!(
+                                "ptr_offset_from cannot compute offset of pointers into different \
+                                allocations.",
+                            );
+                        }
+                        // And they must both be valid for zero-sized accesses ("in-bounds or one past the end").
+                        self.memory.check_ptr_access_align(
+                            a,
+                            Size::ZERO,
+                            Align::ONE,
+                            CheckInAllocMsg::OffsetFromTest,
+                        )?;
+                        self.memory.check_ptr_access_align(
+                            b,
+                            Size::ZERO,
+                            Align::ONE,
+                            CheckInAllocMsg::OffsetFromTest,
+                        )?;
+
+                        // Compute offset.
+                        let usize_layout = self.layout_of(self.tcx.types.usize)?;
+                        let isize_layout = self.layout_of(self.tcx.types.isize)?;
+                        let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout);
+                        let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout);
+                        let (val, _overflowed, _ty) =
+                            self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
+                        let pointee_layout = self.layout_of(substs.type_at(0))?;
+                        let val = ImmTy::from_scalar(val, isize_layout);
+                        let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
+                        self.exact_div(&val, &size, dest)?;
                     }
-                    let usize_layout = self.layout_of(self.tcx.types.usize)?;
-                    let isize_layout = self.layout_of(self.tcx.types.isize)?;
-                    let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout);
-                    let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout);
-                    let (val, _overflowed, _ty) =
-                        self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
-                    let pointee_layout = self.layout_of(substs.type_at(0))?;
-                    let val = ImmTy::from_scalar(val, isize_layout);
-                    let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
-                    self.exact_div(&val, &size, dest)?;
                 }
             }
 
@@ -508,6 +475,49 @@ pub fn exact_div(
         self.binop_ignore_overflow(BinOp::Div, &a, &b, dest)
     }
 
+    pub fn saturating_arith(
+        &self,
+        mir_op: BinOp,
+        l: &ImmTy<'tcx, M::PointerTag>,
+        r: &ImmTy<'tcx, M::PointerTag>,
+    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
+        assert!(matches!(mir_op, BinOp::Add | BinOp::Sub));
+        let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?;
+        Ok(if overflowed {
+            let size = l.layout.size;
+            let num_bits = size.bits();
+            if l.layout.abi.is_signed() {
+                // For signed ints the saturated value depends on the sign of the first
+                // term since the sign of the second term can be inferred from this and
+                // the fact that the operation has overflowed (if either is 0 no
+                // overflow can occur)
+                let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
+                let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
+                if first_term_positive {
+                    // Negative overflow not possible since the positive first term
+                    // can only increase an (in range) negative term for addition
+                    // or corresponding negated positive term for subtraction
+                    Scalar::from_int(size.signed_int_max(), size)
+                } else {
+                    // Positive overflow not possible for similar reason
+                    // max negative
+                    Scalar::from_int(size.signed_int_min(), size)
+                }
+            } else {
+                // unsigned
+                if matches!(mir_op, BinOp::Add) {
+                    // max unsigned
+                    Scalar::from_uint(size.unsigned_int_max(), size)
+                } else {
+                    // underflow to 0
+                    Scalar::from_uint(0u128, size)
+                }
+            }
+        } else {
+            val
+        })
+    }
+
     /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
     /// allocation. For integer pointers, we consider each of them their own tiny allocation of size
     /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
index aa84b16b502817cf0e28d4b20837f329861ae1fc..dfc1a6e4d38e12828791fd4c39c8b7b51cf69537 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::definitions::DisambiguatedDefPathData;
-use rustc_middle::mir::interpret::Allocation;
+use rustc_middle::mir::interpret::{Allocation, ConstAllocation};
 use rustc_middle::ty::{
     self,
     print::{PrettyPrinter, Print, Printer},
@@ -188,7 +188,7 @@ fn write_str(&mut self, s: &str) -> std::fmt::Result {
 }
 
 /// Directly returns an `Allocation` containing an absolute path representation of the given type.
-crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation {
+crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
     let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
     let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
     tcx.intern_const_alloc(alloc)
index 23ec3875cbc1a51a38d4cbec791f9d0044389166..7d75c84d108357d35b993301f7da2816c7076cb4 100644 (file)
@@ -13,8 +13,9 @@
 use rustc_target::spec::abi::Abi;
 
 use super::{
-    AllocId, AllocRange, Allocation, Frame, ImmTy, InterpCx, InterpResult, LocalValue, MemPlace,
-    Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
+    AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
+    LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar,
+    StackPopUnwind,
 };
 
 /// Data returned by Machine::stack_pop,
@@ -252,7 +253,7 @@ fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx
     fn before_access_global(
         _memory_extra: &Self::MemoryExtra,
         _alloc_id: AllocId,
-        _allocation: &Allocation,
+        _allocation: ConstAllocation<'tcx>,
         _static_def_id: Option<DefId>,
         _is_write: bool,
     ) -> InterpResult<'tcx> {
index 04a6209990ccf72795e45716ae4f89f30db87675..6397fcaaf8d10844823f6990034488f4eeb25173 100644 (file)
@@ -275,6 +275,7 @@ pub fn reallocate(
         Ok(new_ptr)
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub fn deallocate(
         &mut self,
         ptr: Pointer<Option<M::PointerTag>>,
@@ -305,6 +306,8 @@ pub fn deallocate(
             .into());
         };
 
+        debug!(?alloc);
+
         if alloc.mutability == Mutability::Not {
             throw_ub_format!("deallocating immutable allocation {}", alloc_id);
         }
@@ -385,9 +388,9 @@ pub fn check_ptr_access_align(
                 CheckInAllocMsg::DerefTest | CheckInAllocMsg::MemoryAccessTest => {
                     AllocCheck::Dereferenceable
                 }
-                CheckInAllocMsg::PointerArithmeticTest | CheckInAllocMsg::InboundsTest => {
-                    AllocCheck::Live
-                }
+                CheckInAllocMsg::PointerArithmeticTest
+                | CheckInAllocMsg::OffsetFromTest
+                | CheckInAllocMsg::InboundsTest => AllocCheck::Live,
             };
             let (size, align) = self.get_size_and_align(alloc_id, check)?;
             Ok((size, align, ()))
@@ -525,12 +528,11 @@ fn get_global_alloc(
             }
         };
         M::before_access_global(&self.extra, id, alloc, def_id, is_write)?;
-        let alloc = Cow::Borrowed(alloc);
         // We got tcx memory. Let the machine initialize its "extra" stuff.
         let alloc = M::init_allocation_extra(
             self,
             id, // always use the ID we got as input, not the "hidden" one.
-            alloc,
+            Cow::Borrowed(alloc.inner()),
             M::GLOBAL_KIND.map(MemoryKind::Machine),
         );
         Ok(alloc)
@@ -711,6 +713,7 @@ pub fn get_size_and_align(
             Some(GlobalAlloc::Memory(alloc)) => {
                 // Need to duplicate the logic here, because the global allocations have
                 // different associated types than the interpreter-local ones.
+                let alloc = alloc.inner();
                 Ok((alloc.size(), alloc.align))
             }
             Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"),
@@ -867,7 +870,7 @@ fn write_allocation_track_relocs<'tcx, Tag: Provenance, Extra>(
                                 &mut *fmt,
                                 self.mem.tcx,
                                 &mut allocs_to_print,
-                                alloc,
+                                alloc.inner(),
                             )?;
                         }
                         Some(GlobalAlloc::Function(func)) => {
index 16870489176d77cb3da5c6081f43ab9cfbdfb7c7..fb4fe41bdbc4c31981b3007ab59cd9faf8c7a02d 100644 (file)
@@ -681,18 +681,22 @@ pub fn read_discriminant(
         let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?;
         assert_eq!(tag_layout.size, tag_val.layout.size);
         assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
-        let tag_val = tag_val.to_scalar()?;
-        trace!("tag value: {:?}", tag_val);
+        trace!("tag value: {}", tag_val);
 
         // Figure out which discriminant and variant this corresponds to.
         Ok(match *tag_encoding {
             TagEncoding::Direct => {
+                // Generate a specific error if `tag_val` is not an integer.
+                // (`tag_bits` itself is only used for error messages below.)
                 let tag_bits = tag_val
+                    .to_scalar()?
                     .try_to_int()
                     .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))?
                     .assert_bits(tag_layout.size);
                 // Cast bits from tag layout to discriminant layout.
-                let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
+                // After the checks we did above, this cannot fail.
+                let discr_val =
+                    self.misc_cast(&tag_val, discr_layout.ty).unwrap().to_scalar().unwrap();
                 let discr_bits = discr_val.assert_bits(discr_layout.size);
                 // Convert discriminant to variant index, and catch invalid discriminants.
                 let index = match *op.layout.ty.kind() {
@@ -712,6 +716,7 @@ pub fn read_discriminant(
                 (discr_val, index.0)
             }
             TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
+                let tag_val = tag_val.to_scalar()?;
                 // Compute the variant this niche value/"tag" corresponds to. With niche layout,
                 // discriminant (encoded in niche/tag) and variant index are the same.
                 let variants_start = niche_variants.start().as_u32();
index 079ce9f07b8e10f5e322ec4c03add05fc224dfec..6dae9dc72b7b4668df706aa5dc605f0e2c3a7ea4 100644 (file)
@@ -127,17 +127,29 @@ fn binary_int_op(
 
         // Shift ops can have an RHS with a different numeric type.
         if bin_op == Shl || bin_op == Shr {
-            let signed = left_layout.abi.is_signed();
             let size = u128::from(left_layout.size.bits());
+            // Even if `r` is signed, we treat it as if it was unsigned (i.e., we use its
+            // zero-extended form). This matches the codegen backend:
+            // <https://github.com/rust-lang/rust/blob/c274e4969f058b1c644243181ece9f829efa7594/compiler/rustc_codegen_ssa/src/base.rs#L315-L317>.
+            // The overflow check is also ignorant to the sign:
+            // <https://github.com/rust-lang/rust/blob/c274e4969f058b1c644243181ece9f829efa7594/compiler/rustc_codegen_ssa/src/mir/rvalue.rs#L728>.
+            // This would behave rather strangely if we had integer types of size 256: a shift by
+            // -1i8 would actually shift by 255, but that would *not* be considered overflowing. A
+            // shift by -1i16 though would be considered overflowing. If we had integers of size
+            // 512, then a shift by -1i8 would even produce a different result than one by -1i16:
+            // the first shifts by 255, the latter by u16::MAX % 512 = 511. Lucky enough, our
+            // integers are maximally 128bits wide, so negative shifts *always* overflow and we have
+            // consistent results for the same value represented at different bit widths.
+            assert!(size <= 128);
             let overflow = r >= size;
             // The shift offset is implicitly masked to the type size, to make sure this operation
             // is always defined. This is the one MIR operator that does *not* directly map to a
             // single LLVM operation. See
-            // <https://github.com/rust-lang/rust/blob/a3b9405ae7bb6ab4e8103b414e75c44598a10fd2/compiler/rustc_codegen_ssa/src/common.rs#L131-L158>
+            // <https://github.com/rust-lang/rust/blob/c274e4969f058b1c644243181ece9f829efa7594/compiler/rustc_codegen_ssa/src/common.rs#L131-L158>
             // for the corresponding truncation in our codegen backends.
             let r = r % size;
             let r = u32::try_from(r).unwrap(); // we masked so this will always fit
-            let result = if signed {
+            let result = if left_layout.abi.is_signed() {
                 let l = self.sign_extend(l, left_layout) as i128;
                 let result = match bin_op {
                     Shl => l.checked_shl(r).unwrap(),
index b78924490cae83da5b373081f91e0ec5fc13e660..7dc279cc840fba930b174c3e11b720e82c91d9d8 100644 (file)
@@ -230,8 +230,6 @@ pub fn check_body(&mut self) {
                 }
             }
 
-            self.check_item_predicates();
-
             for (idx, local) in body.local_decls.iter_enumerated() {
                 // Handle the return place below.
                 if idx == RETURN_PLACE || local.internal {
@@ -358,83 +356,11 @@ fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) {
 
             match *ty.kind() {
                 ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)),
-                ty::Opaque(..) => self.check_op(ops::ty::ImplTrait),
-                ty::FnPtr(..) => self.check_op(ops::ty::FnPtr(kind)),
-
-                ty::Dynamic(preds, _) => {
-                    for pred in preds.iter() {
-                        match pred.skip_binder() {
-                            ty::ExistentialPredicate::AutoTrait(_)
-                            | ty::ExistentialPredicate::Projection(_) => {
-                                self.check_op(ops::ty::DynTrait(kind))
-                            }
-                            ty::ExistentialPredicate::Trait(trait_ref) => {
-                                if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() {
-                                    self.check_op(ops::ty::DynTrait(kind))
-                                }
-                            }
-                        }
-                    }
-                }
                 _ => {}
             }
         }
     }
 
-    fn check_item_predicates(&mut self) {
-        let ConstCx { tcx, .. } = *self.ccx;
-
-        let mut current = self.def_id().to_def_id();
-        loop {
-            let predicates = tcx.predicates_of(current);
-            for (predicate, _) in predicates.predicates {
-                match predicate.kind().skip_binder() {
-                    ty::PredicateKind::RegionOutlives(_)
-                    | ty::PredicateKind::TypeOutlives(_)
-                    | ty::PredicateKind::WellFormed(_)
-                    | ty::PredicateKind::Projection(_)
-                    | ty::PredicateKind::ConstEvaluatable(..)
-                    | ty::PredicateKind::ConstEquate(..)
-                    | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
-                    ty::PredicateKind::ObjectSafe(_) => {
-                        bug!("object safe predicate on function: {:#?}", predicate)
-                    }
-                    ty::PredicateKind::ClosureKind(..) => {
-                        bug!("closure kind predicate on function: {:#?}", predicate)
-                    }
-                    ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) => {
-                        bug!("subtype/coerce predicate on function: {:#?}", predicate)
-                    }
-                    ty::PredicateKind::Trait(pred) => {
-                        if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
-                            continue;
-                        }
-                        match pred.self_ty().kind() {
-                            ty::Param(p) => {
-                                let generics = tcx.generics_of(current);
-                                let def = generics.type_param(p, tcx);
-                                let span = tcx.def_span(def.def_id);
-
-                                // These are part of the function signature, so treat them like
-                                // arguments when determining importance.
-                                let kind = LocalKind::Arg;
-
-                                self.check_op_spanned(ops::ty::TraitBound(kind), span);
-                            }
-                            // other kinds of bounds are either tautologies
-                            // or cause errors in other passes
-                            _ => continue,
-                        }
-                    }
-                }
-            }
-            match predicates.parent {
-                Some(parent) => current = parent,
-                None => break,
-            }
-        }
-    }
-
     fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) {
         match self.const_kind() {
             // In a const fn all borrows are transient or point to the places given via
@@ -613,7 +539,9 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                 ),
                 _,
                 _,
-            ) => self.check_op(ops::FnPtrCast),
+            ) => {
+                // Nothing to do here. Function pointer casts are allowed now.
+            }
 
             Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
                 // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur
index f6b92df92c04434ebfba7ca175c4e88cdc691394..ba248a3b6cbe59e286d9b84a1e21770f6c962c41 100644 (file)
@@ -355,31 +355,6 @@ fn build_error(
     }
 }
 
-#[derive(Debug)]
-pub struct FnPtrCast;
-impl<'tcx> NonConstOp<'tcx> for FnPtrCast {
-    fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
-        if ccx.const_kind() != hir::ConstContext::ConstFn {
-            Status::Allowed
-        } else {
-            Status::Unstable(sym::const_fn_fn_ptr_basics)
-        }
-    }
-
-    fn build_error(
-        &self,
-        ccx: &ConstCx<'_, 'tcx>,
-        span: Span,
-    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_fn_fn_ptr_basics,
-            span,
-            &format!("function pointer casts are not allowed in {}s", ccx.const_kind()),
-        )
-    }
-}
-
 #[derive(Debug)]
 pub struct Generator(pub hir::GeneratorKind);
 impl<'tcx> NonConstOp<'tcx> for Generator {
@@ -820,167 +795,4 @@ fn build_error(
             )
         }
     }
-
-    #[derive(Debug)]
-    pub struct FnPtr(pub mir::LocalKind);
-    impl<'tcx> NonConstOp<'tcx> for FnPtr {
-        fn importance(&self) -> DiagnosticImportance {
-            match self.0 {
-                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
-                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
-                    DiagnosticImportance::Primary
-                }
-            }
-        }
-
-        fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
-            if ccx.const_kind() != hir::ConstContext::ConstFn {
-                Status::Allowed
-            } else {
-                Status::Unstable(sym::const_fn_fn_ptr_basics)
-            }
-        }
-
-        fn build_error(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-            feature_err(
-                &ccx.tcx.sess.parse_sess,
-                sym::const_fn_fn_ptr_basics,
-                span,
-                &format!("function pointers cannot appear in {}s", ccx.const_kind()),
-            )
-        }
-    }
-
-    #[derive(Debug)]
-    pub struct ImplTrait;
-    impl<'tcx> NonConstOp<'tcx> for ImplTrait {
-        fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
-            Status::Unstable(sym::const_impl_trait)
-        }
-
-        fn build_error(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-            feature_err(
-                &ccx.tcx.sess.parse_sess,
-                sym::const_impl_trait,
-                span,
-                &format!("`impl Trait` is not allowed in {}s", ccx.const_kind()),
-            )
-        }
-    }
-
-    #[derive(Debug)]
-    pub struct TraitBound(pub mir::LocalKind);
-    impl<'tcx> NonConstOp<'tcx> for TraitBound {
-        fn importance(&self) -> DiagnosticImportance {
-            match self.0 {
-                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
-                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
-                    DiagnosticImportance::Primary
-                }
-            }
-        }
-
-        fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
-            if ccx.const_kind() != hir::ConstContext::ConstFn {
-                Status::Allowed
-            } else {
-                Status::Unstable(sym::const_fn_trait_bound)
-            }
-        }
-
-        fn build_error(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-            let mut err = feature_err(
-                &ccx.tcx.sess.parse_sess,
-                sym::const_fn_trait_bound,
-                span,
-                "trait bounds other than `Sized` on const fn parameters are unstable",
-            );
-
-            match ccx.fn_sig() {
-                Some(fn_sig) if !fn_sig.span.contains(span) => {
-                    err.span_label(fn_sig.span, "function declared as const here");
-                }
-                _ => {}
-            }
-
-            err
-        }
-    }
-
-    #[derive(Debug)]
-    pub struct DynTrait(pub mir::LocalKind);
-    impl<'tcx> NonConstOp<'tcx> for DynTrait {
-        fn importance(&self) -> DiagnosticImportance {
-            match self.0 {
-                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
-                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
-                    DiagnosticImportance::Primary
-                }
-            }
-        }
-
-        fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
-            if ccx.const_kind() != hir::ConstContext::ConstFn {
-                Status::Allowed
-            } else {
-                Status::Unstable(sym::const_fn_trait_bound)
-            }
-        }
-
-        fn build_error(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-            let mut err = feature_err(
-                &ccx.tcx.sess.parse_sess,
-                sym::const_fn_trait_bound,
-                span,
-                "trait objects in const fn are unstable",
-            );
-
-            match ccx.fn_sig() {
-                Some(fn_sig) if !fn_sig.span.contains(span) => {
-                    err.span_label(fn_sig.span, "function declared as const here");
-                }
-                _ => {}
-            }
-
-            err
-        }
-    }
-
-    /// A trait bound with the `?const Trait` opt-out
-    #[derive(Debug)]
-    pub struct TraitBoundNotConst;
-    impl<'tcx> NonConstOp<'tcx> for TraitBoundNotConst {
-        fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
-            Status::Unstable(sym::const_trait_bound_opt_out)
-        }
-
-        fn build_error(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-            feature_err(
-                &ccx.tcx.sess.parse_sess,
-                sym::const_trait_bound_opt_out,
-                span,
-                "`?const Trait` syntax is unstable",
-            )
-        }
-    }
 }
index ad296c97659d209e1978816e7788a7e362bc9f66..b82e97172614b0df6e0e29ad160973c73b07722f 100644 (file)
@@ -20,7 +20,7 @@ stable_deref_trait = "1.0.0"
 rayon = { version = "0.3.2", package = "rustc-rayon" }
 rayon-core = { version = "0.3.2", package = "rustc-rayon-core" }
 rustc-hash = "1.1.0"
-smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["const_generics", "union", "may_dangle"] }
 rustc_index = { path = "../rustc_index", package = "rustc_index" }
 bitflags = "1.2.1"
 measureme = "10.0.0"
index 46054fe7bcbb97234dff1580361a490e4a2a0cd7..7a320b10b60300460fc3efe19811798742efb599 100644 (file)
@@ -1,3 +1,4 @@
+use crate::stable_hasher::{HashStable, StableHasher};
 use std::cmp::Ordering;
 use std::hash::{Hash, Hasher};
 use std::ops::Deref;
@@ -62,13 +63,17 @@ fn eq(&self, other: &Self) -> bool {
 
 impl<'a, T> Eq for Interned<'a, T> {}
 
-// In practice you can't intern any `T` that doesn't implement `Eq`, because
-// that's needed for hashing. Therefore, we won't be interning any `T` that
-// implements `PartialOrd` without also implementing `Ord`. So we can have the
-// bound `T: Ord` here and avoid duplication with the `Ord` impl below.
-impl<'a, T: Ord> PartialOrd for Interned<'a, T> {
+impl<'a, T: PartialOrd> PartialOrd for Interned<'a, T> {
     fn partial_cmp(&self, other: &Interned<'a, T>) -> Option<Ordering> {
-        Some(self.cmp(other))
+        // Pointer equality implies equality, due to the uniqueness constraint,
+        // but the contents must be compared otherwise.
+        if ptr::eq(self.0, other.0) {
+            Some(Ordering::Equal)
+        } else {
+            let res = self.0.partial_cmp(&other.0);
+            debug_assert_ne!(res, Some(Ordering::Equal));
+            res
+        }
     }
 }
 
@@ -94,5 +99,14 @@ fn hash<H: Hasher>(&self, s: &mut H) {
     }
 }
 
+impl<T, CTX> HashStable<CTX> for Interned<'_, T>
+where
+    T: HashStable<CTX>,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.0.hash_stable(hcx, hasher);
+    }
+}
+
 #[cfg(test)]
 mod tests;
index b1e59d6502913621afd4c6d2b63412d84f5d0118..1a3fe652521567d839b359fdffa81ae0fd70c9b2 100644 (file)
@@ -80,6 +80,7 @@ macro_rules! unlikely {
 pub mod owning_ref;
 pub mod sip128;
 pub mod small_c_str;
+pub mod small_str;
 pub mod snapshot_map;
 pub mod stable_map;
 pub mod svh;
index cd9025245628e628c1f66b3e712eef03777e4162..3a8ab8ff9911e4a34d2b9d01027dec1d328c7b01 100644 (file)
@@ -62,6 +62,7 @@ pub fn spilled(&self) -> bool {
 impl Deref for SmallCStr {
     type Target = ffi::CStr;
 
+    #[inline]
     fn deref(&self) -> &ffi::CStr {
         self.as_c_str()
     }
diff --git a/compiler/rustc_data_structures/src/small_str.rs b/compiler/rustc_data_structures/src/small_str.rs
new file mode 100644 (file)
index 0000000..800acb1
--- /dev/null
@@ -0,0 +1,68 @@
+use smallvec::SmallVec;
+
+#[cfg(test)]
+mod tests;
+
+/// Like SmallVec but for strings.
+#[derive(Default)]
+pub struct SmallStr<const N: usize>(SmallVec<[u8; N]>);
+
+impl<const N: usize> SmallStr<N> {
+    #[inline]
+    pub fn new() -> Self {
+        SmallStr(SmallVec::default())
+    }
+
+    #[inline]
+    pub fn push_str(&mut self, s: &str) {
+        self.0.extend_from_slice(s.as_bytes());
+    }
+
+    #[inline]
+    pub fn empty(&self) -> bool {
+        self.0.is_empty()
+    }
+
+    #[inline]
+    pub fn spilled(&self) -> bool {
+        self.0.spilled()
+    }
+
+    #[inline]
+    pub fn as_str(&self) -> &str {
+        unsafe { std::str::from_utf8_unchecked(self.0.as_slice()) }
+    }
+}
+
+impl<const N: usize> std::ops::Deref for SmallStr<N> {
+    type Target = str;
+
+    #[inline]
+    fn deref(&self) -> &str {
+        self.as_str()
+    }
+}
+
+impl<const N: usize, A: AsRef<str>> FromIterator<A> for SmallStr<N> {
+    #[inline]
+    fn from_iter<T>(iter: T) -> Self
+    where
+        T: IntoIterator<Item = A>,
+    {
+        let mut s = SmallStr::default();
+        s.extend(iter);
+        s
+    }
+}
+
+impl<const N: usize, A: AsRef<str>> Extend<A> for SmallStr<N> {
+    #[inline]
+    fn extend<T>(&mut self, iter: T)
+    where
+        T: IntoIterator<Item = A>,
+    {
+        for a in iter.into_iter() {
+            self.push_str(a.as_ref());
+        }
+    }
+}
diff --git a/compiler/rustc_data_structures/src/small_str/tests.rs b/compiler/rustc_data_structures/src/small_str/tests.rs
new file mode 100644 (file)
index 0000000..7635a9b
--- /dev/null
@@ -0,0 +1,20 @@
+use super::*;
+
+#[test]
+fn empty() {
+    let s = SmallStr::<1>::new();
+    assert!(s.empty());
+    assert_eq!("", s.as_str());
+    assert!(!s.spilled());
+}
+
+#[test]
+fn from_iter() {
+    let s = ["aa", "bb", "cc"].iter().collect::<SmallStr<6>>();
+    assert_eq!("aabbcc", s.as_str());
+    assert!(!s.spilled());
+
+    let s = ["aa", "bb", "cc", "dd"].iter().collect::<SmallStr<6>>();
+    assert_eq!("aabbccdd", s.as_str());
+    assert!(s.spilled());
+}
index 0af571610fe9510c553551e3f599caf4affaf85e..780753ed200e997abb27b87f5a28f3c162924e56 100644 (file)
@@ -49,7 +49,7 @@ struct Edge {
     target: Index,
 }
 
-impl<T: Eq + Hash> TransitiveRelation<T> {
+impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
     pub fn is_empty(&self) -> bool {
         self.edges.is_empty()
     }
@@ -58,8 +58,8 @@ pub fn elements(&self) -> impl Iterator<Item = &T> {
         self.elements.iter()
     }
 
-    fn index(&self, a: &T) -> Option<Index> {
-        self.elements.get_index_of(a).map(Index)
+    fn index(&self, a: T) -> Option<Index> {
+        self.elements.get_index_of(&a).map(Index)
     }
 
     fn add_index(&mut self, a: T) -> Index {
@@ -76,12 +76,12 @@ fn add_index(&mut self, a: T) -> Index {
     /// `None`.
     pub fn maybe_map<F, U>(&self, mut f: F) -> Option<TransitiveRelation<U>>
     where
-        F: FnMut(&T) -> Option<U>,
-        U: Clone + Debug + Eq + Hash + Clone,
+        F: FnMut(T) -> Option<U>,
+        U: Clone + Debug + Eq + Hash + Copy,
     {
         let mut result = TransitiveRelation::default();
         for edge in &self.edges {
-            result.add(f(&self.elements[edge.source.0])?, f(&self.elements[edge.target.0])?);
+            result.add(f(self.elements[edge.source.0])?, f(self.elements[edge.target.0])?);
         }
         Some(result)
     }
@@ -100,7 +100,7 @@ pub fn add(&mut self, a: T, b: T) {
     }
 
     /// Checks whether `a < target` (transitively)
-    pub fn contains(&self, a: &T, b: &T) -> bool {
+    pub fn contains(&self, a: T, b: T) -> bool {
         match (self.index(a), self.index(b)) {
             (Some(a), Some(b)) => self.with_closure(|closure| closure.contains(a.0, b.0)),
             (None, _) | (_, None) => false,
@@ -113,10 +113,10 @@ pub fn contains(&self, a: &T, b: &T) -> bool {
     /// Really this probably ought to be `impl Iterator<Item = &T>`, but
     /// I'm too lazy to make that work, and -- given the caching
     /// strategy -- it'd be a touch tricky anyhow.
-    pub fn reachable_from(&self, a: &T) -> Vec<&T> {
+    pub fn reachable_from(&self, a: T) -> Vec<T> {
         match self.index(a) {
             Some(a) => {
-                self.with_closure(|closure| closure.iter(a.0).map(|i| &self.elements[i]).collect())
+                self.with_closure(|closure| closure.iter(a.0).map(|i| self.elements[i]).collect())
             }
             None => vec![],
         }
@@ -157,7 +157,7 @@ pub fn reachable_from(&self, a: &T) -> Vec<&T> {
     /// a -> a1
     /// b -> b1
     /// ```
-    pub fn postdom_upper_bound(&self, a: &T, b: &T) -> Option<&T> {
+    pub fn postdom_upper_bound(&self, a: T, b: T) -> Option<T> {
         let mubs = self.minimal_upper_bounds(a, b);
         self.mutual_immediate_postdominator(mubs)
     }
@@ -165,7 +165,7 @@ pub fn postdom_upper_bound(&self, a: &T, b: &T) -> Option<&T> {
     /// Viewing the relation as a graph, computes the "mutual
     /// immediate postdominator" of a set of points (if one
     /// exists). See `postdom_upper_bound` for details.
-    pub fn mutual_immediate_postdominator<'a>(&'a self, mut mubs: Vec<&'a T>) -> Option<&'a T> {
+    pub fn mutual_immediate_postdominator<'a>(&'a self, mut mubs: Vec<T>) -> Option<T> {
         loop {
             match mubs.len() {
                 0 => return None,
@@ -189,7 +189,7 @@ pub fn mutual_immediate_postdominator<'a>(&'a self, mut mubs: Vec<&'a T>) -> Opt
     ///     internal indices).
     ///
     /// Note that this set can, in principle, have any size.
-    pub fn minimal_upper_bounds(&self, a: &T, b: &T) -> Vec<&T> {
+    pub fn minimal_upper_bounds(&self, a: T, b: T) -> Vec<T> {
         let (Some(mut a), Some(mut b)) = (self.index(a), self.index(b)) else {
             return vec![];
         };
@@ -267,7 +267,7 @@ pub fn minimal_upper_bounds(&self, a: &T, b: &T) -> Vec<&T> {
         lub_indices
             .into_iter()
             .rev() // (4)
-            .map(|i| &self.elements[i])
+            .map(|i| self.elements[i])
             .collect()
     }
 
@@ -290,7 +290,7 @@ pub fn minimal_upper_bounds(&self, a: &T, b: &T) -> Vec<&T> {
     ///
     /// then `parents(a)` returns `[b, c]`. The `postdom_parent` function
     /// would further reduce this to just `f`.
-    pub fn parents(&self, a: &T) -> Vec<&T> {
+    pub fn parents(&self, a: T) -> Vec<T> {
         let Some(a) = self.index(a) else {
             return vec![];
         };
@@ -314,7 +314,7 @@ pub fn parents(&self, a: &T) -> Vec<&T> {
         ancestors
             .into_iter()
             .rev() // (4)
-            .map(|i| &self.elements[i])
+            .map(|i| self.elements[i])
             .collect()
     }
 
@@ -350,10 +350,10 @@ fn compute_closure(&self) -> BitMatrix<usize, usize> {
 
     /// Lists all the base edges in the graph: the initial _non-transitive_ set of element
     /// relations, which will be later used as the basis for the transitive closure computation.
-    pub fn base_edges(&self) -> impl Iterator<Item = (&T, &T)> {
+    pub fn base_edges(&self) -> impl Iterator<Item = (T, T)> + '_ {
         self.edges
             .iter()
-            .map(move |edge| (&self.elements[edge.source.0], &self.elements[edge.target.0]))
+            .map(move |edge| (self.elements[edge.source.0], self.elements[edge.target.0]))
     }
 }
 
index 9fa7224376c1c35fc2f260ca6aaf7aadd2efe1e7..f63b1be1ddce35a2efafe766fa39820b3ec7a4c2 100644 (file)
@@ -1,9 +1,9 @@
 use super::*;
 
-impl<T: Eq + Hash> TransitiveRelation<T> {
+impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
     /// A "best" parent in some sense. See `parents` and
     /// `postdom_upper_bound` for more details.
-    fn postdom_parent(&self, a: &T) -> Option<&T> {
+    fn postdom_parent(&self, a: T) -> Option<T> {
         self.mutual_immediate_postdominator(self.parents(a))
     }
 }
@@ -13,10 +13,10 @@ fn test_one_step() {
     let mut relation = TransitiveRelation::default();
     relation.add("a", "b");
     relation.add("a", "c");
-    assert!(relation.contains(&"a", &"c"));
-    assert!(relation.contains(&"a", &"b"));
-    assert!(!relation.contains(&"b", &"a"));
-    assert!(!relation.contains(&"a", &"d"));
+    assert!(relation.contains("a", "c"));
+    assert!(relation.contains("a", "b"));
+    assert!(!relation.contains("b", "a"));
+    assert!(!relation.contains("a", "d"));
 }
 
 #[test]
@@ -32,17 +32,17 @@ fn test_many_steps() {
 
     relation.add("e", "g");
 
-    assert!(relation.contains(&"a", &"b"));
-    assert!(relation.contains(&"a", &"c"));
-    assert!(relation.contains(&"a", &"d"));
-    assert!(relation.contains(&"a", &"e"));
-    assert!(relation.contains(&"a", &"f"));
-    assert!(relation.contains(&"a", &"g"));
+    assert!(relation.contains("a", "b"));
+    assert!(relation.contains("a", "c"));
+    assert!(relation.contains("a", "d"));
+    assert!(relation.contains("a", "e"));
+    assert!(relation.contains("a", "f"));
+    assert!(relation.contains("a", "g"));
 
-    assert!(relation.contains(&"b", &"g"));
+    assert!(relation.contains("b", "g"));
 
-    assert!(!relation.contains(&"a", &"x"));
-    assert!(!relation.contains(&"b", &"f"));
+    assert!(!relation.contains("a", "x"));
+    assert!(!relation.contains("b", "f"));
 }
 
 #[test]
@@ -54,9 +54,9 @@ fn mubs_triangle() {
     let mut relation = TransitiveRelation::default();
     relation.add("a", "tcx");
     relation.add("b", "tcx");
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"tcx"]);
-    assert_eq!(relation.parents(&"a"), vec![&"tcx"]);
-    assert_eq!(relation.parents(&"b"), vec![&"tcx"]);
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["tcx"]);
+    assert_eq!(relation.parents("a"), vec!["tcx"]);
+    assert_eq!(relation.parents("b"), vec!["tcx"]);
 }
 
 #[test]
@@ -81,10 +81,10 @@ fn mubs_best_choice1() {
     relation.add("3", "1");
     relation.add("3", "2");
 
-    assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"2"]);
-    assert_eq!(relation.parents(&"0"), vec![&"2"]);
-    assert_eq!(relation.parents(&"2"), vec![&"1"]);
-    assert!(relation.parents(&"1").is_empty());
+    assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["2"]);
+    assert_eq!(relation.parents("0"), vec!["2"]);
+    assert_eq!(relation.parents("2"), vec!["1"]);
+    assert!(relation.parents("1").is_empty());
 }
 
 #[test]
@@ -108,10 +108,10 @@ fn mubs_best_choice2() {
     relation.add("3", "1");
     relation.add("3", "2");
 
-    assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"1"]);
-    assert_eq!(relation.parents(&"0"), vec![&"1"]);
-    assert_eq!(relation.parents(&"1"), vec![&"2"]);
-    assert!(relation.parents(&"2").is_empty());
+    assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["1"]);
+    assert_eq!(relation.parents("0"), vec!["1"]);
+    assert_eq!(relation.parents("1"), vec!["2"]);
+    assert!(relation.parents("2").is_empty());
 }
 
 #[test]
@@ -125,9 +125,9 @@ fn mubs_no_best_choice() {
     relation.add("3", "1");
     relation.add("3", "2");
 
-    assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"1", &"2"]);
-    assert_eq!(relation.parents(&"0"), vec![&"1", &"2"]);
-    assert_eq!(relation.parents(&"3"), vec![&"1", &"2"]);
+    assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["1", "2"]);
+    assert_eq!(relation.parents("0"), vec!["1", "2"]);
+    assert_eq!(relation.parents("3"), vec!["1", "2"]);
 }
 
 #[test]
@@ -145,8 +145,8 @@ fn mubs_best_choice_scc() {
     relation.add("3", "1");
     relation.add("3", "2");
 
-    assert_eq!(relation.minimal_upper_bounds(&"0", &"3"), vec![&"1"]);
-    assert_eq!(relation.parents(&"0"), vec![&"1"]);
+    assert_eq!(relation.minimal_upper_bounds("0", "3"), vec!["1"]);
+    assert_eq!(relation.parents("0"), vec!["1"]);
 }
 
 #[test]
@@ -165,10 +165,10 @@ fn pdub_crisscross() {
     relation.add("a1", "x");
     relation.add("b1", "x");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"a1", &"b1"]);
-    assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
-    assert_eq!(relation.postdom_parent(&"a"), Some(&"x"));
-    assert_eq!(relation.postdom_parent(&"b"), Some(&"x"));
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["a1", "b1"]);
+    assert_eq!(relation.postdom_upper_bound("a", "b"), Some("x"));
+    assert_eq!(relation.postdom_parent("a"), Some("x"));
+    assert_eq!(relation.postdom_parent("b"), Some("x"));
 }
 
 #[test]
@@ -195,12 +195,12 @@ fn pdub_crisscross_more() {
     relation.add("a3", "x");
     relation.add("b2", "x");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"a1", &"b1"]);
-    assert_eq!(relation.minimal_upper_bounds(&"a1", &"b1"), vec![&"a2", &"b2"]);
-    assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["a1", "b1"]);
+    assert_eq!(relation.minimal_upper_bounds("a1", "b1"), vec!["a2", "b2"]);
+    assert_eq!(relation.postdom_upper_bound("a", "b"), Some("x"));
 
-    assert_eq!(relation.postdom_parent(&"a"), Some(&"x"));
-    assert_eq!(relation.postdom_parent(&"b"), Some(&"x"));
+    assert_eq!(relation.postdom_parent("a"), Some("x"));
+    assert_eq!(relation.postdom_parent("b"), Some("x"));
 }
 
 #[test]
@@ -216,13 +216,13 @@ fn pdub_lub() {
     relation.add("a1", "x");
     relation.add("b1", "x");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"x"]);
-    assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x"));
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["x"]);
+    assert_eq!(relation.postdom_upper_bound("a", "b"), Some("x"));
 
-    assert_eq!(relation.postdom_parent(&"a"), Some(&"a1"));
-    assert_eq!(relation.postdom_parent(&"b"), Some(&"b1"));
-    assert_eq!(relation.postdom_parent(&"a1"), Some(&"x"));
-    assert_eq!(relation.postdom_parent(&"b1"), Some(&"x"));
+    assert_eq!(relation.postdom_parent("a"), Some("a1"));
+    assert_eq!(relation.postdom_parent("b"), Some("b1"));
+    assert_eq!(relation.postdom_parent("a1"), Some("x"));
+    assert_eq!(relation.postdom_parent("b1"), Some("x"));
 }
 
 #[test]
@@ -238,7 +238,7 @@ fn mubs_intermediate_node_on_one_side_only() {
     relation.add("c", "d");
     relation.add("b", "d");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"d"]);
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["d"]);
 }
 
 #[test]
@@ -259,7 +259,7 @@ fn mubs_scc_1() {
     relation.add("a", "d");
     relation.add("b", "d");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]);
 }
 
 #[test]
@@ -279,7 +279,7 @@ fn mubs_scc_2() {
     relation.add("b", "d");
     relation.add("b", "c");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]);
 }
 
 #[test]
@@ -300,7 +300,7 @@ fn mubs_scc_3() {
     relation.add("b", "d");
     relation.add("b", "e");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]);
 }
 
 #[test]
@@ -322,7 +322,7 @@ fn mubs_scc_4() {
     relation.add("a", "d");
     relation.add("b", "e");
 
-    assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]);
+    assert_eq!(relation.minimal_upper_bounds("a", "b"), vec!["c"]);
 }
 
 #[test]
@@ -357,6 +357,6 @@ fn parent() {
         relation.add(a, b);
     }
 
-    let p = relation.postdom_parent(&3);
-    assert_eq!(p, Some(&0));
+    let p = relation.postdom_parent(3);
+    assert_eq!(p, Some(0));
 }
index a59d91ea789001db3feabf73598a1cd4a234770f..39ebd57b4b296decfddd85a1874c3efe8559b399 100644 (file)
@@ -7,6 +7,7 @@
 use crate::ToolMetadata;
 use rustc_lint_defs::Applicability;
 use rustc_serialize::json::Json;
+use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use std::fmt;
 use std::hash::{Hash, Hasher};
@@ -342,6 +343,18 @@ pub fn span_help<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self {
         self
     }
 
+    /// Help the user upgrade to the latest edition.
+    /// This is factored out to make sure it does the right thing with `Cargo.toml`.
+    pub fn help_use_latest_edition(&mut self) -> &mut Self {
+        if std::env::var_os("CARGO").is_some() {
+            self.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
+        } else {
+            self.help(&format!("pass `--edition {}` to `rustc`", LATEST_STABLE_EDITION));
+        }
+        self.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+        self
+    }
+
     /// Disallow attaching suggestions this diagnostic.
     /// Any suggestions attached e.g. with the `span_suggestion_*` methods
     /// (before and after the call to `disable_suggestions`) will be ignored.
index 5dc71f1620096113c04ccefde7ab58c8ceda3dcd..98b8b2a569edde1bfb6f4f5e1261cb3e2e99087b 100644 (file)
@@ -409,6 +409,7 @@ pub fn span_labels(
         sp: impl Into<MultiSpan>,
         msg: &str,
     ) -> &mut Self);
+    forward!(pub fn help_use_latest_edition(&mut self,) -> &mut Self);
     forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
 
     forward!(pub fn disable_suggestions(&mut self,) -> &mut Self);
index 52c44231d8f0e0783d288a65429539f095bca050..831d408195e2feede83e3e6f26f7f475bcff38cf 100644 (file)
@@ -1657,6 +1657,31 @@ enum DisplaySuggestion {
             let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
             draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
             let mut lines = complete.lines();
+            if lines.clone().next().is_none() {
+                // Account for a suggestion to completely remove a line(s) with whitespace (#94192).
+                let line_end = sm.lookup_char_pos(parts[0].span.hi()).line;
+                for line in line_start..=line_end {
+                    buffer.puts(
+                        row_num - 1 + line - line_start,
+                        0,
+                        &self.maybe_anonymized(line),
+                        Style::LineNumber,
+                    );
+                    buffer.puts(
+                        row_num - 1 + line - line_start,
+                        max_line_num_len + 1,
+                        "- ",
+                        Style::Removal,
+                    );
+                    buffer.puts(
+                        row_num - 1 + line - line_start,
+                        max_line_num_len + 3,
+                        &normalize_whitespace(&*file_lines.file.get_line(line - 1).unwrap()),
+                        Style::Removal,
+                    );
+                }
+                row_num += line_end - line_start;
+            }
             for (line_pos, (line, highlight_parts)) in
                 lines.by_ref().zip(highlights).take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate()
             {
index 217d3ec2c247ae6edbd6dcaf26677eb6d991bde5..3641c38f9dcd08bd71d15e543858dc56b18bb040 100644 (file)
@@ -1087,12 +1087,12 @@ fn print_error_count(&mut self, registry: &Registry) {
         let warnings = match self.deduplicated_warn_count {
             0 => String::new(),
             1 => "1 warning emitted".to_string(),
-            count => format!("{} warnings emitted", count),
+            count => format!("{count} warnings emitted"),
         };
         let errors = match self.deduplicated_err_count {
             0 => String::new(),
             1 => "aborting due to previous error".to_string(),
-            count => format!("aborting due to {} previous errors", count),
+            count => format!("aborting due to {count} previous errors"),
         };
         if self.treat_err_as_bug() {
             return;
index b024524aa2968e730187350070b5ea3783d175e3..8a9efe01368e39625efca240f973ad2f3e45d42b 100644 (file)
@@ -3,6 +3,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(if_let_guard)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(proc_macro_diagnostic)]
 #![feature(proc_macro_internals)]
index 5244ac36bba5de5badcc923c8728078b06e229b8..3d4c77aba7339ebe37516c84a08f3634d5c0cc40 100644 (file)
@@ -6,17 +6,17 @@
 crate mod macro_check;
 crate mod macro_parser;
 crate mod macro_rules;
+crate mod metavar_expr;
 crate mod quoted;
 crate mod transcribe;
 
+use metavar_expr::MetaVarExpr;
 use rustc_ast::token::{self, NonterminalKind, Token, TokenKind};
 use rustc_ast::tokenstream::DelimSpan;
-
+use rustc_data_structures::sync::Lrc;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
-use rustc_data_structures::sync::Lrc;
-
 /// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note
 /// that the delimiter itself might be `NoDelim`.
 #[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
@@ -73,8 +73,8 @@ enum KleeneOp {
     ZeroOrOne,
 }
 
-/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
-/// are "first-class" token trees. Useful for parsing macros.
+/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, `$(...)`,
+/// and `${...}` are "first-class" token trees. Useful for parsing macros.
 #[derive(Debug, Clone, PartialEq, Encodable, Decodable)]
 enum TokenTree {
     Token(Token),
@@ -85,6 +85,8 @@ enum TokenTree {
     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 */, Option<NonterminalKind>),
+    /// A meta-variable expression inside `${...}`
+    MetaVarExpr(DelimSpan, MetaVarExpr),
 }
 
 impl TokenTree {
@@ -139,7 +141,9 @@ fn span(&self) -> Span {
             TokenTree::Token(Token { span, .. })
             | TokenTree::MetaVar(span, _)
             | TokenTree::MetaVarDecl(span, _, _) => span,
-            TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(),
+            TokenTree::Delimited(span, _)
+            | TokenTree::MetaVarExpr(span, _)
+            | TokenTree::Sequence(span, _) => span.entire(),
         }
     }
 
index 3497e5ad543a1fcb6cb2b3f5d8df86086543f41d..88e11693220937da33a66996e74d7ff48ac346cf 100644 (file)
@@ -278,6 +278,8 @@ fn check_binders(
                 binders.insert(name, BinderInfo { span, ops: ops.into() });
             }
         }
+        // `MetaVarExpr` can not appear in the LHS of a macro arm
+        TokenTree::MetaVarExpr(..) => {}
         TokenTree::Delimited(_, ref del) => {
             for tt in &del.tts {
                 check_binders(sess, node_id, tt, macros, binders, ops, valid);
@@ -335,6 +337,8 @@ fn check_occurrences(
             let name = MacroRulesNormalizedIdent::new(name);
             check_ops_is_prefix(sess, node_id, macros, binders, ops, span, name);
         }
+        // FIXME(c410-f3r) Check token (https://github.com/rust-lang/rust/issues/93902)
+        TokenTree::MetaVarExpr(..) => {}
         TokenTree::Delimited(_, ref del) => {
             check_nested_occurrences(sess, node_id, &del.tts, macros, binders, ops, valid);
         }
index bb36dfd793d4a03bb3a8b96a50b281661323079f..dedfd779bb416d7af3459540a860919a7b7244e9 100644 (file)
@@ -122,7 +122,7 @@ fn get_tt(&self, index: usize) -> TokenTree {
 
 /// An unzipping of `TokenTree`s... see the `stack` field of `MatcherPos`.
 ///
-/// This is used by `inner_parse_loop` to keep track of delimited submatchers that we have
+/// This is used by `parse_tt_inner` to keep track of delimited submatchers that we have
 /// descended into.
 #[derive(Clone)]
 struct MatcherTtFrame<'tt> {
@@ -200,7 +200,7 @@ struct MatcherPos<'root, 'tt> {
 
 // This type is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MatcherPos<'_, '_>, 192);
+rustc_data_structures::static_assert_size!(MatcherPos<'_, '_>, 240);
 
 impl<'root, 'tt> MatcherPos<'root, 'tt> {
     /// Generates the top-level matcher position in which the "dot" is before the first token of
@@ -321,10 +321,13 @@ pub(super) fn count_names(ms: &[TokenTree]) -> usize {
     ms.iter().fold(0, |count, elt| {
         count
             + match *elt {
-                TokenTree::Sequence(_, ref seq) => seq.num_captures,
                 TokenTree::Delimited(_, ref delim) => count_names(&delim.tts),
                 TokenTree::MetaVar(..) => 0,
                 TokenTree::MetaVarDecl(..) => 1,
+                // FIXME(c410-f3r) MetaVarExpr should be handled instead of being ignored
+                // https://github.com/rust-lang/rust/issues/9390
+                TokenTree::MetaVarExpr(..) => 0,
+                TokenTree::Sequence(_, ref seq) => seq.num_captures,
                 TokenTree::Token(..) => 0,
             }
     })
@@ -436,7 +439,8 @@ fn n_rec<I: Iterator<Item = NamedMatch>>(
                 }
                 Occupied(..) => return Err((sp, format!("duplicated bind name: {}", bind_name))),
             },
-            TokenTree::MetaVar(..) | TokenTree::Token(..) => (),
+            TokenTree::Token(..) => (),
+            TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
         }
 
         Ok(())
@@ -476,21 +480,24 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool {
 ///   successful execution of this function.
 /// - `next_items`: the set of newly generated items. These are used to replenish `cur_items` in
 ///   the function `parse`.
-/// - `eof_items`: the set of items that would be valid if this was the EOF.
 /// - `bb_items`: the set of items that are waiting for the black-box parser.
 /// - `token`: the current token of the parser.
 ///
 /// # Returns
 ///
-/// A `ParseResult`. Note that matches are kept track of through the items generated.
-fn inner_parse_loop<'root, 'tt>(
+/// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept track of
+/// through the items generated.
+fn parse_tt_inner<'root, 'tt>(
     sess: &ParseSess,
+    ms: &[TokenTree],
     cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
-    next_items: &mut Vec<MatcherPosHandle<'root, 'tt>>,
+    next_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
     bb_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
-    eof_items: &mut EofItems<'root, 'tt>,
     token: &Token,
-) -> Result<(), (rustc_span::Span, String)> {
+) -> Option<NamedParseResult> {
+    // Matcher positions that would be valid if the macro invocation was over now
+    let mut eof_items = EofItems::None;
+
     // Pop items from `cur_items` until it is empty.
     while let Some(mut item) = cur_items.pop() {
         // When unzipped trees end, remove them. This corresponds to backtracking out of a
@@ -517,6 +524,8 @@ fn inner_parse_loop<'root, 'tt>(
             // then we could be at the end of a sequence or at the beginning of the next
             // repetition.
             if let Some(repetition) = &item.repetition {
+                debug_assert!(matches!(item.top_elts, Tt(TokenTree::Sequence(..))));
+
                 // At this point, regardless of whether there is a separator, we should add all
                 // matches from the complete repetition of the sequence to the shared, top-level
                 // `matches` list (actually, `up.matches`, which could itself not be the top-level,
@@ -560,7 +569,7 @@ fn inner_parse_loop<'root, 'tt>(
             } else {
                 // If we are not in a repetition, then being at the end of a matcher means that we
                 // have reached the potential end of the input.
-                *eof_items = match eof_items {
+                eof_items = match eof_items {
                     EofItems::None => EofItems::One(item),
                     EofItems::One(_) | EofItems::Multiple => EofItems::Multiple,
                 }
@@ -608,7 +617,7 @@ 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 Err((span, "missing fragment specifier".to_string()));
+                        return Some(Error(span, "missing fragment specifier".to_string()));
                     }
                 }
 
@@ -650,13 +659,36 @@ fn inner_parse_loop<'root, 'tt>(
                 // rules. NOTE that this is not necessarily an error unless _all_ items in
                 // `cur_items` end up doing this. There may still be some other matchers that do
                 // end up working out.
-                TokenTree::Token(..) | TokenTree::MetaVar(..) => {}
+                TokenTree::Token(..) => {}
+
+                TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
             }
         }
     }
 
-    // Yay a successful parse (so far)!
-    Ok(())
+    // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
+    // either the parse is ambiguous (which should never happen) or there is a syntax error.
+    if *token == token::Eof {
+        Some(match eof_items {
+            EofItems::One(mut eof_item) => {
+                let matches =
+                    eof_item.matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap());
+                nameize(sess, ms, matches)
+            }
+            EofItems::Multiple => {
+                Error(token.span, "ambiguity: multiple successful parses".to_string())
+            }
+            EofItems::None => Failure(
+                Token::new(
+                    token::Eof,
+                    if token.span.is_dummy() { token.span } else { token.span.shrink_to_hi() },
+                ),
+                "missing tokens in macro arguments",
+            ),
+        })
+    } else {
+        None
+    }
 }
 
 /// Use the given sequence of token trees (`ms`) as a matcher. Match the token
@@ -667,7 +699,7 @@ pub(super) fn parse_tt(
     macro_name: Ident,
 ) -> NamedParseResult {
     // A queue of possible matcher positions. We initialize it with the matcher position in which
-    // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then
+    // the "dot" is before the first token of the first token tree in `ms`. `parse_tt_inner` then
     // processes all of these possible matcher positions and produces possible next positions into
     // `next_items`. After some post-processing, the contents of `next_items` replenish `cur_items`
     // and we start over again.
@@ -676,135 +708,118 @@ pub(super) fn parse_tt(
     // there are frequently *no* others! -- are allocated on the heap.
     let mut initial = MatcherPos::new(ms);
     let mut cur_items = smallvec![MatcherPosHandle::Ref(&mut initial)];
-    let mut next_items = Vec::new();
 
     loop {
-        assert!(next_items.is_empty());
+        let mut next_items = SmallVec::new();
 
         // Matcher positions black-box parsed by parser.rs (`parser`)
         let mut bb_items = SmallVec::new();
 
-        // Matcher positions that would be valid if the macro invocation was over now
-        let mut eof_items = EofItems::None;
-
         // Process `cur_items` until either we have finished the input or we need to get some
         // 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(
+        if let Some(result) = parse_tt_inner(
             parser.sess,
+            ms,
             &mut cur_items,
             &mut next_items,
             &mut bb_items,
-            &mut eof_items,
             &parser.token,
         ) {
-            Ok(()) => {}
-            Err((sp, msg)) => return Error(sp, msg),
+            return result;
         }
 
-        // inner parse loop handled all cur_items, so it's empty
+        // `parse_tt_inner` handled all cur_items, so it's empty.
         assert!(cur_items.is_empty());
 
-        // We need to do some post processing after the `inner_parse_loop`.
+        // We need to do some post processing after the `parse_tt_inner`.
         //
         // Error messages here could be improved with links to original rules.
 
-        // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
-        // either the parse is ambiguous (which should never happen) or there is a syntax error.
-        if parser.token == token::Eof {
-            return match eof_items {
-                EofItems::One(mut eof_item) => {
-                    let matches =
-                        eof_item.matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap());
-                    nameize(parser.sess, ms, matches)
-                }
-                EofItems::Multiple => {
-                    Error(parser.token.span, "ambiguity: multiple successful parses".to_string())
-                }
-                EofItems::None => Failure(
-                    Token::new(
-                        token::Eof,
-                        if parser.token.span.is_dummy() {
-                            parser.token.span
-                        } else {
-                            parser.token.span.shrink_to_hi()
-                        },
-                    ),
-                    "missing tokens in macro arguments",
-                ),
-            };
-        }
-        // Performance hack: `eof_items` may share matchers via `Rc` with other things that we want
-        // to modify. Dropping `eof_items` now may drop these refcounts to 1, preventing an
-        // unnecessary implicit clone later in `Rc::make_mut`.
-        drop(eof_items);
-
-        // If there are no possible next positions AND we aren't waiting for the black-box parser,
-        // then there is a syntax error.
-        if bb_items.is_empty() && next_items.is_empty() {
-            return Failure(parser.token.clone(), "no rules expected this token in macro call");
-        }
+        match (next_items.len(), bb_items.len()) {
+            (0, 0) => {
+                // There are no possible next positions AND we aren't waiting for the black-box
+                // parser: syntax error.
+                return Failure(parser.token.clone(), "no rules expected this token in macro call");
+            }
 
-        if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 {
-            // We need to call out to parse some rust nonterminal (black-box) parser. But something
-            // is wrong, because there is not EXACTLY ONE of these.
-            let nts = bb_items
-                .iter()
-                .map(|item| match item.top_elts.get_tt(item.idx) {
-                    TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind),
-                    _ => panic!(),
-                })
-                .collect::<Vec<String>>()
-                .join(" or ");
-
-            return Error(
-                parser.token.span,
-                format!(
-                    "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}",
-                    match next_items.len() {
-                        0 => format!("built-in NTs {}.", nts),
-                        1 => format!("built-in NTs {} or 1 other option.", nts),
-                        n => format!("built-in NTs {} or {} other options.", nts, n),
-                    }
-                ),
-            );
-        }
+            (_, 0) => {
+                // Dump all possible `next_items` into `cur_items` for the next iteration. Then
+                // process the next token.
+                cur_items.extend(next_items.drain(..));
+                parser.to_mut().bump();
+            }
 
-        if !next_items.is_empty() {
-            // Dump all possible `next_items` into `cur_items` for the next iteration. Then process
-            // the next token.
-            cur_items.extend(next_items.drain(..));
-            parser.to_mut().bump();
-        } else {
-            // Finally, we have the case where we need to call the black-box parser to get some
-            // nonterminal.
-            assert_eq!(bb_items.len(), 1);
-
-            let mut item = bb_items.pop().unwrap();
-            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.
-                let nt = match parser.to_mut().parse_nonterminal(kind) {
-                    Err(mut err) => {
-                        err.span_label(
-                            span,
-                            format!("while parsing argument for this `{}` macro fragment", kind),
-                        )
-                        .emit();
-                        return ErrorReported;
-                    }
-                    Ok(nt) => nt,
-                };
-                item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt)));
-                item.idx += 1;
-                item.match_cur += 1;
-            } else {
-                unreachable!()
+            (0, 1) => {
+                // We need to call the black-box parser to get some nonterminal.
+                let mut item = bb_items.pop().unwrap();
+                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.
+                    let nt = match parser.to_mut().parse_nonterminal(kind) {
+                        Err(mut err) => {
+                            err.span_label(
+                                span,
+                                format!("while parsing argument for this `{kind}` macro fragment"),
+                            )
+                            .emit();
+                            return ErrorReported;
+                        }
+                        Ok(nt) => nt,
+                    };
+                    item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt)));
+                    item.idx += 1;
+                    item.match_cur += 1;
+                } else {
+                    unreachable!()
+                }
+                cur_items.push(item);
+            }
+
+            (_, _) => {
+                // We need to call the black-box parser to get some nonterminal, but something is
+                // wrong.
+                return bb_items_ambiguity_error(
+                    macro_name,
+                    next_items,
+                    bb_items,
+                    parser.token.span,
+                );
             }
-            cur_items.push(item);
         }
 
         assert!(!cur_items.is_empty());
     }
 }
+
+fn bb_items_ambiguity_error<'root, 'tt>(
+    macro_name: Ident,
+    next_items: SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
+    bb_items: SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
+    token_span: rustc_span::Span,
+) -> NamedParseResult {
+    let nts = bb_items
+        .iter()
+        .map(|item| match item.top_elts.get_tt(item.idx) {
+            TokenTree::MetaVarDecl(_, bind, Some(kind)) => {
+                format!("{} ('{}')", kind, bind)
+            }
+            _ => panic!(),
+        })
+        .collect::<Vec<String>>()
+        .join(" or ");
+
+    Error(
+        token_span,
+        format!(
+            "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}",
+            match next_items.len() {
+                0 => format!("built-in NTs {}.", nts),
+                1 => format!("built-in NTs {} or 1 other option.", nts),
+                n => format!("built-in NTs {} or {} other options.", nts, n),
+            }
+        ),
+    )
+}
index 62ea3aa76a46c8f26cb8d4a93665600acc159841..c3b1b34aa29b933ba6863d71afeaec3e15623a57 100644 (file)
@@ -580,7 +580,10 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
     use mbe::TokenTree;
     for tt in tts {
         match *tt {
-            TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => (),
+            TokenTree::Token(..)
+            | TokenTree::MetaVar(..)
+            | TokenTree::MetaVarDecl(..)
+            | TokenTree::MetaVarExpr(..) => (),
             TokenTree::Delimited(_, ref del) => {
                 if !check_lhs_no_empty_seq(sess, &del.tts) {
                     return false;
@@ -669,7 +672,10 @@ fn build_recur(sets: &mut FirstSets, tts: &[TokenTree]) -> TokenSet {
             let mut first = TokenSet::empty();
             for tt in tts.iter().rev() {
                 match *tt {
-                    TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
+                    TokenTree::Token(..)
+                    | TokenTree::MetaVar(..)
+                    | TokenTree::MetaVarDecl(..)
+                    | TokenTree::MetaVarExpr(..) => {
                         first.replace_with(tt.clone());
                     }
                     TokenTree::Delimited(span, ref delimited) => {
@@ -731,7 +737,10 @@ fn first(&self, tts: &[mbe::TokenTree]) -> TokenSet {
         for tt in tts.iter() {
             assert!(first.maybe_empty);
             match *tt {
-                TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
+                TokenTree::Token(..)
+                | TokenTree::MetaVar(..)
+                | TokenTree::MetaVarDecl(..)
+                | TokenTree::MetaVarExpr(..) => {
                     first.add_one(tt.clone());
                     return first;
                 }
@@ -907,7 +916,10 @@ fn check_matcher_core(
         // First, update `last` so that it corresponds to the set
         // of NT tokens that might end the sequence `... token`.
         match *token {
-            TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => {
+            TokenTree::Token(..)
+            | TokenTree::MetaVar(..)
+            | TokenTree::MetaVarDecl(..)
+            | TokenTree::MetaVarExpr(..) => {
                 if token_can_be_followed_by_any(token) {
                     // don't need to track tokens that work with any,
                     last.replace_with_irrelevant();
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
new file mode 100644 (file)
index 0000000..6c5a755
--- /dev/null
@@ -0,0 +1,157 @@
+use rustc_ast::token;
+use rustc_ast::tokenstream::{Cursor, TokenStream, TokenTree};
+use rustc_ast::{LitIntType, LitKind};
+use rustc_ast_pretty::pprust;
+use rustc_errors::{Applicability, PResult};
+use rustc_session::parse::ParseSess;
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+/// A meta-variable expression, for expansions based on properties of meta-variables.
+#[derive(Debug, Clone, PartialEq, Encodable, Decodable)]
+crate enum MetaVarExpr {
+    /// The number of repetitions of an identifier, optionally limited to a number
+    /// of outer-most repetition depths. If the depth limit is `None` then the depth is unlimited.
+    Count(Ident, Option<usize>),
+
+    /// Ignore a meta-variable for repetition without expansion.
+    Ignore(Ident),
+
+    /// The index of the repetition at a particular depth, where 0 is the inner-most
+    /// repetition. The `usize` is the depth.
+    Index(usize),
+
+    /// The length of the repetition at a particular depth, where 0 is the inner-most
+    /// repetition. The `usize` is the depth.
+    Length(usize),
+}
+
+impl MetaVarExpr {
+    /// Attempt to parse a meta-variable expression from a token stream.
+    crate fn parse<'sess>(
+        input: &TokenStream,
+        outer_span: Span,
+        sess: &'sess ParseSess,
+    ) -> PResult<'sess, MetaVarExpr> {
+        let mut tts = input.trees();
+        let ident = parse_ident(&mut tts, sess, outer_span)?;
+        let Some(TokenTree::Delimited(_, token::Paren, args)) = tts.next() else {
+            let msg = "meta-variable expression parameter must be wrapped in parentheses";
+            return Err(sess.span_diagnostic.struct_span_err(ident.span, msg));
+        };
+        check_trailing_token(&mut tts, sess)?;
+        let mut iter = args.trees();
+        let rslt = match &*ident.as_str() {
+            "count" => parse_count(&mut iter, sess, ident.span)?,
+            "ignore" => MetaVarExpr::Ignore(parse_ident(&mut iter, sess, ident.span)?),
+            "index" => MetaVarExpr::Index(parse_depth(&mut iter, sess, ident.span)?),
+            "length" => MetaVarExpr::Length(parse_depth(&mut iter, sess, ident.span)?),
+            _ => {
+                let err_msg = "unrecognized meta-variable expression";
+                let mut err = sess.span_diagnostic.struct_span_err(ident.span, err_msg);
+                err.span_suggestion(
+                    ident.span,
+                    "supported expressions are count, ignore, index and length",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+                return Err(err);
+            }
+        };
+        check_trailing_token(&mut iter, sess)?;
+        Ok(rslt)
+    }
+
+    crate fn ident(&self) -> Option<&Ident> {
+        match self {
+            MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(&ident),
+            MetaVarExpr::Index(..) | MetaVarExpr::Length(..) => None,
+        }
+    }
+}
+
+// Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}`
+fn check_trailing_token<'sess>(iter: &mut Cursor, sess: &'sess ParseSess) -> PResult<'sess, ()> {
+    if let Some(tt) = iter.next() {
+        let mut diag = sess.span_diagnostic.struct_span_err(
+            tt.span(),
+            &format!("unexpected token: {}", pprust::tt_to_string(&tt)),
+        );
+        diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens");
+        Err(diag)
+    } else {
+        Ok(())
+    }
+}
+
+/// Parse a meta-variable `count` expression: `count(ident[, depth])`
+fn parse_count<'sess>(
+    iter: &mut Cursor,
+    sess: &'sess ParseSess,
+    span: Span,
+) -> PResult<'sess, MetaVarExpr> {
+    let ident = parse_ident(iter, sess, span)?;
+    let depth = if try_eat_comma(iter) { Some(parse_depth(iter, sess, span)?) } else { None };
+    Ok(MetaVarExpr::Count(ident, depth))
+}
+
+/// Parses the depth used by index(depth) and length(depth).
+fn parse_depth<'sess>(
+    iter: &mut Cursor,
+    sess: &'sess ParseSess,
+    span: Span,
+) -> PResult<'sess, usize> {
+    let Some(tt) = iter.next() else { return Ok(0) };
+    let TokenTree::Token(token::Token {
+        kind: token::TokenKind::Literal(lit), ..
+    }) = tt else {
+        return Err(sess.span_diagnostic.struct_span_err(
+            span,
+            "meta-variable expression depth must be a literal"
+        ));
+    };
+    if let Ok(lit_kind) = LitKind::from_lit_token(lit)
+        && let LitKind::Int(n_u128, LitIntType::Unsuffixed) = lit_kind
+        && let Ok(n_usize) = usize::try_from(n_u128)
+    {
+        Ok(n_usize)
+    }
+    else {
+        let msg = "only unsuffixes integer literals are supported in meta-variable expressions";
+        Err(sess.span_diagnostic.struct_span_err(span, msg))
+    }
+}
+
+/// Parses an generic ident
+fn parse_ident<'sess>(
+    iter: &mut Cursor,
+    sess: &'sess ParseSess,
+    span: Span,
+) -> PResult<'sess, Ident> {
+    let err_fn = |msg| sess.span_diagnostic.struct_span_err(span, msg);
+    if let Some(tt) = iter.next() && let TokenTree::Token(token) = tt {
+        if let Some((elem, false)) = token.ident() {
+            return Ok(elem);
+        }
+        let token_str = pprust::token_to_string(&token);
+        let mut err = err_fn(&format!("expected identifier, found `{}`", &token_str));
+        err.span_suggestion(
+            token.span,
+            &format!("try removing `{}`", &token_str),
+            String::new(),
+            Applicability::MaybeIncorrect,
+        );
+        return Err(err);
+    }
+    Err(err_fn("expected identifier"))
+}
+
+/// Tries to move the iterator forward returning `true` if there is a comma. If not, then the
+/// iterator is not modified and the result is `false`.
+fn try_eat_comma(iter: &mut Cursor) -> bool {
+    if let Some(TokenTree::Token(token::Token { kind: token::Comma, .. })) = iter.look_ahead(0) {
+        let _ = iter.next();
+        return true;
+    }
+    false
+}
index dedc6c618b9a482442828018babc4780bcff0e6e..12c5dac9e0bf47c33366940ae60959f9a13dc4e0 100644 (file)
@@ -1,13 +1,13 @@
 use crate::mbe::macro_parser;
-use crate::mbe::{Delimited, KleeneOp, KleeneToken, SequenceRepetition, TokenTree};
+use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
 
 use rustc_ast::token::{self, Token};
 use rustc_ast::tokenstream;
 use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_feature::Features;
-use rustc_session::parse::ParseSess;
-use rustc_span::symbol::{kw, Ident};
+use rustc_session::parse::{feature_err, ParseSess};
+use rustc_span::symbol::{kw, sym, Ident};
 
 use rustc_span::edition::Edition;
 use rustc_span::{Span, SyntaxContext};
 /// # Parameters
 ///
 /// - `input`: a token stream to read from, the contents of which we are parsing.
-/// - `expect_matchers`: `parse` can be used to parse either the "patterns" or the "body" of a
-///   macro. Both take roughly the same form _except_ that in a pattern, metavars are declared with
-///   their "matcher" type. For example `$var:expr` or `$id:ident`. In this example, `expr` and
-///   `ident` are "matchers". They are not present in the body of a macro rule -- just in the
-///   pattern, so we pass a parameter to indicate whether to expect them or not.
+/// - `parsing_patterns`: `parse` can be used to parse either the "patterns" or the "body" of a
+///   macro. Both take roughly the same form _except_ that:
+///   - In a pattern, metavars are declared with their "matcher" type. For example `$var:expr` or
+///     `$id:ident`. In this example, `expr` and `ident` are "matchers". They are not present in the
+///     body of a macro rule -- just in the pattern.
+///   - Metavariable expressions are only valid in the "body", not the "pattern".
 /// - `sess`: the parsing session. Any errors will be emitted to this session.
 /// - `node_id`: the NodeId of the macro we are parsing.
 /// - `features`: language features so we can do feature gating.
-/// - `edition`: the edition of the crate defining the macro
 ///
 /// # Returns
 ///
 /// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`.
 pub(super) fn parse(
     input: tokenstream::TokenStream,
-    expect_matchers: bool,
+    parsing_patterns: bool,
     sess: &ParseSess,
     node_id: NodeId,
     features: &Features,
@@ -55,9 +55,9 @@ pub(super) fn parse(
     while let Some(tree) = trees.next() {
         // Given the parsed tree, if there is a metavar and we are expecting matchers, actually
         // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
-        let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features, edition);
+        let tree = parse_tree(tree, &mut trees, parsing_patterns, sess, node_id, features, edition);
         match tree {
-            TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
+            TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
                 let span = match trees.next() {
                     Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span })) => {
                         match trees.next() {
@@ -118,6 +118,14 @@ pub(super) fn parse(
     result
 }
 
+/// Asks for the `macro_metavar_expr` feature if it is not already declared
+fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &ParseSess, span: Span) {
+    if !features.macro_metavar_expr {
+        let msg = "meta-variable expressions are unstable";
+        feature_err(&sess, sym::macro_metavar_expr, span, msg).emit();
+    }
+}
+
 /// Takes a `tokenstream::TokenTree` and returns a `self::TokenTree`. Specifically, this takes a
 /// generic `TokenTree`, such as is used in the rest of the compiler, and returns a `TokenTree`
 /// for use in parsing a macro.
@@ -129,14 +137,13 @@ pub(super) fn parse(
 /// - `tree`: the tree we wish to convert.
 /// - `outer_trees`: an iterator over trees. We may need to read more tokens from it in order to finish
 ///   converting `tree`
-/// - `expect_matchers`: same as for `parse` (see above).
+/// - `parsing_patterns`: same as [parse].
 /// - `sess`: the parsing session. Any errors will be emitted to this session.
 /// - `features`: language features so we can do feature gating.
-/// - `edition` - the edition of the crate defining the macro
 fn parse_tree(
     tree: tokenstream::TokenTree,
     outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
-    expect_matchers: bool,
+    parsing_patterns: bool,
     sess: &ParseSess,
     node_id: NodeId,
     features: &Features,
@@ -158,24 +165,57 @@ fn parse_tree(
             }
 
             match next {
-                // `tree` is followed by a delimited set of token trees. This indicates the beginning
-                // of a repetition sequence in the macro (e.g. `$(pat)*`).
-                Some(tokenstream::TokenTree::Delimited(span, delim, tts)) => {
-                    // Must have `(` not `{` or `[`
-                    if delim != token::Paren {
-                        let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
-                        let msg = format!("expected `(`, found `{}`", tok);
-                        sess.span_diagnostic.span_err(span.entire(), &msg);
+                // `tree` is followed by a delimited set of token trees.
+                Some(tokenstream::TokenTree::Delimited(delim_span, delim, tts)) => {
+                    if parsing_patterns {
+                        if delim != token::Paren {
+                            span_dollar_dollar_or_metavar_in_the_lhs_err(
+                                sess,
+                                &Token { kind: token::OpenDelim(delim), span: delim_span.entire() },
+                            );
+                        }
+                    } else {
+                        match delim {
+                            token::Brace => {
+                                // The delimiter is `{`.  This indicates the beginning
+                                // of a meta-variable expression (e.g. `${count(ident)}`).
+                                // Try to parse the meta-variable expression.
+                                match MetaVarExpr::parse(&tts, delim_span.entire(), sess) {
+                                    Err(mut err) => {
+                                        err.emit();
+                                        // Returns early the same read `$` to avoid spanning
+                                        // unrelated diagnostics that could be performed afterwards
+                                        return TokenTree::token(token::Dollar, span);
+                                    }
+                                    Ok(elem) => {
+                                        maybe_emit_macro_metavar_expr_feature(
+                                            features,
+                                            sess,
+                                            delim_span.entire(),
+                                        );
+                                        return TokenTree::MetaVarExpr(delim_span, elem);
+                                    }
+                                }
+                            }
+                            token::Paren => {}
+                            _ => {
+                                let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
+                                let msg = format!("expected `(` or `{{`, found `{}`", tok);
+                                sess.span_diagnostic.span_err(delim_span.entire(), &msg);
+                            }
+                        }
                     }
-                    // Parse the contents of the sequence itself
-                    let sequence = parse(tts, expect_matchers, sess, node_id, features, edition);
+                    // If we didn't find a metavar expression above, then we must have a
+                    // repetition sequence in the macro (e.g. `$(pat)*`).  Parse the
+                    // contents of the sequence itself
+                    let sequence = parse(tts, parsing_patterns, sess, node_id, features, edition);
                     // Get the Kleene operator and optional separator
                     let (separator, kleene) =
-                        parse_sep_and_kleene_op(&mut trees, span.entire(), sess);
+                        parse_sep_and_kleene_op(&mut trees, delim_span.entire(), sess);
                     // Count the number of captured "names" (i.e., named metavars)
                     let name_captures = macro_parser::count_names(&sequence);
                     TokenTree::Sequence(
-                        span,
+                        delim_span,
                         Lrc::new(SequenceRepetition {
                             tts: sequence,
                             separator,
@@ -197,7 +237,20 @@ fn parse_tree(
                     }
                 }
 
-                // `tree` is followed by a random token. This is an error.
+                // `tree` is followed by another `$`. This is an escaped `$`.
+                Some(tokenstream::TokenTree::Token(Token { kind: token::Dollar, span })) => {
+                    if parsing_patterns {
+                        span_dollar_dollar_or_metavar_in_the_lhs_err(
+                            sess,
+                            &Token { kind: token::Dollar, span },
+                        );
+                    } else {
+                        maybe_emit_macro_metavar_expr_feature(features, sess, span);
+                    }
+                    TokenTree::token(token::Dollar, span)
+                }
+
+                // `tree` is followed by some other token. This is an error.
                 Some(tokenstream::TokenTree::Token(token)) => {
                     let msg = format!(
                         "expected identifier, found `{}`",
@@ -221,7 +274,7 @@ fn parse_tree(
             span,
             Lrc::new(Delimited {
                 delim,
-                tts: parse(tts, expect_matchers, sess, node_id, features, edition),
+                tts: parse(tts, parsing_patterns, sess, node_id, features, edition),
             }),
         ),
     }
@@ -309,3 +362,15 @@ fn parse_sep_and_kleene_op(
     // Return a dummy
     (None, KleeneToken::new(KleeneOp::ZeroOrMore, span))
 }
+
+// `$$` or a meta-variable is the lhs of a macro but shouldn't.
+//
+// For example, `macro_rules! foo { ( ${length()} ) => {} }`
+fn span_dollar_dollar_or_metavar_in_the_lhs_err<'sess>(sess: &'sess ParseSess, token: &Token) {
+    sess.span_diagnostic
+        .span_err(token.span, &format!("unexpected token: {}", pprust::token_to_string(token)));
+    sess.span_diagnostic.span_note_without_error(
+        token.span,
+        "`$$` and meta-variable expressions are not allowed inside macro parameter definitions",
+    );
+}
index 760dea77f9c2b1ecc9f2c018342dffadab2bb2e6..b8d8394754134ca6f63417e0d35229ed039da1ff 100644 (file)
@@ -255,6 +255,11 @@ pub(super) fn transcribe<'a>(
                 }
             }
 
+            // Replace meta-variable expressions with the result of their expansion.
+            mbe::TokenTree::MetaVarExpr(sp, expr) => {
+                transcribe_metavar_expr(cx, expr, interp, &repeats, &mut result, &sp)?;
+            }
+
             // If we are entering a new delimiter, we push its contents to the `stack` to be
             // processed, and we push all of the currently produced results to the `result_stack`.
             // We will produce all of the results of the inside of the `Delimited` and then we will
@@ -391,6 +396,28 @@ fn lockstep_iter_size(
                 _ => LockstepIterSize::Unconstrained,
             }
         }
+        TokenTree::MetaVarExpr(_, ref expr) => {
+            let default_rslt = LockstepIterSize::Unconstrained;
+            let Some(ident) = expr.ident() else { return default_rslt; };
+            let name = MacroRulesNormalizedIdent::new(ident.clone());
+            match lookup_cur_matched(name, interpolations, repeats) {
+                Some(MatchedSeq(ref ads)) => {
+                    default_rslt.with(LockstepIterSize::Constraint(ads.len(), name))
+                }
+                _ => default_rslt,
+            }
+        }
         TokenTree::Token(..) => LockstepIterSize::Unconstrained,
     }
 }
+
+fn transcribe_metavar_expr<'a>(
+    _cx: &ExtCtxt<'a>,
+    _expr: mbe::MetaVarExpr,
+    _interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
+    _repeats: &[(usize, usize)],
+    _result: &mut Vec<TreeAndSpacing>,
+    _sp: &DelimSpan,
+) -> PResult<'a, ()> {
+    Ok(())
+}
index d43f926d0a56a458fc3dbd97fe27ef867736ba31..fc2ac75d609678d9587289261bf6b3fa329b9e9b 100644 (file)
@@ -86,6 +86,10 @@ macro_rules! declare_features {
     (accepted, conservative_impl_trait, "1.26.0", Some(34511), None),
     /// Allows calling constructor functions in `const fn`.
     (accepted, const_constructor, "1.40.0", Some(61456), None),
+    /// Allows using and casting function pointers in a `const fn`.
+    (accepted, const_fn_fn_ptr_basics, "1.61.0", Some(57563), None),
+    /// Allows trait bounds in `const fn`.
+    (accepted, const_fn_trait_bound, "1.61.0", Some(93706), None),
     /// Allows calling `transmute` in const fn
     (accepted, const_fn_transmute, "1.56.0", Some(53605), None),
     /// Allows accessing fields of unions inside `const` functions.
@@ -96,6 +100,8 @@ macro_rules! declare_features {
     (accepted, const_generics_defaults, "1.59.0", Some(44580), None),
     /// Allows the use of `if` and `match` in constants.
     (accepted, const_if_match, "1.46.0", Some(49146), None),
+    /// Allows argument and return position `impl Trait` in a `const fn`.
+    (accepted, const_impl_trait, "1.61.0", Some(77463), None),
     /// Allows indexing into constant arrays.
     (accepted, const_indexing, "1.26.0", Some(29947), None),
     /// Allows let bindings, assignments and destructuring in `const` functions and constants.
index 1f7dc769512bbea2d3581a352b75a98dea5eb305..ccd296c3da12777ddff835188e6eda5d9f9b5d1f 100644 (file)
@@ -169,6 +169,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, staged_api, "1.0.0", None, None),
     /// Added for testing E0705; perma-unstable.
     (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
+    /// Added for testing unstable lints; perma-unstable.
+    (active, test_unstable_lint, "1.60.0", None, None),
     /// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions.
     /// Marked `incomplete` since perma-unstable and unsound.
     (incomplete, unsafe_pin_internals, "1.60.0", None, None),
@@ -338,14 +340,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, const_extern_fn, "1.40.0", Some(64926), None),
     /// Allows basic arithmetic on floating point types in a `const fn`.
     (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None),
-    /// Allows using and casting function pointers in a `const fn`.
-    (active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None),
-    /// Allows trait bounds in `const fn`.
-    (active, const_fn_trait_bound, "1.53.0", Some(93706), None),
     /// Allows `for _ in _` loops in const contexts.
     (active, const_for, "1.56.0", Some(87575), None),
-    /// Allows argument and return position `impl Trait` in a `const fn`.
-    (active, const_impl_trait, "1.48.0", Some(77463), None),
     /// Allows using `&mut` in constant functions.
     (active, const_mut_refs, "1.41.0", Some(57349), None),
     /// Be more precise when looking for live drops in a const context.
@@ -368,6 +364,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, default_alloc_error_handler, "1.48.0", Some(66741), None),
     /// Allows default type parameters to influence type inference.
     (active, default_type_parameter_fallback, "1.3.0", Some(27336), None),
+    /// Allows having using `suggestion` in the `#[deprecated]` attribute.
+    (active, deprecated_suggestion, "1.61.0", Some(94785), None),
     /// Allows `#[derive(Default)]` and `#[default]` on enums.
     (active, derive_default_enum, "1.56.0", Some(86985), None),
     /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
@@ -432,6 +430,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, link_cfg, "1.14.0", Some(37406), None),
     /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
     (active, lint_reasons, "1.31.0", Some(54503), None),
+    /// Give access to additional metadata about declarative macro meta-variables.
+    (active, macro_metavar_expr, "1.61.0", Some(83527), None),
     /// Allows `#[marker]` on certain traits allowing overlapping implementations.
     (active, marker_trait_attr, "1.30.0", Some(29864), None),
     /// A minimal, sound subset of specialization intended to be used by the
index 4b9cf784495fec49cb068149b15aa3c1843bf1d3..9c7b8f803249683bceef3387cb577b6f382038c4 100644 (file)
@@ -461,7 +461,7 @@ pub struct BuiltinAttribute {
     // DuplicatesOk since it has its own validation
     ungated!(
         rustc_deprecated, Normal,
-        template!(List: r#"since = "version", reason = "...""#), DuplicatesOk // See E0550
+        template!(List: r#"since = "version", note = "...""#), DuplicatesOk // See E0550
     ),
     // DuplicatesOk since it has its own validation
     ungated!(
@@ -606,17 +606,17 @@ pub struct BuiltinAttribute {
     rustc_attr!(
         rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
         "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
-        niche optimizations in libcore and will never be stable",
+        niche optimizations in libcore and libstd and will never be stable",
     ),
     rustc_attr!(
         rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
         "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
-        niche optimizations in libcore and will never be stable",
+        niche optimizations in libcore and libstd and will never be stable",
     ),
     rustc_attr!(
         rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
         "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \
-        niche optimizations in libcore and will never be stable",
+        niche optimizations in libcore and libstd and will never be stable",
     ),
 
     // ==========================================================================
index dee391b9cce215cfe9d194fc1048936ce54555b7..f23e3ce1901319b91788a93d76eda14e7f9c8664 100644 (file)
@@ -13,6 +13,7 @@
 /// the code base.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[derive(Encodable, Decodable)]
+#[rustc_pass_by_value]
 pub struct HirId {
     pub owner: LocalDefId,
     pub local_id: ItemLocalId,
index ba3eeb91fe95f8b88b3e94b474807f6ccebffa6c..d56230e1dc57d46a76c9a03db4314f1cc472feb4 100644 (file)
@@ -9,6 +9,7 @@
 #![feature(once_cell)]
 #![feature(min_specialization)]
 #![feature(never_type)]
+#![feature(rustc_attrs)]
 #![recursion_limit = "256"]
 
 #[macro_use]
index 12bde02949452ee607d7b2a8d60ffa8b1a9e41d8..d7e5c2b60566e636dd3992d4ac215dc38f442d17 100644 (file)
@@ -654,15 +654,19 @@ fn intersect(&mut self, _other: &ChunkedBitSet<T>) -> bool {
 
 impl<T: Idx> BitRelations<HybridBitSet<T>> for ChunkedBitSet<T> {
     fn union(&mut self, other: &HybridBitSet<T>) -> bool {
-        // FIXME: this is slow if `other` is dense, and could easily be
-        // improved, but it hasn't been a problem in practice so far.
+        // FIXME: This is slow if `other` is dense, but it hasn't been a problem
+        // in practice so far.
+        // If a a faster implementation of this operation is required, consider
+        // reopening https://github.com/rust-lang/rust/pull/94625
         assert_eq!(self.domain_size, other.domain_size());
         sequential_update(|elem| self.insert(elem), other.iter())
     }
 
     fn subtract(&mut self, other: &HybridBitSet<T>) -> bool {
-        // FIXME: this is slow if `other` is dense, and could easily be
-        // improved, but it hasn't been a problem in practice so far.
+        // FIXME: This is slow if `other` is dense, but it hasn't been a problem
+        // in practice so far.
+        // If a a faster implementation of this operation is required, consider
+        // reopening https://github.com/rust-lang/rust/pull/94625
         assert_eq!(self.domain_size, other.domain_size());
         sequential_update(|elem| self.remove(elem), other.iter())
     }
index 187c67df3eb31cd552c31f3066f03ab13beb717a..082eb1bf11101456b1896ee85ed62a57158481d0 100644 (file)
@@ -86,7 +86,7 @@ pub fn sub_free_regions(
 
     /// Check whether `r_a <= r_b` is found in the relation.
     fn check_relation(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
-        r_a == r_b || self.relation.contains(&r_a, &r_b)
+        r_a == r_b || self.relation.contains(r_a, r_b)
     }
 
     /// True for free regions other than `'static`.
@@ -119,9 +119,9 @@ pub fn lub_free_regions(
         let result = if r_a == r_b {
             r_a
         } else {
-            match self.relation.postdom_upper_bound(&r_a, &r_b) {
+            match self.relation.postdom_upper_bound(r_a, r_b) {
                 None => tcx.lifetimes.re_static,
-                Some(r) => *r,
+                Some(r) => r,
             }
         };
         debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
@@ -132,6 +132,6 @@ pub fn lub_free_regions(
 impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
     type Lifted = FreeRegionMap<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
-        self.relation.maybe_map(|&fr| tcx.lift(fr)).map(|relation| FreeRegionMap { relation })
+        self.relation.maybe_map(|fr| tcx.lift(fr)).map(|relation| FreeRegionMap { relation })
     }
 }
index 381097344ec68eec5e000f22196e5b257d862cfd..e98f33ea86eef899769407146fdff37204382b7e 100644 (file)
@@ -1,3 +1,5 @@
+//! Greatest lower bound. See [`lattice`].
+
 use super::combine::CombineFields;
 use super::lattice::{self, LatticeDir};
 use super::InferCtxt;
index 652f5abab151f6659b6bf277ba8bd6e7f51cb358..73cc411e533d346545c45beba9ac9c2a7f4e1d40 100644 (file)
@@ -58,14 +58,11 @@ pub fn higher_ranked_sub<T>(
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
-    /// Replaces all regions (resp. types) bound by `binder` with placeholder
-    /// regions (resp. types) and return a map indicating which bound-region
-    /// placeholder region. This is the first step of checking subtyping
-    /// when higher-ranked things are involved.
+    /// Replaces all bound variables (lifetimes, types, and constants) bound by
+    /// `binder` with placeholder variables.
     ///
-    /// **Important:** You have to be careful to not leak these placeholders,
-    /// for more information about how placeholders and HRTBs work, see
-    /// the [rustc dev guide].
+    /// This is the first step of checking subtyping when higher-ranked things are involved.
+    /// For more details visit the relevant sections of the [rustc dev guide].
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
     pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
index c47d476963772e2adda260bca51b6a4f3e1f1c97..32affd6a14e1cf0038441feb1fffc9eccc9cdc1c 100644 (file)
@@ -1,23 +1,21 @@
-//! # Lattice Variables
+//! # Lattice variables
 //!
-//! This file contains generic code for operating on inference variables
-//! that are characterized by an upper- and lower-bound. The logic and
-//! reasoning is explained in detail in the large comment in `infer.rs`.
+//! Generic code for operating on [lattices] of inference variables
+//! that are characterized by an upper- and lower-bound.
 //!
-//! The code in here is defined quite generically so that it can be
+//! The code is defined quite generically so that it can be
 //! applied both to type variables, which represent types being inferred,
 //! and fn variables, which represent function types being inferred.
-//! It may eventually be applied to their types as well, who knows.
+//! (It may eventually be applied to their types as well.)
 //! In some cases, the functions are also generic with respect to the
 //! operation on the lattice (GLB vs LUB).
 //!
-//! Although all the functions are generic, we generally write the
-//! comments in a way that is specific to type variables and the LUB
-//! operation. It's just easier that way.
+//! ## Note
 //!
-//! In general all of the functions are defined parametrically
-//! over a `LatticeValue`, which is a value defined with respect to
-//! a lattice.
+//! Although all the functions are generic, for simplicity, comments in the source code
+//! generally refer to type variables and the LUB operation.
+//!
+//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
 
 use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use super::InferCtxt;
 use rustc_middle::ty::TyVar;
 use rustc_middle::ty::{self, Ty};
 
+/// Trait for returning data about a lattice, and for abstracting
+/// over the "direction" of the lattice operation (LUB/GLB).
+///
+/// GLB moves "down" the lattice (to smaller values); LUB moves
+/// "up" the lattice (to bigger values).
 pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
     fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
 
@@ -41,6 +44,7 @@ pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
     fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
 }
 
+/// Relates two types using a given lattice.
 pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
     this: &mut L,
     a: Ty<'tcx>,
index 57cbe2c54f7aec978ddbee9e837b0e54cae8eda9..bc85a4ac609a748bda607b6542d550f43dc899e0 100644 (file)
@@ -1,3 +1,5 @@
+//! Least upper bound. See [`lattice`].
+
 use super::combine::CombineFields;
 use super::lattice::{self, LatticeDir};
 use super::InferCtxt;
index 72b8d8bb297a6b8a486814726ddf34851b73ac31..b6b73ba45391ea1d3d19e3b999bdbf634b8855e6 100644 (file)
@@ -2861,8 +2861,8 @@ fn structurally_same_type_impl<'tcx>(
 
                 let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> {
                     debug!("compare_layouts({:?}, {:?})", a, b);
-                    let a_layout = &cx.layout_of(a)?.layout.abi;
-                    let b_layout = &cx.layout_of(b)?.layout.abi;
+                    let a_layout = &cx.layout_of(a)?.layout.abi();
+                    let b_layout = &cx.layout_of(b)?.layout.abi();
                     debug!(
                         "comparing layouts: {:?} == {:?} = {}",
                         a_layout,
index f46f74fa45fb044c7775d7e0ae37dfc490c9f104..7b018e7f75fa7c3c947ad304983b95add0385891 100644 (file)
@@ -17,7 +17,7 @@
     builtin::{self, FORBIDDEN_LINT_GROUPS},
     Level, Lint, LintExpectationId, LintId,
 };
-use rustc_session::parse::feature_err;
+use rustc_session::parse::{add_feature_diagnostics, feature_err};
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP};
@@ -93,10 +93,19 @@ pub(crate) fn lint_store(&self) -> &LintStore {
         self.store
     }
 
+    fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
+        &self.sets.list[self.cur].specs
+    }
+
+    fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource> {
+        &mut self.sets.list[self.cur].specs
+    }
+
     fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
-        let mut specs = FxHashMap::default();
         self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
 
+        self.cur =
+            self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: COMMAND_LINE });
         for &(ref lint_name, level) in &sess.opts.lint_opts {
             store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools);
             let orig_level = level;
@@ -108,30 +117,24 @@ fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
             };
             for id in ids {
                 // ForceWarn and Forbid cannot be overriden
-                if let Some((Level::ForceWarn | Level::Forbid, _)) = specs.get(&id) {
+                if let Some((Level::ForceWarn | Level::Forbid, _)) = self.current_specs().get(&id) {
                     continue;
                 }
 
-                self.check_gated_lint(id, DUMMY_SP);
-                let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
-                specs.insert(id, (level, src));
+                if self.check_gated_lint(id, DUMMY_SP) {
+                    let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
+                    self.current_specs_mut().insert(id, (level, src));
+                }
             }
         }
-
-        self.cur = self.sets.list.push(LintSet { specs, parent: COMMAND_LINE });
     }
 
     /// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
     /// (e.g. if a forbid was already inserted on the same scope), then emits a
     /// diagnostic with no change to `specs`.
-    fn insert_spec(
-        &mut self,
-        specs: &mut FxHashMap<LintId, LevelAndSource>,
-        id: LintId,
-        (level, src): LevelAndSource,
-    ) {
+    fn insert_spec(&mut self, id: LintId, (level, src): LevelAndSource) {
         let (old_level, old_src) =
-            self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess);
+            self.sets.get_lint_level(id.lint, self.cur, Some(self.current_specs()), &self.sess);
         // Setting to a non-forbid level is an error if the lint previously had
         // a forbid level. Note that this is not necessarily true even with a
         // `#[forbid(..)]` attribute present, as that is overriden by `--cap-lints`.
@@ -154,7 +157,10 @@ fn insert_spec(
                 };
                 debug!(
                     "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
-                    fcw_warning, specs, old_src, id_name
+                    fcw_warning,
+                    self.current_specs(),
+                    old_src,
+                    id_name
                 );
 
                 let decorate_diag = |diag: &mut Diagnostic| {
@@ -213,9 +219,9 @@ fn insert_spec(
             }
         }
         if let Level::ForceWarn = old_level {
-            specs.insert(id, (old_level, old_src));
+            self.current_specs_mut().insert(id, (old_level, old_src));
         } else {
-            specs.insert(id, (level, src));
+            self.current_specs_mut().insert(id, (level, src));
         }
     }
 
@@ -239,7 +245,9 @@ pub(crate) fn push(
         is_crate_node: bool,
         source_hir_id: Option<HirId>,
     ) -> BuilderPush {
-        let mut specs = FxHashMap::default();
+        let prev = self.cur;
+        self.cur = self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev });
+
         let sess = self.sess;
         let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
         for (attr_index, attr) in attrs.iter().enumerate() {
@@ -258,7 +266,7 @@ pub(crate) fn push(
             };
 
             if metas.is_empty() {
-                // FIXME (#55112): issue unused-attributes lint for `#[level()]`
+                // This emits the unused_attributes lint for `#[level()]`
                 continue;
             }
 
@@ -271,8 +279,6 @@ pub(crate) fn push(
                     ast::MetaItemKind::Word => {} // actual lint names handled later
                     ast::MetaItemKind::NameValue(ref name_value) => {
                         if item.path == sym::reason {
-                            // FIXME (#55112): issue unused-attributes lint if we thereby
-                            // don't have any lint names (`#[level(reason = "foo")]`)
                             if let ast::LitKind::Str(rationale, _) = name_value.kind {
                                 if !self.sess.features_untracked().lint_reasons {
                                     feature_err(
@@ -350,8 +356,9 @@ pub(crate) fn push(
                             reason,
                         );
                         for &id in *ids {
-                            self.check_gated_lint(id, attr.span);
-                            self.insert_spec(&mut specs, id, (level, src));
+                            if self.check_gated_lint(id, attr.span) {
+                                self.insert_spec(id, (level, src));
+                            }
                         }
                         if let Level::Expect(expect_id) = level {
                             self.lint_expectations
@@ -370,7 +377,7 @@ pub(crate) fn push(
                                     reason,
                                 );
                                 for id in ids {
-                                    self.insert_spec(&mut specs, *id, (level, src));
+                                    self.insert_spec(*id, (level, src));
                                 }
                                 if let Level::Expect(expect_id) = level {
                                     self.lint_expectations
@@ -379,8 +386,12 @@ pub(crate) fn push(
                             }
                             Err((Some(ids), ref new_lint_name)) => {
                                 let lint = builtin::RENAMED_AND_REMOVED_LINTS;
-                                let (lvl, src) =
-                                    self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
+                                let (lvl, src) = self.sets.get_lint_level(
+                                    lint,
+                                    self.cur,
+                                    Some(self.current_specs()),
+                                    &sess,
+                                );
                                 struct_lint_level(
                                     self.sess,
                                     lint,
@@ -410,7 +421,7 @@ pub(crate) fn push(
                                     reason,
                                 );
                                 for id in ids {
-                                    self.insert_spec(&mut specs, *id, (level, src));
+                                    self.insert_spec(*id, (level, src));
                                 }
                                 if let Level::Expect(expect_id) = level {
                                     self.lint_expectations
@@ -450,8 +461,12 @@ pub(crate) fn push(
 
                     CheckLintNameResult::Warning(msg, renamed) => {
                         let lint = builtin::RENAMED_AND_REMOVED_LINTS;
-                        let (renamed_lint_level, src) =
-                            self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
+                        let (renamed_lint_level, src) = self.sets.get_lint_level(
+                            lint,
+                            self.cur,
+                            Some(self.current_specs()),
+                            &sess,
+                        );
                         struct_lint_level(
                             self.sess,
                             lint,
@@ -474,8 +489,12 @@ pub(crate) fn push(
                     }
                     CheckLintNameResult::NoLint(suggestion) => {
                         let lint = builtin::UNKNOWN_LINTS;
-                        let (level, src) =
-                            self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+                        let (level, src) = self.sets.get_lint_level(
+                            lint,
+                            self.cur,
+                            Some(self.current_specs()),
+                            self.sess,
+                        );
                         struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| {
                             let name = if let Some(tool_ident) = tool_ident {
                                 format!("{}::{}", tool_ident.name, name)
@@ -506,8 +525,9 @@ pub(crate) fn push(
                     {
                         let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason);
                         for &id in ids {
-                            self.check_gated_lint(id, attr.span);
-                            self.insert_spec(&mut specs, id, (level, src));
+                            if self.check_gated_lint(id, attr.span) {
+                                self.insert_spec(id, (level, src));
+                            }
                         }
                         if let Level::Expect(expect_id) = level {
                             self.lint_expectations
@@ -521,7 +541,7 @@ pub(crate) fn push(
         }
 
         if !is_crate_node {
-            for (id, &(level, ref src)) in specs.iter() {
+            for (id, &(level, ref src)) in self.current_specs().iter() {
                 if !id.lint.crate_level_only {
                     continue;
                 }
@@ -532,7 +552,7 @@ pub(crate) fn push(
 
                 let lint = builtin::UNUSED_ATTRIBUTES;
                 let (lint_level, lint_src) =
-                    self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+                    self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), self.sess);
                 struct_lint_level(
                     self.sess,
                     lint,
@@ -553,9 +573,9 @@ pub(crate) fn push(
             }
         }
 
-        let prev = self.cur;
-        if !specs.is_empty() {
-            self.cur = self.sets.list.push(LintSet { specs, parent: prev });
+        if self.current_specs().is_empty() {
+            self.sets.list.pop();
+            self.cur = prev;
         }
 
         BuilderPush { prev, changed: prev != self.cur }
@@ -576,18 +596,24 @@ fn create_stable_id(
     }
 
     /// Checks if the lint is gated on a feature that is not enabled.
-    fn check_gated_lint(&self, lint_id: LintId, span: Span) {
+    ///
+    /// Returns `true` if the lint's feature is enabled.
+    fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool {
         if let Some(feature) = lint_id.lint.feature_gate {
             if !self.sess.features_untracked().enabled(feature) {
-                feature_err(
-                    &self.sess.parse_sess,
-                    feature,
-                    span,
-                    &format!("the `{}` lint is unstable", lint_id.lint.name_lower()),
-                )
-                .emit();
+                let lint = builtin::UNKNOWN_LINTS;
+                let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
+                struct_lint_level(self.sess, lint, level, src, Some(span.into()), |lint_db| {
+                    let mut db =
+                        lint_db.build(&format!("unknown lint: `{}`", lint_id.lint.name_lower()));
+                    db.note(&format!("the `{}` lint is unstable", lint_id.lint.name_lower(),));
+                    add_feature_diagnostics(&mut db, &self.sess.parse_sess, feature);
+                    db.emit();
+                });
+                return false;
             }
         }
+        true
     }
 
     /// Called after `push` when the scope of a set of attributes are exited.
index c0bf64387ff376ab77bad579e4802c70bcc7779e..d4dac640cc7e189d71de027375b15d318f2c8516 100644 (file)
@@ -795,7 +795,9 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
         let field_ty_abi = &cx.layout_of(field_ty).unwrap().abi;
         if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
             match (field_ty_scalar.valid_range.start, field_ty_scalar.valid_range.end) {
-                (0, _) => unreachable!("Non-null optimisation extended to a non-zero value."),
+                (0, x) if x == field_ty_scalar.value.size(&cx.tcx).unsigned_int_max() - 1 => {
+                    return Some(get_nullable_type(cx, field_ty).unwrap());
+                }
                 (1, _) => {
                     return Some(get_nullable_type(cx, field_ty).unwrap());
                 }
@@ -1349,7 +1351,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
             let (largest, slargest, largest_index) = iter::zip(enum_definition.variants, variants)
                 .map(|(variant, variant_layout)| {
                     // Subtract the size of the enum tag.
-                    let bytes = variant_layout.size.bytes().saturating_sub(tag_size);
+                    let bytes = variant_layout.size().bytes().saturating_sub(tag_size);
 
                     debug!("- variant `{}` is {} bytes large", variant.ident, bytes);
                     bytes
index 04a339f3c95a608f81fa3b53b8d75e17e35a8049..8539e8868e2c7aa0df9ab3388bfa6d230ab00c97 100644 (file)
         SUSPICIOUS_AUTO_TRAIT_IMPLS,
         UNEXPECTED_CFGS,
         DEPRECATED_WHERE_CLAUSE_LOCATION,
+        TEST_UNSTABLE_LINT,
     ]
 }
 
     ///     //                  ^^^^^^^^
     ///     // This call to try_into matches both Foo:try_into and TryInto::try_into as
     ///     // `TryInto` has been added to the Rust prelude in 2021 edition.
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     ///
     Warn,
     "deprecated where clause location"
 }
+
+declare_lint! {
+    /// The `test_unstable_lint` lint tests unstable lints and is perma-unstable.
+    ///
+    /// ### Example
+    ///
+    /// ```
+    /// #![allow(test_unstable_lint)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In order to test the behavior of unstable lints, a permanently-unstable
+    /// lint is required. This lint can be used to trigger warnings and errors
+    /// from the compiler related to unstable lints.
+    pub TEST_UNSTABLE_LINT,
+    Deny,
+    "this unstable lint is only for testing",
+    @feature_gate = sym::test_unstable_lint;
+}
index ef6c9ef6627d5beb3c2af7d11aa75ac6b767a4d6..51739df067f9da03718f914fb92a291132a03fbd 100644 (file)
@@ -9,6 +9,7 @@
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/COFFImportFile.h"
 #include "llvm/Object/ObjectFile.h"
+#include "llvm/Pass.h"
 #include "llvm/Bitcode/BitcodeWriterPass.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/ADT/Optional.h"
index f5968a8a7ea73ce15c9b7f1ffb0c1a42c0b98019..c8b31cd0c4d784e2a04ac612f53deeb39202ee59 100644 (file)
@@ -197,6 +197,7 @@ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
             #(#attrs)*
             #[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)]
             #[rustc_layout_scalar_valid_range_end(#max)]
+            #[rustc_pass_by_value]
             #vis struct #name {
                 private: u32,
             }
index 7cdcb6a4ab302604c30cb4fb95c1f1937cc56610..f4bc28f4da19914ee396fcb465356c030160e3da 100644 (file)
@@ -392,7 +392,7 @@ fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize {
                     .layout;
                 // In both stdcall and fastcall, we always round up the argument size to the
                 // nearest multiple of 4 bytes.
-                (layout.size.bytes_usize() + 3) & !3
+                (layout.size().bytes_usize() + 3) & !3
             })
             .sum()
     }
index c4e6734aa0fa71efa23fc2c361a991e462889b35..825dc79129d267a2eb7342432c112106c8d85360 100644 (file)
@@ -6,7 +6,7 @@
 macro_rules! arena_types {
     ($macro:path) => (
         $macro!([
-            [] layout: rustc_target::abi::Layout,
+            [] layout: rustc_target::abi::LayoutS<'tcx>,
             [] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>,
             // AdtDef are interned and compared by address
             [decode] adt_def: rustc_middle::ty::AdtDef,
index f977b0fffebb665cdf53258d9914e60abd15b297..a575f27ad3860206028497b52a38ec2ea2928d50 100644 (file)
@@ -44,6 +44,7 @@
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(trusted_len)]
+#![feature(type_alias_impl_trait)]
 #![feature(crate_visibility_modifier)]
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
index 6124d1407026693a5755cb855478b526e11fd0ae..12fa5a13de885cdcd7037907891cce8def8271c9 100644 (file)
@@ -7,7 +7,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
 
 use crate::ty::TyCtxt;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir as hir;
 use rustc_hir::Node;
@@ -214,14 +214,14 @@ pub struct ScopeTree {
     /// conditional expression or repeating block. (Note that the
     /// enclosing scope ID for the block associated with a closure is
     /// the closure itself.)
-    pub parent_map: FxHashMap<Scope, (Scope, ScopeDepth)>,
+    pub parent_map: FxIndexMap<Scope, (Scope, ScopeDepth)>,
 
     /// Maps from a variable or binding ID to the block in which that
     /// variable is declared.
-    var_map: FxHashMap<hir::ItemLocalId, Scope>,
+    var_map: FxIndexMap<hir::ItemLocalId, Scope>,
 
     /// Maps from a `NodeId` to the associated destruction scope (if any).
-    destruction_scopes: FxHashMap<hir::ItemLocalId, Scope>,
+    destruction_scopes: FxIndexMap<hir::ItemLocalId, Scope>,
 
     /// `rvalue_scopes` includes entries for those expressions whose
     /// cleanup scope is larger than the default. The map goes from the
index 640d3a5a02b0f0ae7e1efc759a9f13a9997096a5..2336d460407e1df12faa2ca94be2241d000f6d54 100644 (file)
@@ -46,7 +46,7 @@ impl CounterValueReference {
 
     /// Returns explicitly-requested zero-based version of the counter id, used
     /// during codegen. LLVM expects zero-based indexes.
-    pub fn zero_based_index(&self) -> u32 {
+    pub fn zero_based_index(self) -> u32 {
         let one_based_index = self.as_u32();
         debug_assert!(one_based_index > 0);
         one_based_index - 1
index 5de119f956282b51448f6bda0135825b1517c9b1..17ff52cefcfa8f9ee4533de1822f075a3a422014 100644 (file)
@@ -2,11 +2,13 @@
 
 use std::borrow::Cow;
 use std::convert::{TryFrom, TryInto};
+use std::fmt;
 use std::iter;
 use std::ops::{Deref, Range};
 use std::ptr;
 
 use rustc_ast::Mutability;
+use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::{Align, HasDataLayout, Size};
@@ -47,6 +49,34 @@ pub struct Allocation<Tag = AllocId, Extra = ()> {
     pub extra: Extra,
 }
 
+/// Interned types generally have an `Outer` type and an `Inner` type, where
+/// `Outer` is a newtype around `Interned<Inner>`, and all the operations are
+/// done on `Outer`, because all occurrences are interned. E.g. `Ty` is an
+/// outer type and `TyS` is its inner type.
+///
+/// Here things are different because only const allocations are interned. This
+/// means that both the inner type (`Allocation`) and the outer type
+/// (`ConstAllocation`) are used quite a bit.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct ConstAllocation<'tcx, Tag = AllocId, Extra = ()>(
+    pub Interned<'tcx, Allocation<Tag, Extra>>,
+);
+
+impl<'tcx> fmt::Debug for ConstAllocation<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // This matches how `Allocation` is printed. We print it like this to
+        // avoid having to update expected output in a lot of tests.
+        write!(f, "{:?}", self.inner())
+    }
+}
+
+impl<'tcx, Tag, Extra> ConstAllocation<'tcx, Tag, Extra> {
+    pub fn inner(self) -> &'tcx Allocation<Tag, Extra> {
+        self.0.0
+    }
+}
+
 /// We have our own error type that does not know about the `AllocId`; that information
 /// is added when converting to `InterpError`.
 #[derive(Debug)]
index e524625f96646b9de4ec0b13a384d89d7ca27a67..c97865904769820f5793b94e54b6f98a8e09d4dc 100644 (file)
@@ -184,6 +184,8 @@ pub enum CheckInAllocMsg {
     MemoryAccessTest,
     /// We are doing pointer arithmetic.
     PointerArithmeticTest,
+    /// We are doing pointer offset_from.
+    OffsetFromTest,
     /// None of the above -- generic/unspecific inbounds test.
     InboundsTest,
 }
@@ -199,6 +201,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 CheckInAllocMsg::DerefTest => "dereferencing pointer failed: ",
                 CheckInAllocMsg::MemoryAccessTest => "memory access failed: ",
                 CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic failed: ",
+                CheckInAllocMsg::OffsetFromTest => "out-of-bounds offset_from: ",
                 CheckInAllocMsg::InboundsTest => "",
             }
         )
@@ -358,6 +361,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             DanglingIntPointer(0, CheckInAllocMsg::InboundsTest) => {
                 write!(f, "null pointer is not a valid pointer for this operation")
             }
+            DanglingIntPointer(0, msg) => {
+                write!(f, "{}null pointer is not a valid pointer", msg)
+            }
             DanglingIntPointer(i, msg) => {
                 write!(f, "{}0x{:x} is not a valid pointer", msg, i)
             }
index 4eac0009f69e2e1893d6448942cb2bfa8d466442..bce962491b7b1c99c17b43139d2743c12d78ebe6 100644 (file)
@@ -126,7 +126,8 @@ macro_rules! throw_machine_stop {
 pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit};
 
 pub use self::allocation::{
-    alloc_range, AllocRange, Allocation, InitChunk, InitChunkIter, InitMask, Relocations,
+    alloc_range, AllocRange, Allocation, ConstAllocation, InitChunk, InitChunkIter, InitMask,
+    Relocations,
 };
 
 pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
@@ -343,7 +344,7 @@ pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> AllocId
         let alloc_id = decoder.with_position(pos, |decoder| {
             match alloc_kind {
                 AllocDiscriminant::Alloc => {
-                    let alloc = <&'tcx Allocation as Decodable<_>>::decode(decoder);
+                    let alloc = <ConstAllocation<'tcx> as Decodable<_>>::decode(decoder);
                     // We already have a reserved `AllocId`.
                     let alloc_id = alloc_id.unwrap();
                     trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
@@ -387,14 +388,14 @@ pub enum GlobalAlloc<'tcx> {
     /// This is also used to break the cycle in recursive statics.
     Static(DefId),
     /// The alloc ID points to memory.
-    Memory(&'tcx Allocation),
+    Memory(ConstAllocation<'tcx>),
 }
 
 impl<'tcx> GlobalAlloc<'tcx> {
     /// Panics if the `GlobalAlloc` does not refer to an `GlobalAlloc::Memory`
     #[track_caller]
     #[inline]
-    pub fn unwrap_memory(&self) -> &'tcx Allocation {
+    pub fn unwrap_memory(&self) -> ConstAllocation<'tcx> {
         match *self {
             GlobalAlloc::Memory(mem) => mem,
             _ => bug!("expected memory, got {:?}", self),
@@ -512,7 +513,7 @@ pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
     /// Statics with identical content will still point to the same `Allocation`, i.e.,
     /// their data will be deduplicated through `Allocation` interning -- but they
     /// are different places in memory and as such need different IDs.
-    pub fn create_memory_alloc(self, mem: &'tcx Allocation) -> AllocId {
+    pub fn create_memory_alloc(self, mem: ConstAllocation<'tcx>) -> AllocId {
         let id = self.reserve_alloc_id();
         self.set_alloc_id_memory(id, mem);
         id
@@ -543,7 +544,7 @@ pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> {
 
     /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
     /// call this function twice, even with the same `Allocation` will ICE the compiler.
-    pub fn set_alloc_id_memory(self, id: AllocId, mem: &'tcx Allocation) {
+    pub fn set_alloc_id_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
         if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) {
             bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old);
         }
@@ -551,7 +552,7 @@ pub fn set_alloc_id_memory(self, id: AllocId, mem: &'tcx Allocation) {
 
     /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
     /// twice for the same `(AllocId, Allocation)` pair.
-    fn set_alloc_id_same_memory(self, id: AllocId, mem: &'tcx Allocation) {
+    fn set_alloc_id_same_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
         self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem));
     }
 }
index 4a57f483c70e2b8a1069263ca031f8271ca817a5..8b0f92d23d75fb72f0aed5f404192901667cb9f9 100644 (file)
@@ -79,7 +79,7 @@ pub fn const_eval_global_id(
     pub fn eval_static_initializer(
         self,
         def_id: DefId,
-    ) -> Result<&'tcx mir::Allocation, ErrorHandled> {
+    ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
         trace!("eval_static_initializer: Need to compute {:?}", def_id);
         assert!(self.is_static(def_id));
         let instance = ty::Instance::mono(self, def_id);
@@ -92,7 +92,7 @@ fn eval_to_allocation(
         self,
         gid: GlobalId<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-    ) -> Result<&'tcx mir::Allocation, ErrorHandled> {
+    ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
         let param_env = param_env.with_const();
         trace!("eval_to_allocation: Need to compute {:?}", gid);
         let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
index c8ddc4edc8adae51efb0b50e5858c7ad696ba8c5..8e32603a357026f9b4af0b6fa1d8eccea5f83df8 100644 (file)
@@ -11,7 +11,7 @@
 use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt};
 
 use super::{
-    AllocId, AllocRange, Allocation, InterpResult, Pointer, PointerArithmetic, Provenance,
+    AllocId, AllocRange, ConstAllocation, InterpResult, Pointer, PointerArithmetic, Provenance,
 };
 
 /// Represents the result of const evaluation via the `eval_to_allocation` query.
@@ -34,13 +34,13 @@ pub enum ConstValue<'tcx> {
     Scalar(Scalar),
 
     /// Used only for `&[u8]` and `&str`
-    Slice { data: &'tcx Allocation, start: usize, end: usize },
+    Slice { data: ConstAllocation<'tcx>, start: usize, end: usize },
 
     /// A value not represented/representable by `Scalar` or `Slice`
     ByRef {
         /// The backing memory of the value, may contain more memory than needed for just the value
-        /// in order to share `Allocation`s between values
-        alloc: &'tcx Allocation,
+        /// in order to share `ConstAllocation`s between values
+        alloc: ConstAllocation<'tcx>,
         /// Offset into `alloc`
         offset: Size,
     },
@@ -603,11 +603,12 @@ pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64
 pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] {
     if let ConstValue::Slice { data, start, end } = val {
         let len = end - start;
-        data.get_bytes(
-            cx,
-            AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) },
-        )
-        .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err))
+        data.inner()
+            .get_bytes(
+                cx,
+                AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) },
+            )
+            .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err))
     } else {
         bug!("expected const slice, but found another const value");
     }
index ce3d6f348d194c09430219a3b8a5bef1132b0107..18c2dd71ad3d0bf11c7e2080f0a7cdcf1eaf87d5 100644 (file)
@@ -3,7 +3,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
 
 use crate::mir::coverage::{CodeRegion, CoverageKind};
-use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar};
+use crate::mir::interpret::{ConstAllocation, ConstValue, GlobalAlloc, Scalar};
 use crate::mir::visit::MirVisitable;
 use crate::ty::adjustment::PointerCast;
 use crate::ty::codec::{TyDecoder, TyEncoder};
@@ -1292,6 +1292,8 @@ pub enum InlineAsmOperand<'tcx> {
 /// Type for MIR `Assert` terminator error messages.
 pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
 
+// FIXME: Change `Successors` to `impl Iterator<Item = BasicBlock>`.
+#[allow(rustc::pass_by_value)]
 pub type Successors<'a> =
     iter::Chain<option::IntoIter<&'a BasicBlock>, slice::Iter<'a, BasicBlock>>;
 pub type SuccessorsMut<'a> =
@@ -1832,7 +1834,8 @@ pub fn is_field_to(&self, f: Field) -> bool {
 /// and the index is a local.
 pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
 
-// At least on 64 bit systems, `PlaceElem` should not be larger than two pointers.
+// This type is fairly frequently used, so we shouldn't unintentionally increase
+// its size.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(PlaceElem<'_>, 24);
 
@@ -1912,6 +1915,27 @@ pub fn iter_projections(
             (base, proj)
         })
     }
+
+    /// Generates a new place by appending `more_projections` to the existing ones
+    /// and interning the result.
+    pub fn project_deeper(self, more_projections: &[PlaceElem<'tcx>], tcx: TyCtxt<'tcx>) -> Self {
+        if more_projections.is_empty() {
+            return self;
+        }
+
+        let mut v: Vec<PlaceElem<'tcx>>;
+
+        let new_projections = if self.projection.is_empty() {
+            more_projections
+        } else {
+            v = Vec::with_capacity(self.projection.len() + more_projections.len());
+            v.extend(self.projection);
+            v.extend(more_projections);
+            &v
+        };
+
+        Place { local: self.local, projection: tcx.intern_place_elems(new_projections) }
+    }
 }
 
 impl From<Local> for Place<'_> {
@@ -2184,6 +2208,15 @@ pub fn constant(&self) -> Option<&Constant<'tcx>> {
             Operand::Copy(_) | Operand::Move(_) => None,
         }
     }
+
+    /// Gets the `ty::FnDef` from an operand if it's a constant function item.
+    ///
+    /// While this is unlikely in general, it's the normal case of what you'll
+    /// find as the `func` in a [`TerminatorKind::Call`].
+    pub fn const_fn_def(&self) -> Option<(DefId, SubstsRef<'tcx>)> {
+        let const_ty = self.constant()?.literal.ty();
+        if let ty::FnDef(def_id, substs) = *const_ty.kind() { Some((def_id, substs)) } else { None }
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -2534,7 +2567,7 @@ pub enum ConstantKind<'tcx> {
 
 impl<'tcx> Constant<'tcx> {
     pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
-        match self.literal.const_for_ty()?.val().try_to_scalar() {
+        match self.literal.try_to_scalar() {
             Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
                 GlobalAlloc::Static(def_id) => {
                     assert!(!tcx.is_thread_local_static(def_id));
@@ -2554,7 +2587,14 @@ pub fn ty(&self) -> Ty<'tcx> {
 impl<'tcx> From<ty::Const<'tcx>> for ConstantKind<'tcx> {
     #[inline]
     fn from(ct: ty::Const<'tcx>) -> Self {
-        Self::Ty(ct)
+        match ct.val() {
+            ty::ConstKind::Value(cv) => {
+                // FIXME Once valtrees are introduced we need to convert those
+                // into `ConstValue` instances here
+                Self::Val(cv, ct.ty())
+            }
+            _ => Self::Ty(ct),
+        }
     }
 }
 
@@ -2635,6 +2675,27 @@ pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -
             Self::Val(val, _) => val.try_to_machine_usize(tcx),
         }
     }
+
+    pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
+        let cv = ConstValue::from_bool(v);
+        Self::Val(cv, tcx.types.bool)
+    }
+
+    pub fn from_zero_sized(ty: Ty<'tcx>) -> Self {
+        let cv = ConstValue::Scalar(Scalar::ZST);
+        Self::Val(cv, ty)
+    }
+
+    pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
+        let ty = tcx.types.usize;
+        let size = tcx
+            .layout_of(ty::ParamEnv::empty().and(ty))
+            .unwrap_or_else(|e| bug!("could not compute layout for {:?}: {:?}", ty, e))
+            .size;
+        let cv = ConstValue::Scalar(Scalar::from_uint(n as u128, size));
+
+        Self::Val(cv, ty)
+    }
 }
 
 /// A collection of projections into user types.
index 6886a0f4cf1489bbb1e448b8385ba0218c705822..50d9c8e98b9b2e193deb22bb3a61078a89f833c9 100644 (file)
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::Idx;
 use rustc_middle::mir::interpret::{
-    read_target_uint, AllocId, Allocation, ConstValue, GlobalAlloc, Pointer, Provenance,
+    read_target_uint, AllocId, Allocation, ConstAllocation, ConstValue, GlobalAlloc, Pointer,
+    Provenance,
 };
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::MirSource;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_target::abi::Size;
-use std::ops::ControlFlow;
 
 const INDENT: &str = "    ";
 /// Alignment for lining up comments following MIR statements
@@ -652,12 +652,14 @@ pub fn write_allocations<'tcx>(
     body: &Body<'_>,
     w: &mut dyn Write,
 ) -> io::Result<()> {
-    fn alloc_ids_from_alloc(alloc: &Allocation) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
-        alloc.relocations().values().map(|id| *id)
+    fn alloc_ids_from_alloc(
+        alloc: ConstAllocation<'_>,
+    ) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
+        alloc.inner().relocations().values().map(|id| *id)
     }
     fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
         match val {
-            ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _size)) => {
+            ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => {
                 Either::Left(Either::Left(std::iter::once(ptr.provenance)))
             }
             ConstValue::Scalar(interpret::Scalar::Int { .. }) => {
@@ -669,16 +671,27 @@ fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> +
         }
     }
     struct CollectAllocIds(BTreeSet<AllocId>);
-    impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds {
-        fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+
+    impl<'tcx> Visitor<'tcx> for CollectAllocIds {
+        fn visit_const(&mut self, c: ty::Const<'tcx>, _loc: Location) {
             if let ty::ConstKind::Value(val) = c.val() {
                 self.0.extend(alloc_ids_from_const(val));
             }
-            c.super_visit_with(self)
+        }
+
+        fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) {
+            match c.literal {
+                ConstantKind::Ty(c) => self.visit_const(c, loc),
+                ConstantKind::Val(val, _) => {
+                    self.0.extend(alloc_ids_from_const(val));
+                }
+            }
         }
     }
+
     let mut visitor = CollectAllocIds(Default::default());
-    body.visit_with(&mut visitor);
+    visitor.visit_body(body);
+
     // `seen` contains all seen allocations, including the ones we have *not* printed yet.
     // The protocol is to first `insert` into `seen`, and only if that returns `true`
     // then push to `todo`.
@@ -686,14 +699,14 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
     let mut todo: Vec<_> = seen.iter().copied().collect();
     while let Some(id) = todo.pop() {
         let mut write_allocation_track_relocs =
-            |w: &mut dyn Write, alloc: &Allocation| -> io::Result<()> {
+            |w: &mut dyn Write, alloc: ConstAllocation<'tcx>| -> io::Result<()> {
                 // `.rev()` because we are popping them from the back of the `todo` vector.
                 for id in alloc_ids_from_alloc(alloc).rev() {
                     if seen.insert(id) {
                         todo.push(id);
                     }
                 }
-                write!(w, "{}", display_allocation(tcx, alloc))
+                write!(w, "{}", display_allocation(tcx, alloc.inner()))
             };
         write!(w, "\n{}", id)?;
         match tcx.get_global_alloc(id) {
index 23f9849e83171976a513b6bf710fe239f9a5f9ee..6f85854fc745cc47c413bf349d58f5c57661b717 100644 (file)
@@ -33,7 +33,7 @@ pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
     /// not carry a `Ty` for `T`.)
     ///
     /// Note that the resulting type has not been normalized.
-    pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> {
+    pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: Field) -> Ty<'tcx> {
         let answer = match self.ty.kind() {
             ty::Adt(adt_def, substs) => {
                 let variant_def = match self.variant_index {
@@ -57,7 +57,7 @@ pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> {
     /// `PlaceElem`, where we can just use the `Ty` that is already
     /// stored inline on field projection elems.
     pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
-        self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, &ty| ty)
+        self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty)
     }
 
     /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@@ -70,11 +70,11 @@ pub fn projection_ty_core<V, T>(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         elem: &ProjectionElem<V, T>,
-        mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>,
+        mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>,
     ) -> PlaceTy<'tcx>
     where
         V: ::std::fmt::Debug,
-        T: ::std::fmt::Debug,
+        T: ::std::fmt::Debug + Copy,
     {
         let answer = match *elem {
             ProjectionElem::Deref => {
@@ -105,7 +105,7 @@ pub fn projection_ty_core<V, T>(
             ProjectionElem::Downcast(_name, index) => {
                 PlaceTy { ty: self.ty, variant_index: Some(index) }
             }
-            ProjectionElem::Field(ref f, ref fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
+            ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
         };
         debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
         answer
index 7320a5690693b732ae617afeb3cc980446eb8885..aeb0f956eb4f78c7337f48df710ed012a9a09110 100644 (file)
@@ -225,12 +225,14 @@ fn visit_var_debug_info(&mut self,
                 self.super_var_debug_info(var_debug_info);
             }
 
+            #[allow(rustc::pass_by_value)]
             fn visit_local(&mut self,
                             _local: & $($mutability)? Local,
                             _context: PlaceContext,
                             _location: Location) {
             }
 
+            #[allow(rustc::pass_by_value)]
             fn visit_source_scope(&mut self,
                                       scope: & $($mutability)? SourceScope) {
                 self.super_source_scope(scope);
@@ -851,6 +853,7 @@ fn super_var_debug_info(&mut self,
                 }
             }
 
+            #[allow(rustc::pass_by_value)]
             fn super_source_scope(&mut self,
                                       _scope: & $($mutability)? SourceScope) {
             }
index 40dce281c82bf2460c6885bfadde72160f236a5d..04bc0c8b52114dccded115a8b98fa0c9a1ac94f1 100644 (file)
@@ -17,6 +17,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_middle::infer::canonical::Canonical;
 use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::mir::{
     BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
 };
@@ -419,7 +420,8 @@ pub enum ExprKind<'tcx> {
     /// This is only distinguished from `Literal` so that we can register some
     /// info for diagnostics.
     StaticRef {
-        literal: Const<'tcx>,
+        alloc_id: AllocId,
+        ty: Ty<'tcx>,
         def_id: DefId,
     },
     /// Inline assembly, i.e. `asm!()`.
index 95489ac3ab2c64c8413680dd4764fa6ef794318e..1c472f38184eadca7faedd6b7c4899278ee24356 100644 (file)
@@ -123,7 +123,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
         }
         Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
         Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
-        StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
+        StaticRef { alloc_id: _, ty: _, def_id: _ } => {}
         InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
             for op in &**operands {
                 use InlineAsmOperand::*;
index 8ba6c1f67c94cc79046ec17e7005d1995081b4b5..65a60dd6b9d7b70ffdc8d36750f0c95fa30f65ef 100644 (file)
@@ -281,7 +281,7 @@ pub struct CaptureInfo {
     /// let mut t = (0,1);
     ///
     /// let c = || {
-    ///     println!("{}",t); // L1
+    ///     println!("{t}"); // L1
     ///     t.1 = 4; // L2
     /// };
     /// ```
index 23fb7a49d9c8e923602a56e5f66a1e504aaf8b92..69455951c5794b8a97f1814ad52fa33396bbd844 100644 (file)
@@ -10,7 +10,7 @@
 use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
 use crate::mir::{
     self,
-    interpret::{AllocId, Allocation},
+    interpret::{AllocId, ConstAllocation},
 };
 use crate::thir;
 use crate::traits;
@@ -150,6 +150,12 @@ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
     }
 }
 
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ConstAllocation<'tcx> {
+    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+        self.inner().encode(e)
+    }
+}
+
 impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AllocId {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         e.encode_alloc_id(self)
@@ -355,8 +361,8 @@ fn decode(decoder: &mut D) -> &'tcx Self {
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for Allocation {
-    fn decode(decoder: &mut D) -> &'tcx Self {
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ConstAllocation<'tcx> {
+    fn decode(decoder: &mut D) -> Self {
         decoder.tcx().intern_const_alloc(Decodable::decode(decoder))
     }
 }
@@ -399,7 +405,6 @@ fn decode(decoder: &mut D) -> &'tcx Self {
     &'tcx ty::List<Ty<'tcx>>,
     &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
     &'tcx traits::ImplSource<'tcx, ()>,
-    &'tcx Allocation,
     &'tcx mir::Body<'tcx>,
     &'tcx mir::UnsafetyCheckResult,
     &'tcx mir::BorrowCheckResult<'tcx>,
index 36d93de9a33463d546e0073bcc7626a8c25fc982..99dd4ab1bf5fd8e14d620c27f5b441fdfd97a3aa 100644 (file)
@@ -7,7 +7,7 @@
 use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
 use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
 use crate::middle::stability;
-use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
+use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
 use crate::mir::{
     Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
 };
@@ -56,7 +56,7 @@
 use rustc_span::source_map::{MultiSpan, SourceMap};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx};
+use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx};
 use rustc_target::spec::abi;
 
 use rustc_type_ir::TypeFlags;
@@ -114,7 +114,7 @@ pub struct CtxtInterners<'tcx> {
     const_: InternedSet<'tcx, ConstS<'tcx>>,
     const_allocation: InternedSet<'tcx, Allocation>,
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
-    layout: InternedSet<'tcx, Layout>,
+    layout: InternedSet<'tcx, LayoutS<'tcx>>,
     adt_def: InternedSet<'tcx, AdtDef>,
 }
 
@@ -1653,22 +1653,6 @@ pub trait Lift<'tcx>: fmt::Debug {
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted>;
 }
 
-// Deprecated: we are in the process of converting all uses to `nop_lift`.
-macro_rules! nop_lift_old {
-    ($set:ident; $ty:ty => $lifted:ty) => {
-        impl<'a, 'tcx> Lift<'tcx> for $ty {
-            type Lifted = $lifted;
-            fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-                if tcx.interners.$set.contains_pointer_to(&InternedInSet(self)) {
-                    Some(unsafe { mem::transmute(self) })
-                } else {
-                    None
-                }
-            }
-        }
-    };
-}
-
 macro_rules! nop_lift {
     ($set:ident; $ty:ty => $lifted:ty) => {
         impl<'a, 'tcx> Lift<'tcx> for $ty {
@@ -1726,7 +1710,7 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
 nop_lift! {type_; Ty<'a> => Ty<'tcx>}
 nop_lift! {region; Region<'a> => Region<'tcx>}
 nop_lift! {const_; Const<'a> => Const<'tcx>}
-nop_lift_old! {const_allocation; &'a Allocation => &'tcx Allocation}
+nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>}
 nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
 
 nop_list_lift! {poly_existential_predicates; ty::Binder<'a, ExistentialPredicate<'a>> => ty::Binder<'tcx, ExistentialPredicate<'tcx>>}
@@ -2161,6 +2145,8 @@ pub fn $method(self, v: $ty) -> $ret_ty {
 direct_interners! {
     region: mk_region(RegionKind): Region -> Region<'tcx>,
     const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>,
+    const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
+    layout: intern_layout(LayoutS<'tcx>): Layout -> Layout<'tcx>,
 }
 
 macro_rules! direct_interners_old {
@@ -2201,8 +2187,6 @@ pub fn $method(self, v: $ty) -> &'tcx $ty {
 
 // FIXME: eventually these should all be converted to `direct_interners`.
 direct_interners_old! {
-    const_allocation: intern_const_alloc(Allocation),
-    layout: intern_layout(Layout),
     adt_def: intern_adt_def(AdtDef),
 }
 
index 7495449da4c4f78abee054894d03aadd3f7eee9e..23664640aaef0f8987c7b82121bb7675359a769c 100644 (file)
@@ -5,6 +5,7 @@
 use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
 use rustc_ast as ast;
 use rustc_attr as attr;
+use rustc_data_structures::intern::Interned;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::BitSet;
@@ -302,7 +303,7 @@ fn invert_mapping(map: &[u32]) -> Vec<u32> {
 }
 
 impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
-    fn scalar_pair(&self, a: Scalar, b: Scalar) -> Layout {
+    fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS<'tcx> {
         let dl = self.data_layout();
         let b_align = b.value.align(dl);
         let align = a.value.align(dl).max(b_align).max(dl.aggregate_align);
@@ -316,7 +317,7 @@ fn scalar_pair(&self, a: Scalar, b: Scalar) -> Layout {
             .chain(Niche::from_scalar(dl, Size::ZERO, a))
             .max_by_key(|niche| niche.available(dl));
 
-        Layout {
+        LayoutS {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Arbitrary {
                 offsets: vec![Size::ZERO, b_offset],
@@ -335,7 +336,7 @@ fn univariant_uninterned(
         fields: &[TyAndLayout<'_>],
         repr: &ReprOptions,
         kind: StructKind,
-    ) -> Result<Layout, LayoutError<'tcx>> {
+    ) -> Result<LayoutS<'tcx>, LayoutError<'tcx>> {
         let dl = self.data_layout();
         let pack = repr.pack;
         if pack.is_some() && repr.align.is_some() {
@@ -503,8 +504,20 @@ fn univariant_uninterned(
 
                 // Two non-ZST fields, and they're both scalars.
                 (
-                    Some((i, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(a), .. }, .. })),
-                    Some((j, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(b), .. }, .. })),
+                    Some((
+                        i,
+                        &TyAndLayout {
+                            layout: Layout(Interned(&LayoutS { abi: Abi::Scalar(a), .. }, _)),
+                            ..
+                        },
+                    )),
+                    Some((
+                        j,
+                        &TyAndLayout {
+                            layout: Layout(Interned(&LayoutS { abi: Abi::Scalar(b), .. }, _)),
+                            ..
+                        },
+                    )),
                     None,
                 ) => {
                     // Order by the memory placement, not source order.
@@ -537,7 +550,7 @@ fn univariant_uninterned(
             abi = Abi::Uninhabited;
         }
 
-        Ok(Layout {
+        Ok(LayoutS {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Arbitrary { offsets, memory_index },
             abi,
@@ -547,7 +560,7 @@ fn univariant_uninterned(
         })
     }
 
-    fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> {
+    fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
         let tcx = self.tcx;
         let param_env = self.param_env;
         let dl = self.data_layout();
@@ -556,7 +569,8 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
             assert!(size.bits() <= 128);
             Scalar { value, valid_range: WrappingRange { start: 0, end: size.unsigned_int_max() } }
         };
-        let scalar = |value: Primitive| tcx.intern_layout(Layout::scalar(self, scalar_unit(value)));
+        let scalar =
+            |value: Primitive| tcx.intern_layout(LayoutS::scalar(self, scalar_unit(value)));
 
         let univariant = |fields: &[TyAndLayout<'_>], repr: &ReprOptions, kind| {
             Ok(tcx.intern_layout(self.univariant_uninterned(ty, fields, repr, kind)?))
@@ -565,11 +579,11 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
 
         Ok(match *ty.kind() {
             // Basic scalars.
-            ty::Bool => tcx.intern_layout(Layout::scalar(
+            ty::Bool => tcx.intern_layout(LayoutS::scalar(
                 self,
                 Scalar { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 } },
             )),
-            ty::Char => tcx.intern_layout(Layout::scalar(
+            ty::Char => tcx.intern_layout(LayoutS::scalar(
                 self,
                 Scalar {
                     value: Int(I32, false),
@@ -585,11 +599,11 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
             ty::FnPtr(_) => {
                 let mut ptr = scalar_unit(Pointer);
                 ptr.valid_range = ptr.valid_range.with_start(1);
-                tcx.intern_layout(Layout::scalar(self, ptr))
+                tcx.intern_layout(LayoutS::scalar(self, ptr))
             }
 
             // The never type.
-            ty::Never => tcx.intern_layout(Layout {
+            ty::Never => tcx.intern_layout(LayoutS {
                 variants: Variants::Single { index: VariantIdx::new(0) },
                 fields: FieldsShape::Primitive,
                 abi: Abi::Uninhabited,
@@ -607,13 +621,13 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
 
                 let pointee = tcx.normalize_erasing_regions(param_env, pointee);
                 if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
-                    return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr)));
+                    return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr)));
                 }
 
                 let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
                 let metadata = match unsized_part.kind() {
                     ty::Foreign(..) => {
-                        return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr)));
+                        return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr)));
                     }
                     ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
                     ty::Dynamic(..) => {
@@ -651,7 +665,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
 
                 let largest_niche = if count != 0 { element.largest_niche } else { None };
 
-                tcx.intern_layout(Layout {
+                tcx.intern_layout(LayoutS {
                     variants: Variants::Single { index: VariantIdx::new(0) },
                     fields: FieldsShape::Array { stride: element.size, count },
                     abi,
@@ -662,7 +676,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
             }
             ty::Slice(element) => {
                 let element = self.layout_of(element)?;
-                tcx.intern_layout(Layout {
+                tcx.intern_layout(LayoutS {
                     variants: Variants::Single { index: VariantIdx::new(0) },
                     fields: FieldsShape::Array { stride: element.size, count: 0 },
                     abi: Abi::Aggregate { sized: false },
@@ -671,7 +685,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
                     size: Size::ZERO,
                 })
             }
-            ty::Str => tcx.intern_layout(Layout {
+            ty::Str => tcx.intern_layout(LayoutS {
                 variants: Variants::Single { index: VariantIdx::new(0) },
                 fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
                 abi: Abi::Aggregate { sized: false },
@@ -775,7 +789,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
 
                     // Extract the number of elements from the layout of the array field:
                     let Ok(TyAndLayout {
-                        layout: Layout { fields: FieldsShape::Array { count, .. }, .. },
+                        layout: Layout(Interned(LayoutS { fields: FieldsShape::Array { count, .. }, .. }, _)),
                         ..
                     }) = self.layout_of(f0_ty) else {
                         return Err(LayoutError::Unknown(ty));
@@ -825,7 +839,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
                     FieldsShape::Array { stride: e_ly.size, count: e_len }
                 };
 
-                tcx.intern_layout(Layout {
+                tcx.intern_layout(LayoutS {
                     variants: Variants::Single { index: VariantIdx::new(0) },
                     fields,
                     abi: Abi::Vector { element: e_abi, count: e_len },
@@ -905,7 +919,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
                         align = align.min(AbiAndPrefAlign::new(pack));
                     }
 
-                    return Ok(tcx.intern_layout(Layout {
+                    return Ok(tcx.intern_layout(LayoutS {
                         variants: Variants::Single { index },
                         fields: FieldsShape::Union(
                             NonZeroUsize::new(variants[index].len())
@@ -1100,17 +1114,17 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
 
                                     align = align.max(st.align);
 
-                                    Ok(st)
+                                    Ok(tcx.intern_layout(st))
                                 })
                                 .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
 
-                            let offset = st[i].fields.offset(field_index) + niche.offset;
-                            let size = st[i].size;
+                            let offset = st[i].fields().offset(field_index) + niche.offset;
+                            let size = st[i].size();
 
-                            let abi = if st.iter().all(|v| v.abi.is_uninhabited()) {
+                            let abi = if st.iter().all(|v| v.abi().is_uninhabited()) {
                                 Abi::Uninhabited
                             } else {
-                                match st[i].abi {
+                                match st[i].abi() {
                                     Abi::Scalar(_) => Abi::Scalar(niche_scalar),
                                     Abi::ScalarPair(first, second) => {
                                         // We need to use scalar_unit to reset the
@@ -1130,7 +1144,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
 
                             let largest_niche = Niche::from_scalar(dl, offset, niche_scalar);
 
-                            niche_filling_layout = Some(Layout {
+                            niche_filling_layout = Some(LayoutS {
                                 variants: Variants::Multiple {
                                     tag: niche_scalar,
                                     tag_encoding: TagEncoding::Niche {
@@ -1377,7 +1391,10 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
 
                 let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
 
-                let tagged_layout = Layout {
+                let layout_variants =
+                    layout_variants.into_iter().map(|v| tcx.intern_layout(v)).collect();
+
+                let tagged_layout = LayoutS {
                     variants: Variants::Multiple {
                         tag,
                         tag_encoding: TagEncoding::Direct,
@@ -1563,7 +1580,7 @@ fn generator_layout(
         ty: Ty<'tcx>,
         def_id: hir::def_id::DefId,
         substs: SubstsRef<'tcx>,
-    ) -> Result<&'tcx Layout, LayoutError<'tcx>> {
+    ) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
         use SavedLocalEligibility::*;
         let tcx = self.tcx;
         let subst_field = |ty: Ty<'tcx>| ty.subst(tcx, substs);
@@ -1586,7 +1603,7 @@ fn generator_layout(
             value: Primitive::Int(discr_int, false),
             valid_range: WrappingRange { start: 0, end: max_discr },
         };
-        let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag));
+        let tag_layout = self.tcx.intern_layout(LayoutS::scalar(self, tag));
         let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
 
         let promoted_layouts = ineligible_locals
@@ -1722,20 +1739,20 @@ fn generator_layout(
 
                 size = size.max(variant.size);
                 align = align.max(variant.align);
-                Ok(variant)
+                Ok(tcx.intern_layout(variant))
             })
             .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
 
         size = size.align_to(align.abi);
 
-        let abi = if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi.is_uninhabited())
-        {
-            Abi::Uninhabited
-        } else {
-            Abi::Aggregate { sized: true }
-        };
+        let abi =
+            if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi().is_uninhabited()) {
+                Abi::Uninhabited
+            } else {
+                Abi::Aggregate { sized: true }
+            };
 
-        let layout = tcx.intern_layout(Layout {
+        let layout = tcx.intern_layout(LayoutS {
             variants: Variants::Multiple {
                 tag,
                 tag_encoding: TagEncoding::Direct,
@@ -2250,7 +2267,7 @@ fn ty_and_layout_for_variant(
                     ty::Adt(def, _) => def.variants[variant_index].fields.len(),
                     _ => bug!(),
                 };
-                tcx.intern_layout(Layout {
+                tcx.intern_layout(LayoutS {
                     variants: Variants::Single { index: variant_index },
                     fields: match NonZeroUsize::new(fields) {
                         Some(fields) => FieldsShape::Union(fields),
@@ -2263,10 +2280,10 @@ fn ty_and_layout_for_variant(
                 })
             }
 
-            Variants::Multiple { ref variants, .. } => &variants[variant_index],
+            Variants::Multiple { ref variants, .. } => variants[variant_index],
         };
 
-        assert_eq!(layout.variants, Variants::Single { index: variant_index });
+        assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
 
         TyAndLayout { ty: this.ty, layout }
     }
@@ -2284,8 +2301,10 @@ fn field_ty_or_layout<'tcx>(
         ) -> TyMaybeWithLayout<'tcx> {
             let tcx = cx.tcx();
             let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
-                let layout = Layout::scalar(cx, tag);
-                TyAndLayout { layout: tcx.intern_layout(layout), ty: tag.value.to_ty(tcx) }
+                TyAndLayout {
+                    layout: tcx.intern_layout(LayoutS::scalar(cx, tag)),
+                    ty: tag.value.to_ty(tcx),
+                }
             };
 
             match *this.ty.kind() {
index 542bc3b02e02bb0b587f97503fa4fd13c146bbd7..0927dc2d266abe4353b461d3276fcfe135bb76d6 100644 (file)
@@ -1267,7 +1267,7 @@ fn pretty_print_const_scalar_ptr(
                 Some(GlobalAlloc::Memory(alloc)) => {
                     let len = int.assert_bits(self.tcx().data_layout.pointer_size);
                     let range = AllocRange { start: offset, size: Size::from_bytes(len) };
-                    if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), range) {
+                    if let Ok(byte_str) = alloc.inner().get_bytes(&self.tcx(), range) {
                         p!(pretty_print_byte_str(byte_str))
                     } else {
                         p!("<too short allocation>")
@@ -1424,7 +1424,8 @@ fn pretty_print_const_value(
                 // The `inspect` here is okay since we checked the bounds, and there are
                 // no relocations (we have an active slice reference here). We don't use
                 // this result to affect interpreter execution.
-                let byte_str = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+                let byte_str =
+                    data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end);
                 self.pretty_print_byte_str(byte_str)
             }
             (
@@ -1434,7 +1435,8 @@ fn pretty_print_const_value(
                 // The `inspect` here is okay since we checked the bounds, and there are no
                 // relocations (we have an active `str` reference here). We don't use this
                 // result to affect interpreter execution.
-                let slice = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+                let slice =
+                    data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end);
                 p!(write("{:?}", String::from_utf8_lossy(slice)));
                 Ok(self)
             }
@@ -1443,7 +1445,7 @@ fn pretty_print_const_value(
                 // cast is ok because we already checked for pointer size (32 or 64 bit) above
                 let range = AllocRange { start: offset, size: Size::from_bytes(n) };
 
-                let byte_str = alloc.get_bytes(&self.tcx(), range).unwrap();
+                let byte_str = alloc.inner().get_bytes(&self.tcx(), range).unwrap();
                 p!("*");
                 p!(pretty_print_byte_str(byte_str));
                 Ok(self)
index a1e906140e0e8211a8f5620f9b05029e1523d0d4..775d86153ced20929f402b35ab1995d41e37f478 100644 (file)
@@ -977,7 +977,6 @@ pub fn from_method(
         substs: SubstsRef<'tcx>,
     ) -> ty::TraitRef<'tcx> {
         let defs = tcx.generics_of(trait_id);
-
         ty::TraitRef { def_id: trait_id, substs: tcx.intern_substs(&substs[..defs.params.len()]) }
     }
 }
@@ -1887,6 +1886,15 @@ pub fn is_slice(self) -> bool {
         }
     }
 
+    #[inline]
+    pub fn is_array_slice(self) -> bool {
+        match self.kind() {
+            Slice(_) => true,
+            RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_)),
+            _ => false,
+        }
+    }
+
     #[inline]
     pub fn is_array(self) -> bool {
         matches!(self.kind(), Array(..))
@@ -2372,6 +2380,57 @@ pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
             }
         }
     }
+
+    /// Fast path helper for primitives which are always `Copy` and which
+    /// have a side-effect-free `Clone` impl.
+    ///
+    /// Returning true means the type is known to be pure and `Copy+Clone`.
+    /// Returning `false` means nothing -- could be `Copy`, might not be.
+    ///
+    /// This is mostly useful for optimizations, as there are the types
+    /// on which we can replace cloning with dereferencing.
+    pub fn is_trivially_pure_clone_copy(self) -> bool {
+        match self.kind() {
+            ty::Bool | ty::Char | ty::Never => true,
+
+            // These aren't even `Clone`
+            ty::Str | ty::Slice(..) | ty::Foreign(..) | ty::Dynamic(..) => false,
+
+            ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
+
+            // The voldemort ZSTs are fine.
+            ty::FnDef(..) => true,
+
+            ty::Array(element_ty, _len) => element_ty.is_trivially_pure_clone_copy(),
+
+            // A 100-tuple isn't "trivial", so doing this only for reasonable sizes.
+            ty::Tuple(field_tys) => {
+                field_tys.len() <= 3 && field_tys.iter().all(Self::is_trivially_pure_clone_copy)
+            }
+
+            // Sometimes traits aren't implemented for every ABI or arity,
+            // because we can't be generic over everything yet.
+            ty::FnPtr(..) => false,
+
+            // Definitely absolutely not copy.
+            ty::Ref(_, _, hir::Mutability::Mut) => false,
+
+            // Thin pointers & thin shared references are pure-clone-copy, but for
+            // anything with custom metadata it might be more complicated.
+            ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false,
+
+            ty::Generator(..) | ty::GeneratorWitness(..) => false,
+
+            // Might be, but not "trivial" so just giving the safe answer.
+            ty::Adt(..) | ty::Closure(..) | ty::Opaque(..) => false,
+
+            ty::Projection(..) | ty::Param(..) | ty::Infer(..) | ty::Error(..) => false,
+
+            ty::Bound(..) | ty::Placeholder(..) => {
+                bug!("`is_trivially_pure_clone_copy` applied to unexpected type: {:?}", self);
+            }
+        }
+    }
 }
 
 /// Extra information about why we ended up with a particular variance.
index 04e766d16cc49c88fec0d6869d32732127b2885a..eb16d305d0a8085c17caab0668a982a65a2e586b 100644 (file)
@@ -704,7 +704,7 @@ pub fn is_copy_modulo_regions(
         tcx_at: TyCtxtAt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> bool {
-        tcx_at.is_copy_raw(param_env.and(self))
+        self.is_trivially_pure_clone_copy() || tcx_at.is_copy_raw(param_env.and(self))
     }
 
     /// Checks whether values of this type `T` have a size known at
index f08c6405af17f2d8fc12236c71b848e66576a3a3..dca9a63120c32f0100852b0982afa25df97e7447 100644 (file)
@@ -2,7 +2,7 @@
 
 use crate::build::CFG;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 
 impl<'tcx> CFG<'tcx> {
     crate fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
@@ -73,7 +73,7 @@ impl<'tcx> CFG<'tcx> {
             Rvalue::Use(Operand::Constant(Box::new(Constant {
                 span: source_info.span,
                 user_ty: None,
-                literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(),
+                literal: ConstantKind::from_zero_sized(tcx.types.unit),
             }))),
         );
     }
index 79ac09d523d079f55b7f5b4c6429a2b6d463d334..0c0b0f2bd05affc985dad8dd83c21e488da36c4c 100644 (file)
@@ -1,6 +1,7 @@
 //! See docs in build/expr/mod.rs
 
 use crate::build::Builder;
+use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::CanonicalUserTypeAnnotation;
@@ -26,8 +27,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 assert_eq!(literal.ty(), ty);
                 Constant { span, user_ty, literal: literal.into() }
             }
-            ExprKind::StaticRef { literal, .. } => {
-                Constant { span, user_ty: None, literal: literal.into() }
+            ExprKind::StaticRef { alloc_id, ty, .. } => {
+                let const_val =
+                    ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &this.tcx));
+                let literal = ConstantKind::Val(const_val, ty);
+
+                Constant { span, user_ty: None, literal }
             }
             ExprKind::ConstBlock { value } => {
                 Constant { span: span, user_ty: None, literal: value.into() }
index c706e6ef1d4664eacb472ce3f01c0a2577d20f9c..9c7c7203f47de83de2cc5f859d159e190ffdcfb7 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_index::vec::Idx;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
-use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
+use rustc_middle::ty::CanonicalUserTypeAnnotation;
 use std::iter;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -107,7 +107,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     Constant {
                         span: expr_span,
                         user_ty: None,
-                        literal: ty::Const::from_bool(this.tcx, true).into(),
+                        literal: ConstantKind::from_bool(this.tcx, true),
                     },
                 );
 
@@ -118,7 +118,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     Constant {
                         span: expr_span,
                         user_ty: None,
-                        literal: ty::Const::from_bool(this.tcx, false).into(),
+                        literal: ConstantKind::from_bool(this.tcx, false),
                     },
                 );
 
@@ -183,8 +183,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         span: expr_span,
                         user_ty: None,
                         literal: match op {
-                            LogicalOp::And => ty::Const::from_bool(this.tcx, false).into(),
-                            LogicalOp::Or => ty::Const::from_bool(this.tcx, true).into(),
+                            LogicalOp::And => ConstantKind::from_bool(this.tcx, false),
+                            LogicalOp::Or => ConstantKind::from_bool(this.tcx, true),
                         },
                     },
                 );
index fd5914460140a84044acf8c62b889c51d56a0f07..3516eca1c1469663a2c7c2b83cde4fc2a75d71f2 100644 (file)
@@ -54,7 +54,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             Constant {
                 span: source_info.span,
                 user_ty: None,
-                literal: ty::Const::from_usize(self.tcx, value).into(),
+                literal: ConstantKind::from_usize(self.tcx, value),
             },
         );
         temp
index 651edc827c320310775024274d9f62a0706425a9..dc11c76e07b237a1c8443a09986ed5f5c488c62a 100644 (file)
@@ -8,7 +8,6 @@
 use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::middle::region;
-use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
 use rustc_middle::thir::*;
 use rustc_middle::ty::adjustment::{
@@ -570,6 +569,9 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
 
             hir::ExprKind::ConstBlock(ref anon_const) => {
                 let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
+
+                // FIXME Do we want to use `from_inline_const` once valtrees
+                // are introduced? This would create `ValTree`s that will never be used...
                 let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
 
                 ExprKind::ConstBlock { value }
@@ -941,15 +943,8 @@ fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKi
                 let kind = if self.tcx.is_thread_local_static(id) {
                     ExprKind::ThreadLocalRef(id)
                 } else {
-                    let ptr = self.tcx.create_static_alloc(id);
-                    ExprKind::StaticRef {
-                        literal: ty::Const::from_scalar(
-                            self.tcx,
-                            Scalar::from_pointer(ptr.into(), &self.tcx),
-                            ty,
-                        ),
-                        def_id: id,
-                    }
+                    let alloc_id = self.tcx.create_static_alloc(id);
+                    ExprKind::StaticRef { alloc_id, ty, def_id: id }
                 };
                 ExprKind::Deref {
                     arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }),
index 27a6b5beb627cb2c0360ea67a899b9194d2fe365..c94da838680e075cc4c2c049fe6bf3886b229ce4 100644 (file)
@@ -7,7 +7,8 @@
 use rustc_arena::TypedArena;
 use rustc_ast::Mutability;
 use rustc_errors::{
-    error_code, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+    error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
+    ErrorGuaranteed,
 };
 use rustc_hir as hir;
 use rustc_hir::def::*;
@@ -20,7 +21,7 @@
 };
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
-use rustc_span::{DesugaringKind, ExpnKind, Span};
+use rustc_span::{BytePos, DesugaringKind, ExpnKind, MultiSpan, Span};
 
 crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
     let body_id = match def_id.as_local() {
@@ -64,7 +65,9 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         intravisit::walk_expr(self, ex);
         match &ex.kind {
-            hir::ExprKind::Match(scrut, arms, source) => self.check_match(scrut, arms, *source),
+            hir::ExprKind::Match(scrut, arms, source) => {
+                self.check_match(scrut, arms, *source, ex.span)
+            }
             hir::ExprKind::Let(hir::Let { pat, init, span, .. }) => {
                 self.check_let(pat, init, *span)
             }
@@ -163,6 +166,7 @@ fn check_match(
         scrut: &hir::Expr<'_>,
         hir_arms: &'tcx [hir::Arm<'tcx>],
         source: hir::MatchSource,
+        expr_span: Span,
     ) {
         let mut cx = self.new_cx(scrut.hir_id);
 
@@ -208,7 +212,6 @@ fn check_match(
         }
 
         // Check if the match is exhaustive.
-        let is_empty_match = arms.is_empty();
         let witnesses = report.non_exhaustiveness_witnesses;
         if !witnesses.is_empty() {
             if source == hir::MatchSource::ForLoopDesugar && hir_arms.len() == 2 {
@@ -216,7 +219,7 @@ fn check_match(
                 let pat = hir_arms[1].pat.for_loop_some().unwrap();
                 self.check_irrefutable(pat, "`for` loop binding", None);
             } else {
-                non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match);
+                non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, hir_arms, expr_span);
             }
         }
     }
@@ -239,6 +242,9 @@ fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>
         }
 
         let joined_patterns = joined_uncovered_patterns(&cx, &witnesses);
+
+        let mut bindings = vec![];
+
         let mut err = struct_span_err!(
             self.tcx.sess,
             pat.span,
@@ -255,6 +261,16 @@ fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>
                 false
             }
             _ => {
+                pat.walk(&mut |pat: &hir::Pat<'_>| {
+                    match pat.kind {
+                        hir::PatKind::Binding(_, _, ident, _) => {
+                            bindings.push(ident);
+                        }
+                        _ => {}
+                    }
+                    true
+                });
+
                 err.span_label(pat.span, pattern_not_covered_label(&witnesses, &joined_patterns));
                 true
             }
@@ -265,13 +281,71 @@ fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>
                 "`let` bindings require an \"irrefutable pattern\", like a `struct` or \
                  an `enum` with only one variant",
             );
-            if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                err.span_suggestion(
-                    span,
-                    "you might want to use `if let` to ignore the variant that isn't matched",
-                    format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]),
+            if self.tcx.sess.source_map().span_to_snippet(span).is_ok() {
+                let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1));
+                let start_span = span.shrink_to_lo();
+                let end_span = semi_span.shrink_to_lo();
+                err.multipart_suggestion(
+                    &format!(
+                        "you might want to use `if let` to ignore the variant{} that {} matched",
+                        pluralize!(witnesses.len()),
+                        match witnesses.len() {
+                            1 => "isn't",
+                            _ => "aren't",
+                        },
+                    ),
+                    vec![
+                        match &bindings[..] {
+                            [] => (start_span, "if ".to_string()),
+                            [binding] => (start_span, format!("let {} = if ", binding)),
+                            bindings => (
+                                start_span,
+                                format!(
+                                    "let ({}) = if ",
+                                    bindings
+                                        .iter()
+                                        .map(|ident| ident.to_string())
+                                        .collect::<Vec<_>>()
+                                        .join(", ")
+                                ),
+                            ),
+                        },
+                        match &bindings[..] {
+                            [] => (semi_span, " { todo!() }".to_string()),
+                            [binding] => {
+                                (end_span, format!(" {{ {} }} else {{ todo!() }}", binding))
+                            }
+                            bindings => (
+                                end_span,
+                                format!(
+                                    " {{ ({}) }} else {{ todo!() }}",
+                                    bindings
+                                        .iter()
+                                        .map(|ident| ident.to_string())
+                                        .collect::<Vec<_>>()
+                                        .join(", ")
+                                ),
+                            ),
+                        },
+                    ],
                     Applicability::HasPlaceholders,
                 );
+                if !bindings.is_empty() && cx.tcx.sess.is_nightly_build() {
+                    err.span_suggestion_verbose(
+                        semi_span.shrink_to_lo(),
+                        &format!(
+                            "alternatively, on nightly, you might want to use \
+                             `#![feature(let_else)]` to handle the variant{} that {} matched",
+                            pluralize!(witnesses.len()),
+                            match witnesses.len() {
+                                1 => "isn't",
+                                _ => "aren't",
+                            },
+                        ),
+                        " else { todo!() }".to_string(),
+                        Applicability::HasPlaceholders,
+                    );
+                }
             }
             err.note(
                 "for more information, visit \
@@ -334,7 +408,7 @@ fn check_for_bindings_named_same_as_variants(
                     let ty_path = cx.tcx.def_path_str(edef.did);
                     let mut err = lint.build(&format!(
                         "pattern binding `{}` is named the same as one \
-                                        of the variants of the type `{}`",
+                         of the variants of the type `{}`",
                         ident, ty_path
                     ));
                     err.code(error_code!(E0170));
@@ -494,8 +568,10 @@ fn non_exhaustive_match<'p, 'tcx>(
     scrut_ty: Ty<'tcx>,
     sp: Span,
     witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
-    is_empty_match: bool,
+    arms: &[hir::Arm<'tcx>],
+    expr_span: Span,
 ) {
+    let is_empty_match = arms.is_empty();
     let non_empty_enum = match scrut_ty.kind() {
         ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(),
         _ => false,
@@ -503,12 +579,15 @@ fn non_exhaustive_match<'p, 'tcx>(
     // In the case of an empty match, replace the '`_` not covered' diagnostic with something more
     // informative.
     let mut err;
+    let pattern;
+    let mut patterns_len = 0;
     if is_empty_match && !non_empty_enum {
         err = create_e0004(
             cx.tcx.sess,
             sp,
             format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
         );
+        pattern = "_".to_string();
     } else {
         let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
         err = create_e0004(
@@ -517,6 +596,16 @@ fn non_exhaustive_match<'p, 'tcx>(
             format!("non-exhaustive patterns: {} not covered", joined_patterns),
         );
         err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
+        patterns_len = witnesses.len();
+        pattern = if witnesses.len() < 4 {
+            witnesses
+                .iter()
+                .map(|witness| witness.to_pat(cx).to_string())
+                .collect::<Vec<String>>()
+                .join(" | ")
+        } else {
+            "_".to_string()
+        };
     };
 
     let is_variant_list_non_exhaustive = match scrut_ty.kind() {
@@ -525,10 +614,6 @@ fn non_exhaustive_match<'p, 'tcx>(
     };
 
     adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
-    err.help(
-        "ensure that all possible cases are being handled, \
-              possibly by adding wildcards or more match arms",
-    );
     err.note(&format!(
         "the matched value is of type `{}`{}",
         scrut_ty,
@@ -540,14 +625,14 @@ fn non_exhaustive_match<'p, 'tcx>(
         && matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
     {
         err.note(&format!(
-            "`{}` does not have a fixed maximum value, \
-                so a wildcard `_` is necessary to match exhaustively",
+            "`{}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
+             exhaustively",
             scrut_ty,
         ));
         if cx.tcx.sess.is_nightly_build() {
             err.help(&format!(
-                "add `#![feature(precise_pointer_size_matching)]` \
-                    to the crate attributes to enable precise `{}` matching",
+                "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
+                 enable precise `{}` matching",
                 scrut_ty,
             ));
         }
@@ -557,6 +642,84 @@ fn non_exhaustive_match<'p, 'tcx>(
             err.note("references are always considered inhabited");
         }
     }
+
+    let mut suggestion = None;
+    let sm = cx.tcx.sess.source_map();
+    match arms {
+        [] if sp.ctxt() == expr_span.ctxt() => {
+            // Get the span for the empty match body `{}`.
+            let (indentation, more) = if let Some(snippet) = sm.indentation_before(sp) {
+                (format!("\n{}", snippet), "    ")
+            } else {
+                (" ".to_string(), "")
+            };
+            suggestion = Some((
+                sp.shrink_to_hi().with_hi(expr_span.hi()),
+                format!(
+                    " {{{indentation}{more}{pattern} => todo!(),{indentation}}}",
+                    indentation = indentation,
+                    more = more,
+                    pattern = pattern,
+                ),
+            ));
+        }
+        [only] => {
+            let pre_indentation = if let (Some(snippet), true) = (
+                sm.indentation_before(only.span),
+                sm.is_multiline(sp.shrink_to_hi().with_hi(only.span.lo())),
+            ) {
+                format!("\n{}", snippet)
+            } else {
+                " ".to_string()
+            };
+            let comma = if matches!(only.body.kind, hir::ExprKind::Block(..)) { "" } else { "," };
+            suggestion = Some((
+                only.span.shrink_to_hi(),
+                format!("{}{}{} => todo!()", comma, pre_indentation, pattern),
+            ));
+        }
+        [.., prev, last] if prev.span.ctxt() == last.span.ctxt() => {
+            if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) {
+                let comma =
+                    if matches!(last.body.kind, hir::ExprKind::Block(..)) { "" } else { "," };
+                suggestion = Some((
+                    last.span.shrink_to_hi(),
+                    format!(
+                        "{}{}{} => todo!()",
+                        comma,
+                        snippet.strip_prefix(",").unwrap_or(&snippet),
+                        pattern
+                    ),
+                ));
+            }
+        }
+        _ => {}
+    }
+
+    let msg = format!(
+        "ensure that all possible cases are being handled by adding a match arm with a wildcard \
+         pattern{}{}",
+        if patterns_len > 1 && patterns_len < 4 && suggestion.is_some() {
+            ", a match arm with multiple or-patterns"
+        } else {
+            // we are either not suggesting anything, or suggesting `_`
+            ""
+        },
+        match patterns_len {
+            // non-exhaustive enum case
+            0 if suggestion.is_some() => " as shown",
+            0 => "",
+            1 if suggestion.is_some() => " or an explicit pattern as shown",
+            1 => " or an explicit pattern",
+            _ if suggestion.is_some() => " as shown, or multiple match arms",
+            _ => " or multiple match arms",
+        },
+    );
+    if let Some((span, sugg)) = suggestion {
+        err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+    } else {
+        err.help(&msg);
+    }
     err.emit();
 }
 
@@ -597,15 +760,27 @@ fn adt_defined_here<'p, 'tcx>(
 ) {
     let ty = ty.peel_refs();
     if let ty::Adt(def, _) = ty.kind() {
-        if let Some(sp) = cx.tcx.hir().span_if_local(def.did) {
-            err.span_label(sp, format!("`{}` defined here", ty));
-        }
-
-        if witnesses.len() < 4 {
+        let mut spans = vec![];
+        if witnesses.len() < 5 {
             for sp in maybe_point_at_variant(cx, def, witnesses.iter()) {
-                err.span_label(sp, "not covered");
+                spans.push(sp);
             }
         }
+        let def_span = cx
+            .tcx
+            .hir()
+            .get_if_local(def.did)
+            .and_then(|node| node.ident())
+            .map(|ident| ident.span)
+            .unwrap_or_else(|| cx.tcx.def_span(def.did));
+        let mut span: MultiSpan =
+            if spans.is_empty() { def_span.into() } else { spans.clone().into() };
+
+        span.push_span_label(def_span, String::new());
+        for pat in spans {
+            span.push_span_label(pat, "not covered".to_string());
+        }
+        err.span_note(span, &format!("`{}` defined here", ty));
     }
 }
 
index f2b341593826b3e0e3dbd9705e023d9452611f6f..1af789b4885e61c276d9f60106952dfb570b7c40 100644 (file)
@@ -37,8 +37,8 @@ pub struct InitIndex {
 }
 
 impl MoveOutIndex {
-    pub fn move_path_index(&self, move_data: &MoveData<'_>) -> MovePathIndex {
-        move_data.moves[*self].path
+    pub fn move_path_index(self, move_data: &MoveData<'_>) -> MovePathIndex {
+        move_data.moves[self].path
     }
 }
 
@@ -338,8 +338,8 @@ pub fn find_local(&self, local: Local) -> MovePathIndex {
     /// `MovePathIndex`es.
     pub fn iter_locals_enumerated(
         &self,
-    ) -> impl DoubleEndedIterator<Item = (Local, &MovePathIndex)> + ExactSizeIterator {
-        self.locals.iter_enumerated()
+    ) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> + ExactSizeIterator + '_ {
+        self.locals.iter_enumerated().map(|(l, &idx)| (l, idx))
     }
 }
 
index 7b000e2e1d22645303479956ce3b6cbf56f982c8..4c1a7eaf6f03b83c6af0c2e6b0c82845cb2074ab 100644 (file)
@@ -7,7 +7,7 @@ edition = "2021"
 doctest = false
 
 [dependencies]
-itertools = "0.10"
+itertools = "0.10.1"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 tracing = "0.1"
 rustc_ast = { path = "../rustc_ast" }
index eaf3f19bff196990bfa5b054c25db61236f487e2..87b9244c068edd7044aa68297c4748a9245a00eb 100644 (file)
@@ -127,7 +127,10 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                 &AggregateKind::Closure(def_id, _) | &AggregateKind::Generator(def_id, _, _) => {
                     let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
                         self.tcx.unsafety_check_result(def_id.expect_local());
-                    self.register_violations(violations, used_unsafe_blocks);
+                    self.register_violations(
+                        violations,
+                        used_unsafe_blocks.iter().map(|(&h, &d)| (h, d)),
+                    );
                 }
             },
             _ => {}
@@ -261,7 +264,7 @@ fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViola
     fn register_violations<'a>(
         &mut self,
         violations: impl IntoIterator<Item = &'a UnsafetyViolation>,
-        new_used_unsafe_blocks: impl IntoIterator<Item = (&'a HirId, &'a UsedUnsafeBlockData)>,
+        new_used_unsafe_blocks: impl IntoIterator<Item = (HirId, UsedUnsafeBlockData)>,
     ) {
         use UsedUnsafeBlockData::{AllAllowedInUnsafeFn, SomeDisallowedInUnsafeFn};
 
@@ -318,7 +321,7 @@ fn register_violations<'a>(
 
         new_used_unsafe_blocks
             .into_iter()
-            .for_each(|(&hir_id, &usage_data)| update_entry(self, hir_id, usage_data));
+            .for_each(|(hir_id, usage_data)| update_entry(self, hir_id, usage_data));
     }
     fn check_mut_borrowing_layout_constrained_field(
         &mut self,
index d849bc408fab47caebac145afd4a6cdcb9ba01d0..34c539f319194761c161ca96b6e6c372a9a3e8ec 100644 (file)
@@ -31,8 +31,8 @@
 use crate::MirPass;
 use rustc_const_eval::const_eval::ConstEvalErr;
 use rustc_const_eval::interpret::{
-    self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy,
-    Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy,
+    self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame,
+    ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy,
     Operand as InterpOperand, PlaceTy, Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind,
 };
 
@@ -274,7 +274,7 @@ fn access_local_mut<'a>(
     fn before_access_global(
         _memory_extra: &(),
         _alloc_id: AllocId,
-        allocation: &Allocation<Self::PointerTag, Self::AllocExtra>,
+        alloc: ConstAllocation<'tcx, Self::PointerTag, Self::AllocExtra>,
         _static_def_id: Option<DefId>,
         is_write: bool,
     ) -> InterpResult<'tcx> {
@@ -283,7 +283,7 @@ fn before_access_global(
         }
         // If the static allocation is mutable, then we can't const prop it as its content
         // might be different at runtime.
-        if allocation.mutability == Mutability::Mut {
+        if alloc.inner().mutability == Mutability::Mut {
             throw_machine_stop_str!("can't access mutable globals in ConstProp");
         }
 
index 55f7e70db8fd30f8a2dca6382950cfb88c3225a2..6bb7e676e851c6fa234c27c8768bbb4b963b798c 100644 (file)
@@ -48,7 +48,7 @@ pub fn from_mir(mir_body: &mir::Body<'_>) -> Self {
                 let mut bcb_successors = Vec::new();
                 for successor in
                     bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind)
-                        .filter_map(|&successor_bb| bb_to_bcb[successor_bb])
+                        .filter_map(|successor_bb| bb_to_bcb[successor_bb])
                 {
                     if !seen[successor] {
                         seen[successor] = true;
@@ -483,7 +483,7 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 fn bcb_filtered_successors<'a, 'tcx>(
     body: &'tcx &'a mir::Body<'tcx>,
     term_kind: &'tcx TerminatorKind<'tcx>,
-) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a> {
+) -> Box<dyn Iterator<Item = BasicBlock> + 'a> {
     let mut successors = term_kind.successors();
     Box::new(
         match &term_kind {
@@ -494,9 +494,8 @@ fn bcb_filtered_successors<'a, 'tcx>(
             // `next().into_iter()`) into the `mir::Successors` aliased type.
             _ => successors.next().into_iter().chain(&[]),
         }
-        .filter(move |&&successor| {
-            body[successor].terminator().kind != TerminatorKind::Unreachable
-        }),
+        .copied()
+        .filter(move |&successor| body[successor].terminator().kind != TerminatorKind::Unreachable),
     )
 }
 
@@ -695,7 +694,7 @@ pub struct ShortCircuitPreorder<
     F: Fn(
         &'tcx &'a mir::Body<'tcx>,
         &'tcx TerminatorKind<'tcx>,
-    ) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
+    ) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
 > {
     body: &'tcx &'a mir::Body<'tcx>,
     visited: BitSet<BasicBlock>,
@@ -709,7 +708,7 @@ impl<
     F: Fn(
         &'tcx &'a mir::Body<'tcx>,
         &'tcx TerminatorKind<'tcx>,
-    ) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
+    ) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
 > ShortCircuitPreorder<'a, 'tcx, F>
 {
     pub fn new(
@@ -733,7 +732,7 @@ impl<
     F: Fn(
         &'tcx &'a mir::Body<'tcx>,
         &'tcx TerminatorKind<'tcx>,
-    ) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
+    ) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
 > Iterator for ShortCircuitPreorder<'a, 'tcx, F>
 {
     type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
index 385fcc43496e3695d635d57eac0ff712939defa4..d1c4a4b21d0a2e3f4fe886ab5738053c2022c71a 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_hir::Mutability;
 use rustc_middle::mir::{
     BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo,
-    StatementKind, UnOp,
+    Statement, StatementKind, Terminator, TerminatorKind, UnOp,
 };
 use rustc_middle::ty::{self, TyCtxt};
 
@@ -29,6 +29,11 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                     _ => {}
                 }
             }
+
+            ctx.combine_primitive_clone(
+                &mut block.terminator.as_mut().unwrap(),
+                &mut block.statements,
+            );
         }
     }
 }
@@ -130,4 +135,70 @@ fn combine_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
             }
         }
     }
+
+    fn combine_primitive_clone(
+        &self,
+        terminator: &mut Terminator<'tcx>,
+        statements: &mut Vec<Statement<'tcx>>,
+    ) {
+        let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind
+        else { return };
+
+        // It's definitely not a clone if there are multiple arguments
+        if args.len() != 1 {
+            return;
+        }
+
+        let Some((destination_place, destination_block)) = *destination
+        else { return };
+
+        // Only bother looking more if it's easy to know what we're calling
+        let Some((fn_def_id, fn_substs)) = func.const_fn_def()
+        else { return };
+
+        // Clone needs one subst, so we can cheaply rule out other stuff
+        if fn_substs.len() != 1 {
+            return;
+        }
+
+        // These types are easily available from locals, so check that before
+        // doing DefId lookups to figure out what we're actually calling.
+        let arg_ty = args[0].ty(self.local_decls, self.tcx);
+
+        let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind()
+        else { return };
+
+        if !inner_ty.is_trivially_pure_clone_copy() {
+            return;
+        }
+
+        let trait_def_id = self.tcx.trait_of_item(fn_def_id);
+        if trait_def_id.is_none() || trait_def_id != self.tcx.lang_items().clone_trait() {
+            return;
+        }
+
+        if !self.tcx.consider_optimizing(|| {
+            format!(
+                "InstCombine - Call: {:?} SourceInfo: {:?}",
+                (fn_def_id, fn_substs),
+                terminator.source_info
+            )
+        }) {
+            return;
+        }
+
+        let Some(arg_place) = args.pop().unwrap().place()
+        else { return };
+
+        statements.push(Statement {
+            source_info: terminator.source_info,
+            kind: StatementKind::Assign(box (
+                destination_place,
+                Rvalue::Use(Operand::Copy(
+                    arg_place.project_deeper(&[ProjectionElem::Deref], self.tcx),
+                )),
+            )),
+        });
+        terminator.kind = TerminatorKind::Goto { target: destination_block };
+    }
 }
index d5507fcc78cad8016befb447a1bad1c52fa23e39..abd75c20524e9640fe6ceb652721855cce0ada3f 100644 (file)
@@ -707,7 +707,7 @@ fn statement_equality(
     ) -> StatementEquality {
         let helper = |rhs: &Rvalue<'tcx>,
                       place: &Place<'tcx>,
-                      variant_index: &VariantIdx,
+                      variant_index: VariantIdx,
                       switch_value: u128,
                       side_to_choose| {
             let place_type = place.ty(self.body, self.tcx).ty;
@@ -717,7 +717,7 @@ fn statement_equality(
             };
             // We need to make sure that the switch value that targets the bb with
             // SetDiscriminant is the same as the variant discriminant.
-            let variant_discr = adt.discriminant_for_variant(self.tcx, *variant_index).val;
+            let variant_discr = adt.discriminant_for_variant(self.tcx, variant_index).val;
             if variant_discr != switch_value {
                 trace!(
                     "NO: variant discriminant {} does not equal switch value {}",
@@ -726,7 +726,7 @@ fn statement_equality(
                 );
                 return StatementEquality::NotEqual;
             }
-            let variant_is_fieldless = adt.variants[*variant_index].fields.is_empty();
+            let variant_is_fieldless = adt.variants[variant_index].fields.is_empty();
             if !variant_is_fieldless {
                 trace!("NO: variant {:?} was not fieldless", variant_index);
                 return StatementEquality::NotEqual;
@@ -753,7 +753,7 @@ fn statement_equality(
             // check for case A
             (
                 StatementKind::Assign(box (_, rhs)),
-                StatementKind::SetDiscriminant { place, variant_index },
+                &StatementKind::SetDiscriminant { ref place, variant_index },
             ) if y_target_and_value.value.is_some() => {
                 // choose basic block of x, as that has the assign
                 helper(
@@ -765,8 +765,8 @@ fn statement_equality(
                 )
             }
             (
-                StatementKind::SetDiscriminant { place, variant_index },
-                StatementKind::Assign(box (_, rhs)),
+                &StatementKind::SetDiscriminant { ref place, variant_index },
+                &StatementKind::Assign(box (_, ref rhs)),
             ) if x_target_and_value.value.is_some() => {
                 // choose basic block of y, as that has the assign
                 helper(
index 7133724d07d95c6639b922ce61ab40cd8fb3ebbf..bd196f1187966db729fe37b77b544bfa79e6b621 100644 (file)
@@ -65,7 +65,7 @@ fn variant_discriminants<'tcx>(
         Variants::Multiple { variants, .. } => variants
             .iter_enumerated()
             .filter_map(|(idx, layout)| {
-                (layout.abi != Abi::Uninhabited)
+                (layout.abi() != Abi::Uninhabited)
                     .then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
             })
             .collect(),
index 819cffd3a9bf1dc0e0acccc53c537e08835d3f6c..ed771534c4c4c2c152252541c294998261dcc65d 100644 (file)
@@ -401,7 +401,7 @@ fn collect_items_rec<'tcx>(
             recursion_depth_reset = None;
 
             if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
-                for &id in alloc.relocations().values() {
+                for &id in alloc.inner().relocations().values() {
                     collect_miri(tcx, id, &mut neighbors);
                 }
             }
@@ -1370,7 +1370,7 @@ fn collect_miri<'tcx>(
         }
         GlobalAlloc::Memory(alloc) => {
             trace!("collecting {:?} with {:#?}", alloc_id, alloc);
-            for &inner in alloc.relocations().values() {
+            for &inner in alloc.inner().relocations().values() {
                 rustc_data_structures::stack::ensure_sufficient_stack(|| {
                     collect_miri(tcx, inner, output);
                 });
@@ -1405,7 +1405,7 @@ fn collect_const_value<'tcx>(
     match value {
         ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => collect_miri(tcx, ptr.provenance, output),
         ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => {
-            for &id in alloc.relocations().values() {
+            for &id in alloc.inner().relocations().values() {
                 collect_miri(tcx, id, output);
             }
         }
index df865d77b9bb4cc5d40a66adc61c72a4f305ebfc..b993d48c995b4748ec20c05d3a1b148215e8b108 100644 (file)
@@ -20,7 +20,6 @@
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult};
 use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
 use rustc_session::lint::BuiltinLintDiagnostics;
-use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Pos};
@@ -2712,8 +2711,7 @@ pub(super) fn parse_struct_fields(
         let mut async_block_err = |e: &mut Diagnostic, span: Span| {
             recover_async = true;
             e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
-            e.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
-            e.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+            e.help_use_latest_edition();
         };
 
         while self.token != token::CloseDelim(close_delim) {
index ec89301c1e22edf17358721a99c63179ee207dcf..122fe10e80f8fb331ce3aab4cae7a15c923ec420 100644 (file)
@@ -14,7 +14,7 @@
 use rustc_ast::{MacArgs, MacCall, MacDelimiter};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{struct_span_err, Applicability, PResult, StashKey};
-use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
+use rustc_span::edition::Edition;
 use rustc_span::lev_distance::lev_distance;
 use rustc_span::source_map::{self, Span};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -2112,8 +2112,7 @@ fn ban_async_in_2015(&self, span: Span) {
             let diag = self.diagnostic();
             struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015")
                 .span_label(span, "to use `async fn`, switch to Rust 2018 or later")
-                .help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION))
-                .note("for more on editions, read https://doc.rust-lang.org/edition-guide")
+                .help_use_latest_edition()
                 .emit();
         }
     }
index d94ad7ba71a9c63a19560b02cde7e77b2a0d1409..01b12eec628ec074877dc828802fdd3fea137f7b 100644 (file)
@@ -4,7 +4,7 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
+use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, struct_span_err, Applicability};
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@@ -178,34 +178,7 @@ fn check_attributes(
                 check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
             }
 
-            // Warn on useless empty attributes.
-            if matches!(
-                attr.name_or_empty(),
-                sym::macro_use
-                    | sym::allow
-                    | sym::warn
-                    | sym::deny
-                    | sym::forbid
-                    | sym::feature
-                    | sym::repr
-                    | sym::target_feature
-            ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
-            {
-                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    lint.build("unused attribute")
-                        .span_suggestion(
-                            attr.span,
-                            "remove this attribute",
-                            String::new(),
-                            Applicability::MachineApplicable,
-                        )
-                        .note(&format!(
-                            "attribute `{}` with an empty list has no effect",
-                            attr.name_or_empty()
-                        ))
-                        .emit();
-                });
-            }
+            self.check_unused_attribute(hir_id, attr)
         }
 
         if !is_valid {
@@ -1372,7 +1345,7 @@ fn check_rustc_legacy_const_generics(
         target: Target,
         item: Option<ItemLike<'_>>,
     ) -> bool {
-        let is_function = matches!(target, Target::Fn | Target::Method(..));
+        let is_function = matches!(target, Target::Fn);
         if !is_function {
             self.tcx
                 .sess
@@ -1969,6 +1942,55 @@ fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target
             });
         }
     }
+
+    fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
+        // Warn on useless empty attributes.
+        let note = if matches!(
+            attr.name_or_empty(),
+            sym::macro_use
+                | sym::allow
+                | sym::expect
+                | sym::warn
+                | sym::deny
+                | sym::forbid
+                | sym::feature
+                | sym::repr
+                | sym::target_feature
+        ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
+        {
+            format!(
+                "attribute `{}` with an empty list has no effect",
+                attr.name_or_empty()
+            )
+        } else if matches!(
+                attr.name_or_empty(),
+                sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
+            ) && let Some(meta) = attr.meta_item_list()
+            && meta.len() == 1
+            && let Some(item) = meta[0].meta_item()
+            && let MetaItemKind::NameValue(_) = &item.kind
+            && item.path == sym::reason
+        {
+            format!(
+                "attribute `{}` without any lints has no effect",
+                attr.name_or_empty()
+            )
+        } else {
+            return;
+        };
+
+        self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+            lint.build("unused attribute")
+                .span_suggestion(
+                    attr.span,
+                    "remove this attribute",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                )
+                .note(&note)
+                .emit();
+        });
+    }
 }
 
 impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
index 37a9f0ecd8c1867956ad0fe13e4cdf249047bce8..f36a1f61aaccb03f02d693a14480a9491567dce2 100644 (file)
@@ -202,7 +202,7 @@ fn annotate<F>(
                     self.tcx.sess,
                     *span,
                     E0549,
-                    "rustc_deprecated attribute must be paired with \
+                    "deprecated attribute must be paired with \
                     either stable or unstable attribute"
                 )
                 .emit();
index b56cb86a18c86f30cd2697d4b0ffbae32c57e6be..fd1c0239b596511b011a76acd04436b0d90ff95c 100644 (file)
@@ -852,7 +852,7 @@ fn generics(&mut self) -> &mut Self {
                         self.visit(self.ev.tcx.type_of(param.def_id));
                     }
                 }
-                GenericParamDefKind::Const { has_default, .. } => {
+                GenericParamDefKind::Const { has_default } => {
                     self.visit(self.ev.tcx.type_of(param.def_id));
                     if has_default {
                         self.visit(self.ev.tcx.const_param_default(param.def_id));
index 5f8aec80bccc7a46d5c09dbffa84d93b0798dd85..1d36ff059de81eb89456660854facc29f1888a64 100644 (file)
@@ -1072,6 +1072,7 @@ fn fill_well_known_names(&mut self) {
         // NOTE: This should be kept in sync with `default_configuration` and
         // `fill_well_known_values`
         const WELL_KNOWN_NAMES: &[Symbol] = &[
+            // rustc
             sym::unix,
             sym::windows,
             sym::target_os,
@@ -1091,9 +1092,12 @@ fn fill_well_known_names(&mut self) {
             sym::debug_assertions,
             sym::proc_macro,
             sym::test,
+            sym::feature,
+            // rustdoc
             sym::doc,
             sym::doctest,
-            sym::feature,
+            // miri
+            sym::miri,
         ];
 
         // We only insert well-known names if `names()` was activated
@@ -1128,13 +1132,14 @@ fn fill_well_known_values(&mut self) {
 
         // No-values
         for name in [
+            sym::doc,
+            sym::miri,
             sym::unix,
-            sym::windows,
-            sym::debug_assertions,
-            sym::proc_macro,
             sym::test,
-            sym::doc,
             sym::doctest,
+            sym::windows,
+            sym::proc_macro,
+            sym::debug_assertions,
             sym::target_thread_local,
         ] {
             self.values_valid.entry(name).or_default();
@@ -2628,11 +2633,10 @@ fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Opt
         name => early_error(
             efmt,
             &format!(
-                "argument to `unpretty` must be one of `normal`, \
-                            `expanded`, `identified`, `expanded,identified`, \
-                            `expanded,hygiene`, `everybody_loops`, \
+                "argument to `unpretty` must be one of `normal`, `identified`, \
+                            `expanded`, `expanded,identified`, `expanded,hygiene`, \
                             `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
-                            `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
+                            `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {}",
                 name
             ),
         ),
index 38ddb841d96566721298cda2bb69d3913ff4a604..d34a3360a83e215a0621fa36f49742fac19e6454 100644 (file)
@@ -98,7 +98,26 @@ pub fn feature_err_issue<'a>(
     explain: &str,
 ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
     let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658));
+    add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
+    err
+}
+
+/// Adds the diagnostics for a feature to an existing error.
+pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) {
+    add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language);
+}
 
+/// Adds the diagnostics for a feature to an existing error.
+///
+/// This variant allows you to control whether it is a library or language feature.
+/// Almost always, you want to use this for a language feature. If so, prefer
+/// `add_feature_diagnostics`.
+pub fn add_feature_diagnostics_for_issue<'a>(
+    err: &mut Diagnostic,
+    sess: &'a ParseSess,
+    feature: Symbol,
+    issue: GateIssue,
+) {
     if let Some(n) = find_feature_issue(feature, issue) {
         err.note(&format!(
             "see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
@@ -110,8 +129,6 @@ pub fn feature_err_issue<'a>(
     if sess.unstable_features.is_nightly_build() {
         err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
     }
-
-    err
 }
 
 /// Info about a parsing session.
index 56da7c437280472bab4d7a0120fe7d6b21ad4255..6d1b36796d869fec88463521d022bc76dea66489 100644 (file)
@@ -27,8 +27,8 @@ pub fn new(x: usize) -> CrateNum {
     }
 
     #[inline]
-    pub fn as_def_id(&self) -> DefId {
-        DefId { krate: *self, index: CRATE_DEF_INDEX }
+    pub fn as_def_id(self) -> DefId {
+        DefId { krate: self, index: CRATE_DEF_INDEX }
     }
 }
 
@@ -222,6 +222,7 @@ impl<D: Decoder> Decodable<D> for DefIndex {
 // On below-64 bit systems we can simply use the derived `Hash` impl
 #[cfg_attr(not(target_pointer_width = "64"), derive(Hash))]
 #[repr(C)]
+#[rustc_pass_by_value]
 // We guarantee field order. Note that the order is essential here, see below why.
 pub struct DefId {
     // cfg-ing the order of fields so that the `DefIndex` which is high entropy always ends up in
index 5fae46d5fd89b52fa313df0209012bbbc9840175..86adfa7a18cdf7f5573a7067833566d6c298c847 100644 (file)
@@ -85,10 +85,17 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     /// A unique ID associated with a macro invocation and expansion.
     pub struct LocalExpnId {
         ENCODABLE = custom
+        ORD_IMPL = custom
         DEBUG_FORMAT = "expn{}"
     }
 }
 
+// To ensure correctness of incremental compilation,
+// `LocalExpnId` must not implement `Ord` or `PartialOrd`.
+// See https://github.com/rust-lang/rust/issues/90317.
+impl !Ord for LocalExpnId {}
+impl !PartialOrd for LocalExpnId {}
+
 /// Assert that the provided `HashStableContext` is configured with the 'default'
 /// `HashingControls`. We should always have bailed out before getting to here
 /// with a non-default mode. With this check in place, we can avoid the need
index 3f44292e03425ad301d7806ef215ceea12088ef0..967eb3cc22a90e2360d0e123cc4f08594b715bb2 100644 (file)
         delay_span_bug_from_inside_query,
         deny,
         deprecated,
+        deprecated_suggestion,
         deref,
         deref_method,
         deref_mut,
         macro_export,
         macro_lifetime_matcher,
         macro_literal_matcher,
+        macro_metavar_expr,
         macro_reexport,
         macro_use,
         macro_vis_matcher,
         minnumf32,
         minnumf64,
         mips_target_feature,
+        miri,
         misc,
         mmx_reg,
         modifiers,
         test_case,
         test_removed_feature,
         test_runner,
+        test_unstable_lint,
         then_with,
         thread,
         thread_local,
index 62b5436142f5a35bafd3a418017718bd10429337..a9c41ce0c4ea4033bdfecb76bd9c261cafd5eff2 100644 (file)
@@ -633,8 +633,9 @@ fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error
                         // The `inspect` here is okay since we checked the bounds, and there are no
                         // relocations (we have an active `str` reference here). We don't use this
                         // result to affect interpreter execution.
-                        let slice =
-                            data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+                        let slice = data
+                            .inner()
+                            .inspect_with_uninit_and_ptr_outside_interpreter(start..end);
                         let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
 
                         self.push("e");
index 4ef863712983f802b793c2f87c717e08c5e39cfc..fb5e0272cc359c36e5273fa685b17eb45fcdc966 100644 (file)
@@ -10,6 +10,7 @@
 use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
 use std::str::FromStr;
 
+use rustc_data_structures::intern::Interned;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::json::{Json, ToJson};
@@ -1024,7 +1025,7 @@ pub struct VariantIdx {
 }
 
 #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub enum Variants {
+pub enum Variants<'a> {
     /// Single enum variants, structs/tuples, unions, and all non-ADTs.
     Single { index: VariantIdx },
 
@@ -1038,7 +1039,7 @@ pub enum Variants {
         tag: Scalar,
         tag_encoding: TagEncoding,
         tag_field: usize,
-        variants: IndexVec<VariantIdx, Layout>,
+        variants: IndexVec<VariantIdx, Layout<'a>>,
     },
 }
 
@@ -1146,8 +1147,8 @@ pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Sc
     }
 }
 
-#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub struct Layout {
+#[derive(PartialEq, Eq, Hash, HashStable_Generic)]
+pub struct LayoutS<'a> {
     /// Says where the fields are located within the layout.
     pub fields: FieldsShape,
 
@@ -1158,7 +1159,7 @@ pub struct Layout {
     ///
     /// To access all fields of this layout, both `fields` and the fields of the active variant
     /// must be taken into account.
-    pub variants: Variants,
+    pub variants: Variants<'a>,
 
     /// The `abi` defines how this data is passed between functions, and it defines
     /// value restrictions via `valid_range`.
@@ -1177,12 +1178,12 @@ pub struct Layout {
     pub size: Size,
 }
 
-impl Layout {
+impl<'a> LayoutS<'a> {
     pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
         let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
         let size = scalar.value.size(cx);
         let align = scalar.value.align(cx);
-        Layout {
+        LayoutS {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Primitive,
             abi: Abi::Scalar(scalar),
@@ -1193,6 +1194,59 @@ pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
     }
 }
 
+impl<'a> fmt::Debug for LayoutS<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // This is how `Layout` used to print before it become
+        // `Interned<LayoutS>`. We print it like this to avoid having to update
+        // expected output in a lot of tests.
+        f.debug_struct("Layout")
+            .field("fields", &self.fields)
+            .field("variants", &self.variants)
+            .field("abi", &self.abi)
+            .field("largest_niche", &self.largest_niche)
+            .field("align", &self.align)
+            .field("size", &self.size)
+            .finish()
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Layout<'a>(pub Interned<'a, LayoutS<'a>>);
+
+impl<'a> fmt::Debug for Layout<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // See comment on `<LayoutS as Debug>::fmt` above.
+        self.0.0.fmt(f)
+    }
+}
+
+impl<'a> Layout<'a> {
+    pub fn fields(self) -> &'a FieldsShape {
+        &self.0.0.fields
+    }
+
+    pub fn variants(self) -> &'a Variants<'a> {
+        &self.0.0.variants
+    }
+
+    pub fn abi(self) -> Abi {
+        self.0.0.abi
+    }
+
+    pub fn largest_niche(self) -> Option<Niche> {
+        self.0.0.largest_niche
+    }
+
+    pub fn align(self) -> AbiAndPrefAlign {
+        self.0.0.align
+    }
+
+    pub fn size(self) -> Size {
+        self.0.0.size
+    }
+}
+
 /// The layout of a type, alongside the type itself.
 /// Provides various type traversal APIs (e.g., recursing into fields).
 ///
@@ -1203,13 +1257,13 @@ pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
 pub struct TyAndLayout<'a, Ty> {
     pub ty: Ty,
-    pub layout: &'a Layout,
+    pub layout: Layout<'a>,
 }
 
 impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
-    type Target = &'a Layout;
-    fn deref(&self) -> &&'a Layout {
-        &self.layout
+    type Target = &'a LayoutS<'a>;
+    fn deref(&self) -> &&'a LayoutS<'a> {
+        &self.layout.0.0
     }
 }
 
index 2919743e4996fa12e9d65f7f2df4a5da3b5a7b8c..e9ef71ede51821469a6d3840fc8b26ef055de3b5 100644 (file)
@@ -8,13 +8,14 @@
 //! LLVM.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(bool_to_option)]
-#![feature(let_else)]
-#![feature(nll)]
-#![feature(never_type)]
 #![feature(associated_type_bounds)]
+#![feature(bool_to_option)]
 #![feature(exhaustive_patterns)]
+#![feature(let_else)]
 #![feature(min_specialization)]
+#![feature(never_type)]
+#![feature(nll)]
+#![feature(rustc_attrs)]
 #![feature(step_trait)]
 
 use std::iter::FromIterator;
index 6655541461d014d55ee35e3eb034e15c5ee020ea..f880b28b3c8dc2f12d7b26ca6304ff482190886d 100644 (file)
@@ -35,34 +35,14 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
     span: Span,
 ) -> Result<(), NotConstEvaluatable> {
     debug!("is_const_evaluatable({:?})", uv);
-    if infcx.tcx.features().generic_const_exprs {
-        let tcx = infcx.tcx;
+    let tcx = infcx.tcx;
+
+    if tcx.features().generic_const_exprs {
         match AbstractConst::new(tcx, uv)? {
             // We are looking at a generic abstract constant.
             Some(ct) => {
-                for pred in param_env.caller_bounds() {
-                    match pred.kind().skip_binder() {
-                        ty::PredicateKind::ConstEvaluatable(uv) => {
-                            if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
-                                // Try to unify with each subtree in the AbstractConst to allow for
-                                // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
-                                // predicate for `(N + 1) * 2`
-                                let result =
-                                    walk_abstract_const(tcx, b_ct, |b_ct| {
-                                        match try_unify(tcx, ct, b_ct) {
-                                            true => ControlFlow::BREAK,
-                                            false => ControlFlow::CONTINUE,
-                                        }
-                                    });
-
-                                if let ControlFlow::Break(()) = result {
-                                    debug!("is_const_evaluatable: abstract_const ~~> ok");
-                                    return Ok(());
-                                }
-                            }
-                        }
-                        _ => {} // don't care
-                    }
+                if satisfied_from_param_env(tcx, ct, param_env)? {
+                    return Ok(());
                 }
 
                 // We were unable to unify the abstract constant with
@@ -163,6 +143,33 @@ enum FailureKind {
         }
     }
 
+    // If we're evaluating a foreign constant, under a nightly compiler without generic
+    // const exprs, AND it would've passed if that expression had been evaluated with
+    // generic const exprs, then suggest using generic const exprs.
+    if concrete.is_err()
+        && tcx.sess.is_nightly_build()
+        && !uv.def.did.is_local()
+        && !tcx.features().generic_const_exprs
+        && let Ok(Some(ct)) = AbstractConst::new(tcx, uv)
+        && satisfied_from_param_env(tcx, ct, param_env) == Ok(true)
+    {
+        tcx.sess
+            .struct_span_fatal(
+                // Slightly better span than just using `span` alone
+                if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
+                "failed to evaluate generic const expression",
+            )
+            .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
+            .span_suggestion_verbose(
+                rustc_span::DUMMY_SP,
+                "consider enabling this feature",
+                "#![feature(generic_const_exprs)]\n".to_string(),
+                rustc_errors::Applicability::MaybeIncorrect,
+            )
+            .emit();
+        rustc_errors::FatalError.raise();
+    }
+
     debug!(?concrete, "is_const_evaluatable");
     match concrete {
         Err(ErrorHandled::TooGeneric) => Err(match uv.has_infer_types_or_consts() {
@@ -178,6 +185,37 @@ enum FailureKind {
     }
 }
 
+fn satisfied_from_param_env<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ct: AbstractConst<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> Result<bool, NotConstEvaluatable> {
+    for pred in param_env.caller_bounds() {
+        match pred.kind().skip_binder() {
+            ty::PredicateKind::ConstEvaluatable(uv) => {
+                if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
+                    // Try to unify with each subtree in the AbstractConst to allow for
+                    // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
+                    // predicate for `(N + 1) * 2`
+                    let result =
+                        walk_abstract_const(tcx, b_ct, |b_ct| match try_unify(tcx, ct, b_ct) {
+                            true => ControlFlow::BREAK,
+                            false => ControlFlow::CONTINUE,
+                        });
+
+                    if let ControlFlow::Break(()) = result {
+                        debug!("is_const_evaluatable: abstract_const ~~> ok");
+                        return Ok(true);
+                    }
+                }
+            }
+            _ => {} // don't care
+        }
+    }
+
+    Ok(false)
+}
+
 /// A tree representing an anonymous constant.
 ///
 /// This is only able to represent a subset of `MIR`,
index a277f74f7a43fbf8bb6a17c247390eeaedeb4e0b..59c88b6603c228aa1f8f7fde58ad0ad65d9d7bc1 100644 (file)
@@ -4,20 +4,20 @@
 use crate::infer::InferCtxt;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, GenericParamDefKind};
 use rustc_span::symbol::sym;
 use std::iter;
 
 use super::InferCtxtPrivExt;
 
-crate trait InferCtxtExt<'tcx> {
+pub trait InferCtxtExt<'tcx> {
     /*private*/
     fn impl_similar_to(
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
         obligation: &PredicateObligation<'tcx>,
-    ) -> Option<DefId>;
+    ) -> Option<(DefId, SubstsRef<'tcx>)>;
 
     /*private*/
     fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>;
@@ -34,7 +34,7 @@ fn impl_similar_to(
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
         obligation: &PredicateObligation<'tcx>,
-    ) -> Option<DefId> {
+    ) -> Option<(DefId, SubstsRef<'tcx>)> {
         let tcx = self.tcx;
         let param_env = obligation.param_env;
         let trait_ref = tcx.erase_late_bound_regions(trait_ref);
@@ -50,7 +50,7 @@ fn impl_similar_to(
             let impl_self_ty = impl_trait_ref.self_ty();
 
             if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
-                self_match_impls.push(def_id);
+                self_match_impls.push((def_id, impl_substs));
 
                 if iter::zip(
                     trait_ref.substs.types().skip(1),
@@ -58,12 +58,12 @@ fn impl_similar_to(
                 )
                 .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
                 {
-                    fuzzy_match_impls.push(def_id);
+                    fuzzy_match_impls.push((def_id, impl_substs));
                 }
             }
         });
 
-        let impl_def_id = if self_match_impls.len() == 1 {
+        let impl_def_id_and_substs = if self_match_impls.len() == 1 {
             self_match_impls[0]
         } else if fuzzy_match_impls.len() == 1 {
             fuzzy_match_impls[0]
@@ -71,7 +71,8 @@ fn impl_similar_to(
             return None;
         };
 
-        tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id)
+        tcx.has_attr(impl_def_id_and_substs.0, sym::rustc_on_unimplemented)
+            .then_some(impl_def_id_and_substs)
     }
 
     /// Used to set on_unimplemented's `ItemContext`
@@ -120,8 +121,9 @@ fn on_unimplemented_note(
         trait_ref: ty::PolyTraitRef<'tcx>,
         obligation: &PredicateObligation<'tcx>,
     ) -> OnUnimplementedNote {
-        let def_id =
-            self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id());
+        let (def_id, substs) = self
+            .impl_similar_to(trait_ref, obligation)
+            .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs));
         let trait_ref = trait_ref.skip_binder();
 
         let mut flags = vec![(
@@ -176,7 +178,7 @@ fn on_unimplemented_note(
             for param in generics.params.iter() {
                 let value = match param.kind {
                     GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
-                        trait_ref.substs[param.index as usize].to_string()
+                        substs[param.index as usize].to_string()
                     }
                     GenericParamDefKind::Lifetime => continue,
                 };
@@ -184,7 +186,7 @@ fn on_unimplemented_note(
                 flags.push((name, Some(value)));
 
                 if let GenericParamDefKind::Type { .. } = param.kind {
-                    let param_ty = trait_ref.substs[param.index as usize].expect_ty();
+                    let param_ty = substs[param.index as usize].expect_ty();
                     if let Some(def) = param_ty.ty_adt_def() {
                         // We also want to be able to select the parameter's
                         // original signature with no type arguments resolved
@@ -202,6 +204,10 @@ fn on_unimplemented_note(
                 flags.push((sym::_Self, Some("{integral}".to_owned())));
             }
 
+            if self_ty.is_array_slice() {
+                flags.push((sym::_Self, Some("&[]".to_owned())));
+            }
+
             if let ty::Array(aty, len) = self_ty.kind() {
                 flags.push((sym::_Self, Some("[]".to_owned())));
                 flags.push((sym::_Self, Some(format!("[{}]", aty))));
@@ -229,9 +235,7 @@ fn on_unimplemented_note(
             }
         });
 
-        if let Ok(Some(command)) =
-            OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)
-        {
+        if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
             command.evaluate(self.tcx, trait_ref, &flags)
         } else {
             OnUnimplementedNote::default()
index b194e6a6d89f31f6624264677f9cfbe46f3dea18..f2ddc3ea7fa3909eebfebdd593ef60acc0fbf0a1 100644 (file)
@@ -405,7 +405,7 @@ fn suggest_restricting_param_bound(
                 }
                 hir::Node::Item(hir::Item {
                     kind:
-                        hir::ItemKind::Trait(_, _, generics, _, _)
+                        hir::ItemKind::Trait(_, _, generics, ..)
                         | hir::ItemKind::Impl(hir::Impl { generics, .. }),
                     ..
                 }) if projection.is_some() => {
index b4b2e4cd0422933837ac9f29520d39df7e7948bb..62c6c8454797a8f9592a5207a19b55e4b6761739 100644 (file)
@@ -346,6 +346,8 @@ fn process_changed_obligations(
 
         let obligation = &mut pending_obligation.obligation;
 
+        debug!(?obligation, "process_obligation pre-resolve");
+
         if obligation.predicate.has_infer_types_or_consts() {
             obligation.predicate =
                 self.selcx.infcx().resolve_vars_if_possible(obligation.predicate);
@@ -355,6 +357,21 @@ fn process_changed_obligations(
 
         let infcx = self.selcx.infcx();
 
+        if obligation.predicate.has_projections() {
+            let mut obligations = Vec::new();
+            let predicate = crate::traits::project::try_normalize_with_depth_to(
+                self.selcx,
+                obligation.param_env,
+                obligation.cause.clone(),
+                obligation.recursion_depth + 1,
+                obligation.predicate,
+                &mut obligations,
+            );
+            if predicate != obligation.predicate {
+                obligations.push(obligation.with(predicate));
+                return ProcessResult::Changed(mk_pending(obligations));
+            }
+        }
         let binder = obligation.predicate.kind();
         match binder.no_bound_vars() {
             None => match binder.skip_binder() {
index 9752ff453235ad0572ca1ac6d92a2426d5cb178a..2f697c1fa27b79e3eb4f7d2a902a9a24f520fb5f 100644 (file)
@@ -54,7 +54,7 @@ fn parse_error(
 impl<'tcx> OnUnimplementedDirective {
     fn parse(
         tcx: TyCtxt<'tcx>,
-        trait_def_id: DefId,
+        item_def_id: DefId,
         items: &[NestedMetaItem],
         span: Span,
         is_root: bool,
@@ -63,7 +63,7 @@ fn parse(
         let mut item_iter = items.iter();
 
         let parse_value = |value_str| {
-            OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
+            OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some)
         };
 
         let condition = if is_root {
@@ -135,7 +135,7 @@ fn parse(
             {
                 if let Some(items) = item.meta_item_list() {
                     if let Ok(subcommand) =
-                        Self::parse(tcx, trait_def_id, &items, item.span(), false)
+                        Self::parse(tcx, item_def_id, &items, item.span(), false)
                     {
                         subcommands.push(subcommand);
                     } else {
@@ -178,19 +178,15 @@ fn parse(
         }
     }
 
-    pub fn of_item(
-        tcx: TyCtxt<'tcx>,
-        trait_def_id: DefId,
-        impl_def_id: DefId,
-    ) -> Result<Option<Self>, ErrorGuaranteed> {
-        let attrs = tcx.get_attrs(impl_def_id);
+    pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
+        let attrs = tcx.get_attrs(item_def_id);
 
         let Some(attr) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else {
             return Ok(None);
         };
 
         let result = if let Some(items) = attr.meta_item_list() {
-            Self::parse(tcx, trait_def_id, &items, attr.span, true).map(Some)
+            Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some)
         } else if let Some(value) = attr.value_str() {
             Ok(Some(OnUnimplementedDirective {
                 condition: None,
@@ -198,7 +194,7 @@ pub fn of_item(
                 subcommands: vec![],
                 label: Some(OnUnimplementedFormatString::try_parse(
                     tcx,
-                    trait_def_id,
+                    item_def_id,
                     value,
                     attr.span,
                 )?),
@@ -209,7 +205,7 @@ pub fn of_item(
         } else {
             return Err(ErrorGuaranteed);
         };
-        debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result);
+        debug!("of_item({:?}) = {:?}", item_def_id, result);
         result
     }
 
@@ -280,23 +276,29 @@ pub fn evaluate(
 impl<'tcx> OnUnimplementedFormatString {
     fn try_parse(
         tcx: TyCtxt<'tcx>,
-        trait_def_id: DefId,
+        item_def_id: DefId,
         from: Symbol,
         err_sp: Span,
     ) -> Result<Self, ErrorGuaranteed> {
         let result = OnUnimplementedFormatString(from);
-        result.verify(tcx, trait_def_id, err_sp)?;
+        result.verify(tcx, item_def_id, err_sp)?;
         Ok(result)
     }
 
     fn verify(
         &self,
         tcx: TyCtxt<'tcx>,
-        trait_def_id: DefId,
+        item_def_id: DefId,
         span: Span,
     ) -> Result<(), ErrorGuaranteed> {
-        let name = tcx.item_name(trait_def_id);
-        let generics = tcx.generics_of(trait_def_id);
+        let trait_def_id = if tcx.is_trait(item_def_id) {
+            item_def_id
+        } else {
+            tcx.trait_id_of_impl(item_def_id)
+                .expect("expected `on_unimplemented` to correspond to a trait")
+        };
+        let trait_name = tcx.item_name(trait_def_id);
+        let generics = tcx.generics_of(item_def_id);
         let s = self.0.as_str();
         let parser = Parser::new(s, None, None, false, ParseMode::Format);
         let mut result = Ok(());
@@ -307,7 +309,7 @@ fn verify(
                     // `{Self}` is allowed
                     Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (),
                     // `{ThisTraitsName}` is allowed
-                    Position::ArgumentNamed(s, _) if s == name => (),
+                    Position::ArgumentNamed(s, _) if s == trait_name => (),
                     // `{from_method}` is allowed
                     Position::ArgumentNamed(s, _) if s == sym::from_method => (),
                     // `{from_desugaring}` is allowed
@@ -329,9 +331,13 @@ fn verify(
                                     tcx.sess,
                                     span,
                                     E0230,
-                                    "there is no parameter `{}` on trait `{}`",
+                                    "there is no parameter `{}` on {}",
                                     s,
-                                    name
+                                    if trait_def_id == item_def_id {
+                                        format!("trait `{}`", trait_name)
+                                    } else {
+                                        "impl".to_string()
+                                    }
                                 )
                                 .emit();
                                 result = Err(ErrorGuaranteed);
index c32c73c6384127b9a82ec9b57ab7193ae16cf692..ea48fab1cebb88b00b12a59bf48d6fba82fd95ab 100644 (file)
@@ -295,6 +295,32 @@ pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
     result
 }
 
+#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
+pub fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>(
+    selcx: &'a mut SelectionContext<'b, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    cause: ObligationCause<'tcx>,
+    depth: usize,
+    value: T,
+    obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> T
+where
+    T: TypeFoldable<'tcx>,
+{
+    debug!(obligations.len = obligations.len());
+    let mut normalizer = AssocTypeNormalizer::new_without_eager_inference_replacement(
+        selcx,
+        param_env,
+        cause,
+        depth,
+        obligations,
+    );
+    let result = ensure_sufficient_stack(|| normalizer.fold(value));
+    debug!(?result, obligations.len = normalizer.obligations.len());
+    debug!(?normalizer.obligations,);
+    result
+}
+
 pub(crate) fn needs_normalization<'tcx, T: TypeFoldable<'tcx>>(value: &T, reveal: Reveal) -> bool {
     match reveal {
         Reveal::UserFacing => value
@@ -314,6 +340,10 @@ struct AssocTypeNormalizer<'a, 'b, 'tcx> {
     obligations: &'a mut Vec<PredicateObligation<'tcx>>,
     depth: usize,
     universes: Vec<Option<ty::UniverseIndex>>,
+    /// If true, when a projection is unable to be completed, an inference
+    /// variable will be created and an obligation registered to project to that
+    /// inference variable. Also, constants will be eagerly evaluated.
+    eager_inference_replacement: bool,
 }
 
 impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
@@ -324,7 +354,33 @@ fn new(
         depth: usize,
         obligations: &'a mut Vec<PredicateObligation<'tcx>>,
     ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
-        AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] }
+        AssocTypeNormalizer {
+            selcx,
+            param_env,
+            cause,
+            obligations,
+            depth,
+            universes: vec![],
+            eager_inference_replacement: true,
+        }
+    }
+
+    fn new_without_eager_inference_replacement(
+        selcx: &'a mut SelectionContext<'b, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        cause: ObligationCause<'tcx>,
+        depth: usize,
+        obligations: &'a mut Vec<PredicateObligation<'tcx>>,
+    ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
+        AssocTypeNormalizer {
+            selcx,
+            param_env,
+            cause,
+            obligations,
+            depth,
+            universes: vec![],
+            eager_inference_replacement: false,
+        }
     }
 
     fn fold<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
@@ -428,14 +484,28 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 // there won't be bound vars there.
 
                 let data = data.super_fold_with(self);
-                let normalized_ty = normalize_projection_type(
-                    self.selcx,
-                    self.param_env,
-                    data,
-                    self.cause.clone(),
-                    self.depth,
-                    &mut self.obligations,
-                );
+                let normalized_ty = if self.eager_inference_replacement {
+                    normalize_projection_type(
+                        self.selcx,
+                        self.param_env,
+                        data,
+                        self.cause.clone(),
+                        self.depth,
+                        &mut self.obligations,
+                    )
+                } else {
+                    opt_normalize_projection_type(
+                        self.selcx,
+                        self.param_env,
+                        data,
+                        self.cause.clone(),
+                        self.depth,
+                        &mut self.obligations,
+                    )
+                    .ok()
+                    .flatten()
+                    .unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self)))
+                };
                 debug!(
                     ?self.depth,
                     ?ty,
@@ -501,7 +571,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
     }
 
     fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if self.selcx.tcx().lazy_normalization() {
+        if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement {
             constant
         } else {
             let constant = constant.super_fold_with(self);
index 6a2bd9ce1ea91d3043d04b07a38048fb20c1e35c..ed0ad5601aa400478afdf09db7e7e731ecab7c05 100644 (file)
@@ -334,6 +334,21 @@ fn try_fold_mir_const(
         &mut self,
         constant: mir::ConstantKind<'tcx>,
     ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
-        constant.try_super_fold_with(self)
+        let constant_kind = match constant {
+            mir::ConstantKind::Ty(c) => {
+                let const_folded = c.try_fold_with(self)?;
+                match const_folded.val() {
+                    ty::ConstKind::Value(cv) => {
+                        // FIXME With Valtrees we need to convert `cv: ValTree`
+                        // to a `ConstValue` here.
+                        mir::ConstantKind::Val(cv, const_folded.ty())
+                    }
+                    _ => mir::ConstantKind::Ty(const_folded),
+                }
+            }
+            mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?,
+        };
+
+        Ok(constant_kind)
     }
 }
index 3d0f76f7a93eba4cba2250b73b7d1849a6fae5d4..d3e9820834ab9310ca54a214ae0a775a56cdf9af 100644 (file)
@@ -165,6 +165,12 @@ pub enum CastError {
     NonScalar,
     UnknownExprPtrKind,
     UnknownCastPtrKind,
+    /// Cast of int to (possibly) fat raw pointer.
+    ///
+    /// Argument is the specific name of the metadata in plain words, such as "a vtable"
+    /// or "a length". If this argument is None, then the metadata is unknown, for example,
+    /// when we're typechecking a type parameter with a ?Sized bound.
+    IntToFatCast(Option<&'static str>),
 }
 
 impl From<ErrorGuaranteed> for CastError {
@@ -522,6 +528,35 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                 .diagnostic()
                 .emit();
             }
+            CastError::IntToFatCast(known_metadata) => {
+                let mut err = struct_span_err!(
+                    fcx.tcx.sess,
+                    self.cast_span,
+                    E0606,
+                    "cannot cast `{}` to a pointer that {} wide",
+                    fcx.ty_to_string(self.expr_ty),
+                    if known_metadata.is_some() { "is" } else { "may be" }
+                );
+
+                err.span_label(
+                    self.cast_span,
+                    format!(
+                        "creating a `{}` requires both an address and {}",
+                        self.cast_ty,
+                        known_metadata.unwrap_or("type-specific metadata"),
+                    ),
+                );
+
+                if fcx.tcx.sess.is_nightly_build() {
+                    err.span_label(
+                        self.expr.span,
+                        "consider casting this expression to `*const ()`, \
+                        then using `core::ptr::from_raw_parts`",
+                    );
+                }
+
+                err.emit();
+            }
             CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
                 let unknown_cast_to = match e {
                     CastError::UnknownCastPtrKind => true,
@@ -900,7 +935,13 @@ fn check_addr_ptr_cast(
         match fcx.pointer_kind(m_cast.ty, self.span)? {
             None => Err(CastError::UnknownCastPtrKind),
             Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
-            _ => Err(CastError::IllegalCast),
+            Some(PointerKind::Vtable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))),
+            Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))),
+            Some(
+                PointerKind::OfProjection(_)
+                | PointerKind::OfOpaque(_, _)
+                | PointerKind::OfParam(_),
+            ) => Err(CastError::IntToFatCast(None)),
         }
     }
 
index 765b752691f231eb94db144368a2a5e88f03b28d..7c3594175b85508ed4c10ac92fc306d6cbf79d52 100644 (file)
@@ -742,12 +742,11 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
                     impl_trait_ref,
                     &impl_.items,
                 );
-                let trait_def_id = impl_trait_ref.def_id;
-                check_on_unimplemented(tcx, trait_def_id, it);
+                check_on_unimplemented(tcx, it);
             }
         }
         hir::ItemKind::Trait(_, _, _, _, ref items) => {
-            check_on_unimplemented(tcx, it.def_id.to_def_id(), it);
+            check_on_unimplemented(tcx, it);
 
             for item in items.iter() {
                 let item = tcx.hir().trait_item(item.id);
@@ -857,9 +856,9 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
     }
 }
 
-pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) {
+pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
     // an error would be reported if this fails.
-    let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item.def_id.to_def_id());
+    let _ = traits::OnUnimplementedDirective::of_item(tcx, item.def_id.to_def_id());
 }
 
 pub(super) fn check_specialization_validity<'tcx>(
index 8e245beaa3db073a2af3fcbda35e07b3e4becb6f..7e7104f62fdc67588d58a2b91cf844d982422644 100644 (file)
@@ -43,7 +43,6 @@
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
 use rustc_session::parse::feature_err;
-use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::Span;
@@ -2010,8 +2009,7 @@ fn ban_nonexisting_field(
             // We know by construction that `<expr>.await` is either on Rust 2015
             // or results in `ExprKind::Await`. Suggest switching the edition to 2018.
             err.note("to `.await` a `Future`, switch to Rust 2018 or later");
-            err.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
-            err.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+            err.help_use_latest_edition();
         }
 
         err.emit();
index e46eccd61b14c40d4b009e7a86c851448bb9093e..b3213451d76c43049bddb5ecef655d312455c6a5 100644 (file)
@@ -1403,7 +1403,7 @@ fn inferred_kind(
                             self.fcx.var_for_def(self.span, param)
                         }
                     }
-                    GenericParamDefKind::Const { has_default, .. } => {
+                    GenericParamDefKind::Const { has_default } => {
                         if !infer_args && has_default {
                             tcx.const_param_default(param.def_id)
                                 .subst_spanned(tcx, substs.unwrap(), Some(self.span))
index 3f6247facd1a2b2d13e3d3d0468eb13b9430ce27..f165093c958dba28ffcfcd499828aadf6a9f4beb 100644 (file)
@@ -281,6 +281,8 @@ pub(in super::super) fn check_argument_types(
             self.demand_suptype(provided_arg.span, formal_input_ty, coerced_ty);
         };
 
+        let minimum_input_count = formal_input_tys.len();
+
         // Check the arguments.
         // We do this in a pretty awful way: first we type-check any arguments
         // that are not closures, then we type-check the closures. This is so
@@ -303,7 +305,6 @@ pub(in super::super) fn check_argument_types(
                 })
             }
 
-            let minimum_input_count = formal_input_tys.len();
             for (idx, arg) in provided_args.iter().enumerate() {
                 // Warn only for the first loop (the "no closures" one).
                 // Closure arguments themselves can't be diverging, but
@@ -456,17 +457,18 @@ pub(in super::super) fn check_argument_types(
             err.emit();
         }
 
-        // We also need to make sure we at least write the ty of the other
-        // arguments which we skipped above.
-        if c_variadic {
-            fn variadic_error<'tcx>(sess: &Session, span: Span, ty: Ty<'tcx>, cast_ty: &str) {
-                use crate::structured_errors::MissingCastForVariadicArg;
+        for arg in provided_args.iter().skip(minimum_input_count) {
+            let arg_ty = self.check_expr(&arg);
 
-                MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
-            }
+            if c_variadic {
+                // We also need to make sure we at least write the ty of the other
+                // arguments which we skipped above, either because they were additional
+                // c_variadic args, or because we had an argument count mismatch.
+                fn variadic_error<'tcx>(sess: &Session, span: Span, ty: Ty<'tcx>, cast_ty: &str) {
+                    use crate::structured_errors::MissingCastForVariadicArg;
 
-            for arg in provided_args.iter().skip(expected_arg_count) {
-                let arg_ty = self.check_expr(&arg);
+                    MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
+                }
 
                 // There are a few types which get autopromoted when passed via varargs
                 // in C but we just error out instead and require explicit casts.
index 0ae2dfa180b9eaaf940ca348cd98afd21bf80ff7..504e1ce8c9f51c84de1a494d5db9e613adef0a1d 100644 (file)
 use rustc_span::lev_distance;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{source_map, FileName, MultiSpan, Span};
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
-    FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
+    FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote,
 };
 
 use std::cmp::Ordering;
@@ -483,150 +484,6 @@ pub fn report_method_error(
                     }
                 }
 
-                let mut label_span_not_found = || {
-                    if unsatisfied_predicates.is_empty() {
-                        err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
-                        let is_string_or_ref_str = match actual.kind() {
-                            ty::Ref(_, ty, _) => {
-                                ty.is_str()
-                                    || matches!(
-                                        ty.kind(),
-                                        ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did)
-                                    )
-                            }
-                            ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did),
-                            _ => false,
-                        };
-                        if is_string_or_ref_str && item_name.name == sym::iter {
-                            err.span_suggestion_verbose(
-                                item_name.span,
-                                "because of the in-memory representation of `&str`, to obtain \
-                                 an `Iterator` over each of its codepoint use method `chars`",
-                                String::from("chars"),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                        if let ty::Adt(adt, _) = rcvr_ty.kind() {
-                            let mut inherent_impls_candidate = self
-                                .tcx
-                                .inherent_impls(adt.did)
-                                .iter()
-                                .copied()
-                                .filter(|def_id| {
-                                    if let Some(assoc) = self.associated_value(*def_id, item_name) {
-                                        // Check for both mode is the same so we avoid suggesting
-                                        // incorrect associated item.
-                                        match (mode, assoc.fn_has_self_parameter, source) {
-                                            (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
-                                                // We check that the suggest type is actually
-                                                // different from the received one
-                                                // So we avoid suggestion method with Box<Self>
-                                                // for instance
-                                                self.tcx.at(span).type_of(*def_id) != actual
-                                                    && self.tcx.at(span).type_of(*def_id) != rcvr_ty
-                                            }
-                                            (Mode::Path, false, _) => true,
-                                            _ => false,
-                                        }
-                                    } else {
-                                        false
-                                    }
-                                })
-                                .collect::<Vec<_>>();
-                            if !inherent_impls_candidate.is_empty() {
-                                inherent_impls_candidate.sort();
-                                inherent_impls_candidate.dedup();
-
-                                // number of type to shows at most.
-                                let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
-                                let type_candidates = inherent_impls_candidate
-                                    .iter()
-                                    .take(limit)
-                                    .map(|impl_item| {
-                                        format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
-                                    })
-                                    .collect::<Vec<_>>()
-                                    .join("\n");
-                                let additional_types = if inherent_impls_candidate.len() > limit {
-                                    format!(
-                                        "\nand {} more types",
-                                        inherent_impls_candidate.len() - limit
-                                    )
-                                } else {
-                                    "".to_string()
-                                };
-                                err.note(&format!(
-                                    "the {item_kind} was found for\n{}{}",
-                                    type_candidates, additional_types
-                                ));
-                            }
-                        }
-                    } else {
-                        err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
-                    }
-                };
-
-                // If the method name is the name of a field with a function or closure type,
-                // give a helping note that it has to be called as `(x.f)(...)`.
-                if let SelfSource::MethodCall(expr) = source {
-                    let field_receiver =
-                        self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
-                            ty::Adt(def, substs) if !def.is_enum() => {
-                                let variant = &def.non_enum_variant();
-                                self.tcx.find_field_index(item_name, variant).map(|index| {
-                                    let field = &variant.fields[index];
-                                    let field_ty = field.ty(tcx, substs);
-                                    (field, field_ty)
-                                })
-                            }
-                            _ => None,
-                        });
-
-                    if let Some((field, field_ty)) = field_receiver {
-                        let scope = self.tcx.parent_module(self.body_id).to_def_id();
-                        let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
-
-                        if is_accessible {
-                            if self.is_fn_ty(field_ty, span) {
-                                let expr_span = expr.span.to(item_name.span);
-                                err.multipart_suggestion(
-                                    &format!(
-                                        "to call the function stored in `{}`, \
-                                         surround the field access with parentheses",
-                                        item_name,
-                                    ),
-                                    vec![
-                                        (expr_span.shrink_to_lo(), '('.to_string()),
-                                        (expr_span.shrink_to_hi(), ')'.to_string()),
-                                    ],
-                                    Applicability::MachineApplicable,
-                                );
-                            } else {
-                                let call_expr = self
-                                    .tcx
-                                    .hir()
-                                    .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-
-                                if let Some(span) = call_expr.span.trim_start(item_name.span) {
-                                    err.span_suggestion(
-                                        span,
-                                        "remove the arguments",
-                                        String::new(),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
-                            }
-                        }
-
-                        let field_kind = if is_accessible { "field" } else { "private field" };
-                        err.span_label(item_name.span, format!("{}, not a method", field_kind));
-                    } else if lev_candidate.is_none() && static_sources.is_empty() {
-                        label_span_not_found();
-                    }
-                } else {
-                    label_span_not_found();
-                }
-
                 if self.is_fn_ty(rcvr_ty, span) {
                     fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) {
                         err.note(
@@ -645,12 +502,15 @@ fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) {
                     }
                 }
 
+                let mut custom_span_label = false;
+
                 if !static_sources.is_empty() {
                     err.note(
                         "found the following associated functions; to be used as methods, \
                          functions must have a `self` parameter",
                     );
                     err.span_label(span, "this is an associated function, not a method");
+                    custom_span_label = true;
                 }
                 if static_sources.len() == 1 {
                     let ty_str = if let Some(CandidateSource::ImplSource(impl_did)) =
@@ -686,6 +546,7 @@ fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) {
                     report_candidates(span, &mut err, static_sources, sugg_span);
                 }
 
+                let mut bound_spans = vec![];
                 let mut restrict_type_params = false;
                 let mut unsatisfied_bounds = false;
                 if item_name.name == sym::count && self.is_slice_ty(actual, span) {
@@ -709,7 +570,31 @@ fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) {
                         self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id))
                     };
                     let mut type_params = FxHashMap::default();
-                    let mut bound_spans = vec![];
+
+                    // Pick out the list of unimplemented traits on the receiver.
+                    // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
+                    let mut unimplemented_traits = FxHashMap::default();
+                    for (predicate, _parent_pred, cause) in &unsatisfied_predicates {
+                        if let (ty::PredicateKind::Trait(p), Some(cause)) =
+                            (predicate.kind().skip_binder(), cause.as_ref())
+                        {
+                            if p.trait_ref.self_ty() != rcvr_ty {
+                                // This is necessary, not just to keep the errors clean, but also
+                                // because our derived obligations can wind up with a trait ref that
+                                // requires a different param_env to be correctly compared.
+                                continue;
+                            }
+                            unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
+                                predicate.kind().rebind(p.trait_ref),
+                                Obligation {
+                                    cause: cause.clone(),
+                                    param_env: self.param_env,
+                                    predicate: predicate.clone(),
+                                    recursion_depth: 0,
+                                },
+                            ));
+                        }
+                    }
 
                     let mut collect_type_param_suggestions =
                         |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
@@ -945,11 +830,7 @@ trait bound{s}",
                     bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
                     bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
                     bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
-                    bound_spans.sort();
-                    bound_spans.dedup();
-                    for (span, msg) in bound_spans.into_iter() {
-                        err.span_label(span, &msg);
-                    }
+
                     if !bound_list.is_empty() || !skip_list.is_empty() {
                         let bound_list = bound_list
                             .into_iter()
@@ -957,9 +838,34 @@ trait bound{s}",
                             .collect::<Vec<_>>()
                             .join("\n");
                         let actual_prefix = actual.prefix_string(self.tcx);
-                        err.set_primary_message(&format!(
+                        info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
+                        let (primary_message, label) = if unimplemented_traits.len() == 1 {
+                            unimplemented_traits
+                                .into_iter()
+                                .next()
+                                .map(|(_, (trait_ref, obligation))| {
+                                    if trait_ref.self_ty().references_error()
+                                        || actual.references_error()
+                                    {
+                                        // Avoid crashing.
+                                        return (None, None);
+                                    }
+                                    let OnUnimplementedNote { message, label, .. } =
+                                        self.infcx.on_unimplemented_note(trait_ref, &obligation);
+                                    (message, label)
+                                })
+                                .unwrap_or((None, None))
+                        } else {
+                            (None, None)
+                        };
+                        let primary_message = primary_message.unwrap_or_else(|| format!(
                             "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
                         ));
+                        err.set_primary_message(&primary_message);
+                        if let Some(label) = label {
+                            custom_span_label = true;
+                            err.span_label(span, label);
+                        }
                         if !bound_list.is_empty() {
                             err.note(&format!(
                                 "the following trait bounds were not satisfied:\n{bound_list}"
@@ -971,6 +877,156 @@ trait bound{s}",
                     }
                 }
 
+                let mut label_span_not_found = || {
+                    if unsatisfied_predicates.is_empty() {
+                        err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+                        let is_string_or_ref_str = match actual.kind() {
+                            ty::Ref(_, ty, _) => {
+                                ty.is_str()
+                                    || matches!(
+                                        ty.kind(),
+                                        ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did)
+                                    )
+                            }
+                            ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did),
+                            _ => false,
+                        };
+                        if is_string_or_ref_str && item_name.name == sym::iter {
+                            err.span_suggestion_verbose(
+                                item_name.span,
+                                "because of the in-memory representation of `&str`, to obtain \
+                                 an `Iterator` over each of its codepoint use method `chars`",
+                                String::from("chars"),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                        if let ty::Adt(adt, _) = rcvr_ty.kind() {
+                            let mut inherent_impls_candidate = self
+                                .tcx
+                                .inherent_impls(adt.did)
+                                .iter()
+                                .copied()
+                                .filter(|def_id| {
+                                    if let Some(assoc) = self.associated_value(*def_id, item_name) {
+                                        // Check for both mode is the same so we avoid suggesting
+                                        // incorrect associated item.
+                                        match (mode, assoc.fn_has_self_parameter, source) {
+                                            (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+                                                // We check that the suggest type is actually
+                                                // different from the received one
+                                                // So we avoid suggestion method with Box<Self>
+                                                // for instance
+                                                self.tcx.at(span).type_of(*def_id) != actual
+                                                    && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+                                            }
+                                            (Mode::Path, false, _) => true,
+                                            _ => false,
+                                        }
+                                    } else {
+                                        false
+                                    }
+                                })
+                                .collect::<Vec<_>>();
+                            if !inherent_impls_candidate.is_empty() {
+                                inherent_impls_candidate.sort();
+                                inherent_impls_candidate.dedup();
+
+                                // number of type to shows at most.
+                                let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+                                let type_candidates = inherent_impls_candidate
+                                    .iter()
+                                    .take(limit)
+                                    .map(|impl_item| {
+                                        format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+                                    })
+                                    .collect::<Vec<_>>()
+                                    .join("\n");
+                                let additional_types = if inherent_impls_candidate.len() > limit {
+                                    format!(
+                                        "\nand {} more types",
+                                        inherent_impls_candidate.len() - limit
+                                    )
+                                } else {
+                                    "".to_string()
+                                };
+                                err.note(&format!(
+                                    "the {item_kind} was found for\n{}{}",
+                                    type_candidates, additional_types
+                                ));
+                            }
+                        }
+                    } else {
+                        err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
+                    }
+                };
+
+                // If the method name is the name of a field with a function or closure type,
+                // give a helping note that it has to be called as `(x.f)(...)`.
+                if let SelfSource::MethodCall(expr) = source {
+                    let field_receiver =
+                        self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
+                            ty::Adt(def, substs) if !def.is_enum() => {
+                                let variant = &def.non_enum_variant();
+                                self.tcx.find_field_index(item_name, variant).map(|index| {
+                                    let field = &variant.fields[index];
+                                    let field_ty = field.ty(tcx, substs);
+                                    (field, field_ty)
+                                })
+                            }
+                            _ => None,
+                        });
+
+                    if let Some((field, field_ty)) = field_receiver {
+                        let scope = self.tcx.parent_module(self.body_id).to_def_id();
+                        let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
+
+                        if is_accessible {
+                            if self.is_fn_ty(field_ty, span) {
+                                let expr_span = expr.span.to(item_name.span);
+                                err.multipart_suggestion(
+                                    &format!(
+                                        "to call the function stored in `{}`, \
+                                         surround the field access with parentheses",
+                                        item_name,
+                                    ),
+                                    vec![
+                                        (expr_span.shrink_to_lo(), '('.to_string()),
+                                        (expr_span.shrink_to_hi(), ')'.to_string()),
+                                    ],
+                                    Applicability::MachineApplicable,
+                                );
+                            } else {
+                                let call_expr = self
+                                    .tcx
+                                    .hir()
+                                    .expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+
+                                if let Some(span) = call_expr.span.trim_start(item_name.span) {
+                                    err.span_suggestion(
+                                        span,
+                                        "remove the arguments",
+                                        String::new(),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                }
+                            }
+                        }
+
+                        let field_kind = if is_accessible { "field" } else { "private field" };
+                        err.span_label(item_name.span, format!("{}, not a method", field_kind));
+                    } else if lev_candidate.is_none() && !custom_span_label {
+                        label_span_not_found();
+                    }
+                } else if !custom_span_label {
+                    label_span_not_found();
+                }
+
+                bound_spans.sort();
+                bound_spans.dedup();
+                for (span, msg) in bound_spans.into_iter() {
+                    err.span_label(span, &msg);
+                }
+
                 if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
                 } else {
                     self.suggest_traits_to_import(
index e2a91635a2d8b5f54bfee480833fde095e72824e..4c0eab51c355833decf4392b29e624345c2921a9 100644 (file)
@@ -553,7 +553,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S
     // the consumer's responsibility to ensure all bytes that have been read
     // have defined values.
     if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) {
-        if alloc.relocations().len() != 0 {
+        if alloc.inner().relocations().len() != 0 {
             let msg = "statics with a custom `#[link_section]` must be a \
                            simple list of bytes on the wasm target with no \
                            extra levels of indirection such as references";
index 257846324b888307145e064e96a9a48f8a4b852f..a2c79c6903218b1c473a200a4cc2621d9d45994f 100644 (file)
@@ -458,10 +458,10 @@ fn process_collected_capture_information(
     /// let s: String;  // hir_id_s
     /// let mut p: Point; // his_id_p
     /// let c = || {
-    ///        println!("{}", s);  // L1
+    ///        println!("{s}");  // L1
     ///        p.x += 10;  // L2
-    ///        println!("{}" , p.y) // L3
-    ///        println!("{}", p) // L4
+    ///        println!("{}" , p.y); // L3
+    ///        println!("{p}"); // L4
     ///        drop(s);   // L5
     /// };
     /// ```
@@ -785,7 +785,7 @@ fn perform_2229_migration_anaysis(
                             // Add a label pointing to where a captured variable affected by drop order
                             // is dropped
                             if lint_note.reason.drop_order {
-                                let drop_location_span = drop_location_span(self.tcx, &closure_hir_id);
+                                let drop_location_span = drop_location_span(self.tcx, closure_hir_id);
 
                                 match &lint_note.captures_info {
                                     UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
@@ -1697,8 +1697,8 @@ fn apply_capture_kind_on_capture_ty<'tcx>(
 }
 
 /// Returns the Span of where the value with the provided HirId would be dropped
-fn drop_location_span<'tcx>(tcx: TyCtxt<'tcx>, hir_id: &hir::HirId) -> Span {
-    let owner_id = tcx.hir().get_enclosing_scope(*hir_id).unwrap();
+fn drop_location_span<'tcx>(tcx: TyCtxt<'tcx>, hir_id: hir::HirId) -> Span {
+    let owner_id = tcx.hir().get_enclosing_scope(hir_id).unwrap();
 
     let owner_node = tcx.hir().get(owner_id);
     let owner_span = match owner_node {
index 8c19bbd3214eea75bec1513f8aa9ea23656010eb..62598d23bd64e9536372257af02338e4f3707af8 100644 (file)
@@ -702,10 +702,10 @@ fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
     fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
         fn upvar_is_local_variable<'tcx>(
             upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
-            upvar_id: &hir::HirId,
+            upvar_id: hir::HirId,
             body_owner_is_closure: bool,
         ) -> bool {
-            upvars.map(|upvars| !upvars.contains_key(upvar_id)).unwrap_or(body_owner_is_closure)
+            upvars.map(|upvars| !upvars.contains_key(&upvar_id)).unwrap_or(body_owner_is_closure)
         }
 
         debug!("walk_captures({:?})", closure_expr);
@@ -727,7 +727,7 @@ fn upvar_is_local_variable<'tcx>(
                     PlaceBase::Upvar(upvar_id) => {
                         if upvar_is_local_variable(
                             upvars,
-                            &upvar_id.var_path.hir_id,
+                            upvar_id.var_path.hir_id,
                             body_owner_is_closure,
                         ) {
                             // The nested closure might be fake reading the current (enclosing) closure's local variables.
index 9d4f9af91a5e19712ed254b4a88e6b9655b58e74..bd7d721b5e17332a7560ba95d306939a86cd65b3 100644 (file)
@@ -397,7 +397,7 @@ pub mod __alloc_error_handler {
     // if there is no `#[alloc_error_handler]`
     #[rustc_std_internal_symbol]
     pub unsafe extern "C-unwind" fn __rdl_oom(size: usize, _align: usize) -> ! {
-        panic!("memory allocation of {} bytes failed", size)
+        panic!("memory allocation of {size} bytes failed")
     }
 
     // if there is an `#[alloc_error_handler]`
index 63234ee91f091096568443b861b55d3d52d4dd50..8b13e36c4b3c7e342a45d403b0ef901f3dd80c0c 100644 (file)
@@ -161,7 +161,7 @@ fn clone_into(&self, target: &mut T) {
 /// let readonly = [1, 2];
 /// let borrowed = Items::new((&readonly[..]).into());
 /// match borrowed {
-///     Items { values: Cow::Borrowed(b) } => println!("borrowed {:?}", b),
+///     Items { values: Cow::Borrowed(b) } => println!("borrowed {b:?}"),
 ///     _ => panic!("expect borrowed value"),
 /// }
 ///
index 68bf59a01b3dd637efb5ca605d365f49616d7a37..7dce3db0a4766a61751761150562ca77bda0023d 100644 (file)
@@ -31,7 +31,7 @@
 //! }
 //!
 //! let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
-//! println!("{:?}", list);
+//! println!("{list:?}");
 //! ```
 //!
 //! This will print `Cons(1, Cons(2, Nil))`.
@@ -1170,8 +1170,7 @@ pub const fn into_pin(boxed: Self) -> Pin<Self>
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_box", issue = "92521")]
-unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> const Drop for Box<T, A> {
+unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
     fn drop(&mut self) {
         // FIXME: Do nothing, drop is currently performed by compiler.
     }
@@ -1408,7 +1407,7 @@ impl<T: Copy> From<&[T]> for Box<[T]> {
     /// let slice: &[u8] = &[104, 101, 108, 108, 111];
     /// let boxed_slice: Box<[u8]> = Box::from(slice);
     ///
-    /// println!("{:?}", boxed_slice);
+    /// println!("{boxed_slice:?}");
     /// ```
     fn from(slice: &[T]) -> Box<[T]> {
         let len = slice.len();
@@ -1450,7 +1449,7 @@ impl From<&str> for Box<str> {
     ///
     /// ```rust
     /// let boxed: Box<str> = Box::from("hello");
-    /// println!("{}", boxed);
+    /// println!("{boxed}");
     /// ```
     #[inline]
     fn from(s: &str) -> Box<str> {
@@ -1475,14 +1474,14 @@ impl From<Cow<'_, str>> for Box<str> {
     ///
     /// let unboxed = Cow::Borrowed("hello");
     /// let boxed: Box<str> = Box::from(unboxed);
-    /// println!("{}", boxed);
+    /// println!("{boxed}");
     /// ```
     ///
     /// ```rust
     /// # use std::borrow::Cow;
     /// let unboxed = Cow::Owned("hello".to_string());
     /// let boxed: Box<str> = Box::from(unboxed);
-    /// println!("{}", boxed);
+    /// println!("{boxed}");
     /// ```
     #[inline]
     fn from(cow: Cow<'_, str>) -> Box<str> {
@@ -1529,7 +1528,7 @@ fn from(s: Box<str, A>) -> Self {
     ///
     /// ```rust
     /// let boxed: Box<[u8]> = Box::from([4, 2]);
-    /// println!("{:?}", boxed);
+    /// println!("{boxed:?}");
     /// ```
     fn from(array: [T; N]) -> Box<[T]> {
         box array
index e18cd8cd46427ac7c70d9b9500e86751a9c4cace..e6c3d38dab3a29603ba1e54c30f9e72c0e7d1f0c 100644 (file)
 /// // We can iterate over the items in the heap, although they are returned in
 /// // a random order.
 /// for x in &heap {
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // If we instead pop these scores, they should come back in order.
@@ -779,7 +779,7 @@ pub fn drain_sorted(&mut self) -> DrainSorted<'_, T> {
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns
+    /// In other words, remove all elements `e` for which `f(&e)` returns
     /// `false`. The elements are visited in unsorted (and unspecified) order.
     ///
     /// # Examples
@@ -830,7 +830,7 @@ impl<T> BinaryHeap<T> {
     ///
     /// // Print 1, 2, 3, 4 in arbitrary order
     /// for x in heap.iter() {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1110,7 +1110,7 @@ pub fn as_slice(&self) -> &[T] {
     ///
     /// // Will print in some order
     /// for x in vec {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     #[must_use = "`self` will be dropped if the result is not used"]
@@ -1179,7 +1179,7 @@ pub fn is_empty(&self) -> bool {
     /// assert!(!heap.is_empty());
     ///
     /// for x in heap.drain() {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     ///
     /// assert!(heap.is_empty());
@@ -1624,7 +1624,7 @@ impl<T> IntoIterator for BinaryHeap<T> {
     /// // Print 1, 2, 3, 4 in arbitrary order
     /// for x in heap.into_iter() {
     ///     // x has type i32, not &i32
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     fn into_iter(self) -> IntoIter<T> {
index 7890c1040f0a18a08496cd5cbcde446fdc755a36..d0ff3eb747598a86ce4029223935d1f9b937b14e 100644 (file)
 /// let to_find = ["Up!", "Office Space"];
 /// for movie in &to_find {
 ///     match movie_reviews.get(movie) {
-///        Some(review) => println!("{}: {}", movie, review),
-///        None => println!("{} is unreviewed.", movie)
+///        Some(review) => println!("{movie}: {review}"),
+///        None => println!("{movie} is unreviewed.")
 ///     }
 /// }
 ///
 ///
 /// // iterate over everything.
 /// for (movie, review) in &movie_reviews {
-///     println!("{}: \"{}\"", movie, review);
+///     println!("{movie}: \"{review}\"");
 /// }
 /// ```
 ///
@@ -963,7 +963,7 @@ pub fn remove_entry<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
+    /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`.
     /// The elements are visited in ascending key order.
     ///
     /// # Examples
@@ -1061,7 +1061,7 @@ pub fn append(&mut self, other: &mut Self)
     /// map.insert(5, "b");
     /// map.insert(8, "c");
     /// for (&key, &value) in map.range((Included(&4), Included(&8))) {
-    ///     println!("{}: {}", key, value);
+    ///     println!("{key}: {value}");
     /// }
     /// assert_eq!(Some((&5, &"b")), map.range(4..).next());
     /// ```
@@ -1104,7 +1104,7 @@ pub fn range<T: ?Sized, R>(&self, range: R) -> Range<'_, K, V>
     ///     *balance += 100;
     /// }
     /// for (name, balance) in &map {
-    ///     println!("{} => {}", name, balance);
+    ///     println!("{name} => {balance}");
     /// }
     /// ```
     #[stable(feature = "btree_range", since = "1.17.0")]
@@ -2088,7 +2088,7 @@ impl<K, V> BTreeMap<K, V> {
     /// map.insert(1, "a");
     ///
     /// for (key, value) in map.iter() {
-    ///     println!("{}: {}", key, value);
+    ///     println!("{key}: {value}");
     /// }
     ///
     /// let (first_key, first_value) = map.iter().next().unwrap();
index 5cef007a46f0d1ea9d725fd87c3b8f703288426c..66608d09082d77363f10718a13cfa74f4e68a8c1 100644 (file)
@@ -3,7 +3,7 @@
 use core::mem;
 
 use super::super::borrow::DormantMutRef;
-use super::super::node::{marker, Handle, InsertResult::*, NodeRef};
+use super::super::node::{marker, Handle, NodeRef};
 use super::BTreeMap;
 
 use Entry::*;
@@ -313,13 +313,13 @@ pub fn into_key(self) -> K {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(self, value: V) -> &'a mut V {
         let out_ptr = match self.handle.insert_recursing(self.key, value) {
-            (Fit(_), val_ptr) => {
+            (None, val_ptr) => {
                 // SAFETY: We have consumed self.handle and the handle returned.
                 let map = unsafe { self.dormant_map.awaken() };
                 map.length += 1;
                 val_ptr
             }
-            (Split(ins), val_ptr) => {
+            (Some(ins), val_ptr) => {
                 drop(ins.left);
                 // SAFETY: We have consumed self.handle and the reference returned.
                 let map = unsafe { self.dormant_map.awaken() };
index 65468d5fe57166222a53de3fb2ce0efce3dc64ec..4d21df32417248a81867d53a13712e3edb337680 100644 (file)
@@ -1758,7 +1758,7 @@ fn map<K>(mut map: BTreeMap<K, ()>) {
     }
 
     fn map_debug<K: Debug>(mut map: BTreeMap<K, ()>) {
-        format!("{:?}", map);
+        format!("{map:?}");
         format!("{:?}", map.iter());
         format!("{:?}", map.iter_mut());
         format!("{:?}", map.keys());
index dfce98f97bd4496f280e2dab003a8891fed80f86..44f5bc850b8527c61482e5e1da3957d5b4d9196b 100644 (file)
@@ -861,11 +861,10 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
     /// this edge. This method splits the node if there isn't enough room.
     ///
     /// The returned pointer points to the inserted value.
-    fn insert(mut self, key: K, val: V) -> (InsertResult<'a, K, V, marker::Leaf>, *mut V) {
+    fn insert(mut self, key: K, val: V) -> (Option<SplitResult<'a, K, V, marker::Leaf>>, *mut V) {
         if self.node.len() < CAPACITY {
             let val_ptr = self.insert_fit(key, val);
-            let kv = unsafe { Handle::new_kv(self.node, self.idx) };
-            (InsertResult::Fit(kv), val_ptr)
+            (None, val_ptr)
         } else {
             let (middle_kv_idx, insertion) = splitpoint(self.idx);
             let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
@@ -879,7 +878,7 @@ fn insert(mut self, key: K, val: V) -> (InsertResult<'a, K, V, marker::Leaf>, *m
                 },
             };
             let val_ptr = insertion_edge.insert_fit(key, val);
-            (InsertResult::Split(result), val_ptr)
+            (Some(result), val_ptr)
         }
     }
 }
@@ -923,13 +922,12 @@ fn insert(
         key: K,
         val: V,
         edge: Root<K, V>,
-    ) -> InsertResult<'a, K, V, marker::Internal> {
+    ) -> Option<SplitResult<'a, K, V, marker::Internal>> {
         assert!(edge.height == self.node.height - 1);
 
         if self.node.len() < CAPACITY {
             self.insert_fit(key, val, edge);
-            let kv = unsafe { Handle::new_kv(self.node, self.idx) };
-            InsertResult::Fit(kv)
+            None
         } else {
             let (middle_kv_idx, insertion) = splitpoint(self.idx);
             let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
@@ -943,7 +941,7 @@ fn insert(
                 },
             };
             insertion_edge.insert_fit(key, val, edge);
-            InsertResult::Split(result)
+            Some(result)
         }
     }
 }
@@ -953,32 +951,26 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
     /// this edge. This method splits the node if there isn't enough room, and tries to
     /// insert the split off portion into the parent node recursively, until the root is reached.
     ///
-    /// If the returned result is a `Fit`, its handle's node can be this edge's node or an ancestor.
-    /// If the returned result is a `Split`, the `left` field will be the root node.
-    /// The returned pointer points to the inserted value.
+    /// If the returned result is some `SplitResult`, the `left` field will be the root node.
+    /// The returned pointer points to the inserted value, which in the case of `SplitResult`
+    /// is in the `left` or `right` tree.
     pub fn insert_recursing(
         self,
         key: K,
         value: V,
-    ) -> (InsertResult<'a, K, V, marker::LeafOrInternal>, *mut V) {
+    ) -> (Option<SplitResult<'a, K, V, marker::LeafOrInternal>>, *mut V) {
         let (mut split, val_ptr) = match self.insert(key, value) {
-            (InsertResult::Fit(handle), ptr) => {
-                return (InsertResult::Fit(handle.forget_node_type()), ptr);
-            }
-            (InsertResult::Split(split), val_ptr) => (split.forget_node_type(), val_ptr),
+            (None, val_ptr) => return (None, val_ptr),
+            (Some(split), val_ptr) => (split.forget_node_type(), val_ptr),
         };
 
         loop {
             split = match split.left.ascend() {
                 Ok(parent) => match parent.insert(split.kv.0, split.kv.1, split.right) {
-                    InsertResult::Fit(handle) => {
-                        return (InsertResult::Fit(handle.forget_node_type()), val_ptr);
-                    }
-                    InsertResult::Split(split) => split.forget_node_type(),
+                    None => return (None, val_ptr),
+                    Some(split) => split.forget_node_type(),
                 },
-                Err(root) => {
-                    return (InsertResult::Split(SplitResult { left: root, ..split }), val_ptr);
-                }
+                Err(root) => return (Some(SplitResult { left: root, ..split }), val_ptr),
             };
         }
     }
@@ -1529,14 +1521,6 @@ pub fn forget_node_type(
     }
 }
 
-impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::KV> {
-    pub fn forget_node_type(
-        self,
-    ) -> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV> {
-        unsafe { Handle::new_kv(self.node.forget_type(), self.idx) }
-    }
-}
-
 impl<BorrowType, K, V, Type> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, Type> {
     /// Checks whether the underlying node is an `Internal` node or a `Leaf` node.
     pub fn force(
@@ -1621,7 +1605,7 @@ pub enum ForceResult<Leaf, Internal> {
 pub struct SplitResult<'a, K, V, NodeType> {
     // Altered node in existing tree with elements and edges that belong to the left of `kv`.
     pub left: NodeRef<marker::Mut<'a>, K, V, NodeType>,
-    // Some key and value split off, to be inserted elsewhere.
+    // Some key and value that existed before and were split off, to be inserted elsewhere.
     pub kv: (K, V),
     // Owned, unattached, new node with elements and edges that belong to the right of `kv`.
     pub right: NodeRef<marker::Owned, K, V, NodeType>,
@@ -1639,11 +1623,6 @@ pub fn forget_node_type(self) -> SplitResult<'a, K, V, marker::LeafOrInternal> {
     }
 }
 
-pub enum InsertResult<'a, K, V, NodeType> {
-    Fit(Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV>),
-    Split(SplitResult<'a, K, V, NodeType>),
-}
-
 pub mod marker {
     use core::marker::PhantomData;
 
index bab6af826986421a57a6fb0782abd86b7265ead3..d6733425288d4d50091f07f8c62991f38f26d516 100644 (file)
@@ -60,7 +60,7 @@
 ///
 /// // Iterate over everything.
 /// for book in &books {
-///     println!("{}", book);
+///     println!("{book}");
 /// }
 /// ```
 ///
@@ -284,7 +284,7 @@ pub const fn new() -> BTreeSet<T> {
     /// set.insert(5);
     /// set.insert(8);
     /// for &elem in set.range((Included(&4), Included(&8))) {
-    ///     println!("{}", elem);
+    ///     println!("{elem}");
     /// }
     /// assert_eq!(Some(&5), set.range(4..).next());
     /// ```
@@ -873,7 +873,7 @@ pub fn take<Q: ?Sized>(&mut self, value: &Q) -> Option<T>
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+    /// In other words, remove all elements `e` for which `f(&e)` returns `false`.
     /// The elements are visited in ascending order.
     ///
     /// # Examples
index 7865d37ae51f1cde0a29e538d1496c980e3c4d24..032563e4f09beb028258f8424e1011a34624f648 100644 (file)
@@ -431,10 +431,10 @@ fn test_show() {
     set.insert(1);
     set.insert(2);
 
-    let set_str = format!("{:?}", set);
+    let set_str = format!("{set:?}");
 
     assert_eq!(set_str, "{1, 2}");
-    assert_eq!(format!("{:?}", empty), "{}");
+    assert_eq!(format!("{empty:?}"), "{}");
 }
 
 #[test]
@@ -649,7 +649,7 @@ fn set<K>(mut set: BTreeSet<K>) {
     }
 
     fn set_debug<K: Debug>(set: BTreeSet<K>) {
-        format!("{:?}", set);
+        format!("{set:?}");
         format!("{:?}", set.iter());
         format!("{:?}", set.into_iter());
     }
index 7139a0fb94d76752372e8af27767274028bf30f4..c3cabc754e6a8069c4846121c39650317ffb3eb6 100644 (file)
@@ -2119,7 +2119,7 @@ pub fn append(&mut self, other: &mut Self) {
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns false.
+    /// In other words, remove all elements `e` for which `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.
     ///
@@ -2158,7 +2158,7 @@ pub fn retain<F>(&mut self, mut f: F)
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns false.
+    /// In other words, remove all elements `e` for which `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.
     ///
index aeb7554f8e914ec1117b3cce8a35f9f16e40376b..501a6353b2c97ae9797ce572e5997ffd0ba0b5d0 100644 (file)
 //! fn main() {
 //!     let myvector = Vector2D { x: 3, y: 4 };
 //!
-//!     println!("{}", myvector);       // => "(3, 4)"
-//!     println!("{:?}", myvector);     // => "Vector2D {x: 3, y:4}"
-//!     println!("{:10.3b}", myvector); // => "     5.000"
+//!     println!("{myvector}");       // => "(3, 4)"
+//!     println!("{myvector:?}");     // => "Vector2D {x: 3, y:4}"
+//!     println!("{myvector:10.3b}"); // => "     5.000"
 //! }
 //! ```
 //!
index 82493f9c398cb5805d7653cab651b6b19b570538..0a180b83355e0d7c8f8a843c4504dd04c6b527f2 100644 (file)
 #![feature(box_syntax)]
 #![feature(cfg_sanitize)]
 #![feature(const_deref)]
-#![feature(const_fn_trait_bound)]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
 #![feature(const_mut_refs)]
 #![feature(const_ptr_write)]
 #![feature(const_precise_live_drops)]
index 843a9b07fa93448ef99c84197b25718d82a95db2..d7c28f8063337f3d4ac78b67f2aa99050e32c3e0 100644 (file)
@@ -309,7 +309,7 @@ fn test_cowrc_clone_weak() {
 #[test]
 fn test_show() {
     let foo = Rc::new(75);
-    assert_eq!(format!("{:?}", foo), "75");
+    assert_eq!(format!("{foo:?}"), "75");
 }
 
 #[test]
@@ -324,7 +324,7 @@ fn test_maybe_thin_unsized() {
     use std::ffi::{CStr, CString};
 
     let x: Rc<CStr> = Rc::from(CString::new("swordfish").unwrap().into_boxed_c_str());
-    assert_eq!(format!("{:?}", x), "\"swordfish\"");
+    assert_eq!(format!("{x:?}"), "\"swordfish\"");
     let y: Weak<CStr> = Rc::downgrade(&x);
     drop(x);
 
@@ -451,7 +451,7 @@ fn test_from_box_trait_zero_sized() {
     let b: Box<dyn Debug> = box ();
     let r: Rc<dyn Debug> = Rc::from(b);
 
-    assert_eq!(format!("{:?}", r), "()");
+    assert_eq!(format!("{r:?}"), "()");
 }
 
 #[test]
index f0397d08f95a8f4e03875c77c9eed85a197aff5c..f52871c73d9fcf6c4cf24a68ebee822417d47a0c 100644 (file)
@@ -48,7 +48,7 @@
 //! ```
 //! let numbers = &[0, 1, 2];
 //! for n in numbers {
-//!     println!("{} is a number!", n);
+//!     println!("{n} is a number!");
 //! }
 //! ```
 //!
index 716bb4983a651f2cb581862d21ad92f4e62e69c6..71419c151968d34b84026746fab18a130325ce42 100644 (file)
@@ -2718,7 +2718,7 @@ impl From<String> for Vec<u8> {
     /// let v1 = Vec::from(s1);
     ///
     /// for b in v1 {
-    ///     println!("{}", b);
+    ///     println!("{b}");
     /// }
     /// ```
     fn from(string: String) -> Vec<u8> {
index 7e7670aad6425fc1bc6476687a60c48ab6396961..2140c3f168d1c3a75b2b413e6755d9fd1a9765f6 100644 (file)
@@ -200,7 +200,7 @@ macro_rules! acquire {
 ///     let five = Arc::clone(&five);
 ///
 ///     thread::spawn(move || {
-///         println!("{:?}", five);
+///         println!("{five:?}");
 ///     });
 /// }
 /// ```
@@ -221,7 +221,7 @@ macro_rules! acquire {
 ///
 ///     thread::spawn(move || {
 ///         let v = val.fetch_add(1, Ordering::SeqCst);
-///         println!("{:?}", v);
+///         println!("{v:?}");
 ///     });
 /// }
 /// ```
index 4ccb32fbbf63d3e5f131b304196834a36a29f2eb..452a88773018c0455a18b88c19fb0181e919c705 100644 (file)
@@ -335,7 +335,7 @@ fn test_weak_count() {
 #[test]
 fn show_arc() {
     let a = Arc::new(5);
-    assert_eq!(format!("{:?}", a), "5");
+    assert_eq!(format!("{a:?}"), "5");
 }
 
 // Make sure deriving works with Arc<T>
@@ -347,7 +347,7 @@ struct Foo {
 #[test]
 fn test_unsized() {
     let x: Arc<[i32]> = Arc::new([1, 2, 3]);
-    assert_eq!(format!("{:?}", x), "[1, 2, 3]");
+    assert_eq!(format!("{x:?}"), "[1, 2, 3]");
     let y = Arc::downgrade(&x.clone());
     drop(x);
     assert!(y.upgrade().is_none());
@@ -359,7 +359,7 @@ fn test_maybe_thin_unsized() {
     use std::ffi::{CStr, CString};
 
     let x: Arc<CStr> = Arc::from(CString::new("swordfish").unwrap().into_boxed_c_str());
-    assert_eq!(format!("{:?}", x), "\"swordfish\"");
+    assert_eq!(format!("{x:?}"), "\"swordfish\"");
     let y: Weak<CStr> = Arc::downgrade(&x);
     drop(x);
 
@@ -509,7 +509,7 @@ fn test_from_box_trait_zero_sized() {
     let b: Box<dyn Debug> = box ();
     let r: Arc<dyn Debug> = Arc::from(b);
 
-    assert_eq!(format!("{:?}", r), "()");
+    assert_eq!(format!("{r:?}"), "()");
 }
 
 #[test]
index b4741c35c583fa3157e44ef5175c00397329cf39..299ed156a5d2706da9bbda653f2c2a49226e25f8 100644 (file)
@@ -47,8 +47,8 @@ fn any_move() {
 fn test_show() {
     let a = Box::new(8) as Box<dyn Any>;
     let b = Box::new(Test) as Box<dyn Any>;
-    let a_str = format!("{:?}", a);
-    let b_str = format!("{:?}", b);
+    let a_str = format!("{a:?}");
+    let b_str = format!("{b:?}");
     assert_eq!(a_str, "Any { .. }");
     assert_eq!(b_str, "Any { .. }");
 
@@ -56,9 +56,9 @@ fn test_show() {
     static TEST: Test = Test;
     let a = &EIGHT as &dyn Any;
     let b = &TEST as &dyn Any;
-    let s = format!("{:?}", a);
+    let s = format!("{a:?}");
     assert_eq!(s, "Any { .. }");
-    let s = format!("{:?}", b);
+    let s = format!("{b:?}");
     assert_eq!(s, "Any { .. }");
 }
 
index c4c393f55eee9f8aeaa980976fefec890d1d4c78..5131168db0c82bb972889c2dc630fd5bf3405786 100644 (file)
 /// vec.extend([1, 2, 3].iter().copied());
 ///
 /// for x in &vec {
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 /// assert_eq!(vec, [7, 1, 2, 3]);
 /// ```
 ///
 /// while let Some(top) = stack.pop() {
 ///     // Prints 3, 2, 1
-///     println!("{}", top);
+///     println!("{top}");
 /// }
 /// ```
 ///
@@ -1297,7 +1297,7 @@ 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);
+            panic!("swap_remove index (is {index}) should be < len (is {len})");
         }
 
         let len = self.len();
@@ -1338,7 +1338,7 @@ 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);
+            panic!("insertion index (is {index}) should be <= len (is {len})");
         }
 
         let len = self.len();
@@ -1397,7 +1397,7 @@ pub fn remove(&mut self, index: usize) -> T {
         #[inline(never)]
         #[track_caller]
         fn assert_failed(index: usize, len: usize) -> ! {
-            panic!("removal index (is {}) should be < len (is {})", index, len);
+            panic!("removal index (is {index}) should be < len (is {len})");
         }
 
         let len = self.len();
@@ -1424,7 +1424,7 @@ fn assert_failed(index: usize, len: usize) -> ! {
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+    /// In other words, remove all elements `e` for which `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.
     ///
@@ -1942,7 +1942,7 @@ pub fn split_off(&mut self, at: usize) -> Self
         #[cold]
         #[inline(never)]
         fn assert_failed(at: usize, len: usize) -> ! {
-            panic!("`at` split index (is {}) should be <= len (is {})", at, len);
+            panic!("`at` split index (is {at}) should be <= len (is {len})");
         }
 
         if at > self.len() {
@@ -2568,7 +2568,7 @@ impl<T, A: Allocator> IntoIterator for Vec<T, A> {
     /// let v = vec!["a".to_string(), "b".to_string()];
     /// for s in v.into_iter() {
     ///     // s has type String, not &String
-    ///     println!("{}", s);
+    ///     println!("{s}");
     /// }
     /// ```
     #[inline]
index 0d7acfed8c6a1b36f0354714fa375f9de8efd9b4..9e5123be989900f2809ca93a2471ed57509d1be4 100644 (file)
@@ -160,7 +160,7 @@ fn const_box() {
         *boxed = 42;
         assert!(*boxed == 42);
 
-        *boxed
+        *Box::leak(boxed)
     };
 
     assert!(VALUE == 42);
index 27ab6c07e430989aa5d48f9252700d55f3d21eb7..1575a5999f932b688b91cfd24502b3a3e3dab5b3 100644 (file)
@@ -84,8 +84,8 @@ fn test_format_macro_interface() {
     }
     t!(format!("{:p}", 0x1234 as *const isize), "0x1234");
     t!(format!("{:p}", 0x1234 as *mut isize), "0x1234");
-    t!(format!("{:x}", A), "aloha");
-    t!(format!("{:X}", B), "adios");
+    t!(format!("{A:x}"), "aloha");
+    t!(format!("{B:X}"), "adios");
     t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
     t!(format!("{1} {0}", 0, 1), "1 0");
     t!(format!("{foo} {bar}", foo = 0, bar = 1), "0 1");
@@ -94,11 +94,11 @@ fn test_format_macro_interface() {
     t!(format!("{_foo}", _foo = 6usize), "6");
     t!(format!("{foo_bar}", foo_bar = 1), "1");
     t!(format!("{}", 5 + 5), "10");
-    t!(format!("{:#4}", C), "☃123");
-    t!(format!("{:b}", D), "aa☃bb");
+    t!(format!("{C:#4}"), "☃123");
+    t!(format!("{D:b}"), "aa☃bb");
 
     let a: &dyn fmt::Debug = &1;
-    t!(format!("{:?}", a), "1");
+    t!(format!("{a:?}"), "1");
 
     // Formatting strings and their arguments
     t!(format!("{}", "a"), "a");
@@ -206,7 +206,7 @@ fn test_format_macro_interface() {
     // Test that pointers don't get truncated.
     {
         let val = usize::MAX;
-        let exp = format!("{:#x}", val);
+        let exp = format!("{val:#x}");
         t!(format!("{:p}", val as *const isize), exp);
     }
 
@@ -216,14 +216,14 @@ fn test_format_macro_interface() {
 
     // make sure that format! doesn't move out of local variables
     let a = Box::new(3);
-    format!("{}", a);
-    format!("{}", a);
+    format!("{a}");
+    format!("{a}");
 
     // make sure that format! doesn't cause spurious unused-unsafe warnings when
     // it's inside of an outer unsafe block
     unsafe {
         let a: isize = ::std::mem::transmute(3_usize);
-        format!("{}", a);
+        format!("{a}");
     }
 
     // test that trailing commas are acceptable
@@ -315,9 +315,9 @@ fn foo() -> isize {
 #[test]
 fn test_refcell() {
     let refcell = RefCell::new(5);
-    assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
+    assert_eq!(format!("{refcell:?}"), "RefCell { value: 5 }");
     let borrow = refcell.borrow_mut();
-    assert_eq!(format!("{:?}", refcell), "RefCell { value: <borrowed> }");
+    assert_eq!(format!("{refcell:?}"), "RefCell { value: <borrowed> }");
     drop(borrow);
-    assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
+    assert_eq!(format!("{refcell:?}"), "RefCell { value: 5 }");
 }
index 5f5bd9af2fe5f37e9df1decce3fd4e8902208648..66a9cca6644c41481c65fb0521f5692e9baa0ca9 100644 (file)
@@ -302,10 +302,10 @@ fn test_ord_nan() {
 #[test]
 fn test_show() {
     let list: LinkedList<_> = (0..10).collect();
-    assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
+    assert_eq!(format!("{list:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
 
     let list: LinkedList<_> = ["just", "one", "test", "more"].into_iter().collect();
-    assert_eq!(format!("{:?}", list), "[\"just\", \"one\", \"test\", \"more\"]");
+    assert_eq!(format!("{list:?}"), "[\"just\", \"one\", \"test\", \"more\"]");
 }
 
 #[test]
index b93d7938bc9a5cd1e5a8db56734d4992633b2ecb..b027a25a146bcf97b1dc61d3df2c4d96ebbab711 100644 (file)
@@ -1045,10 +1045,10 @@ fn assert_tight_size_hints(mut it: impl Iterator, which: Bounds, ctx: impl fmt::
             a(v.rsplit_mut(p), b, "rsplit_mut");
 
             for n in 0..=3 {
-                a(v.splitn(n, p), b, f!("splitn, n = {}", n));
-                a(v.splitn_mut(n, p), b, f!("splitn_mut, n = {}", n));
-                a(v.rsplitn(n, p), b, f!("rsplitn, n = {}", n));
-                a(v.rsplitn_mut(n, p), b, f!("rsplitn_mut, n = {}", n));
+                a(v.splitn(n, p), b, f!("splitn, n = {n}"));
+                a(v.splitn_mut(n, p), b, f!("splitn_mut, n = {n}"));
+                a(v.rsplitn(n, p), b, f!("rsplitn, n = {n}"));
+                a(v.rsplitn_mut(n, p), b, f!("rsplitn_mut, n = {n}"));
             }
         }
     }
@@ -1184,8 +1184,8 @@ fn test_show() {
     macro_rules! test_show_vec {
         ($x:expr, $x_str:expr) => {{
             let (x, x_str) = ($x, $x_str);
-            assert_eq!(format!("{:?}", x), x_str);
-            assert_eq!(format!("{:?}", x), x_str);
+            assert_eq!(format!("{x:?}"), x_str);
+            assert_eq!(format!("{x:?}"), x_str);
         }};
     }
     let empty = Vec::<i32>::new();
index 6b8be2506b64e5bc8d179eaae03798c003ce42f9..f3ed611acda5a6b69b7e822dba2f8cc21e6728d2 100644 (file)
@@ -1259,7 +1259,7 @@ fn test_chars_debug() {
     let s = "ศไทย中华Việt Nam";
     let c = s.chars();
     assert_eq!(
-        format!("{:?}", c),
+        format!("{c:?}"),
         r#"Chars(['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'])"#
     );
 }
@@ -1870,7 +1870,7 @@ fn cmp_search_to_vec<'a>(
         }
 
         if let Some(err) = err {
-            panic!("Input skipped range at {}", err);
+            panic!("Input skipped range at {err}");
         }
 
         if first_index != haystack.len() {
@@ -2187,10 +2187,10 @@ fn utf8() {
     fn check_str_eq(a: String, b: String) {
         let mut i: isize = 0;
         for ab in a.bytes() {
-            println!("{}", i);
-            println!("{}", ab);
+            println!("{i}");
+            println!("{ab}");
             let bb: u8 = b.as_bytes()[i as usize];
-            println!("{}", bb);
+            println!("{bb}");
             assert_eq!(ab, bb);
             i += 1;
         }
index 893283e5a248572658bff274b08be9445f379ca0..b6836fdc88ee8e3f4586da3441b1167c35e31ece 100644 (file)
@@ -470,7 +470,7 @@ fn test_simple_types() {
 #[test]
 fn test_vectors() {
     let x: Vec<i32> = vec![];
-    assert_eq!(format!("{:?}", x), "[]");
+    assert_eq!(format!("{x:?}"), "[]");
     assert_eq!(format!("{:?}", vec![1]), "[1]");
     assert_eq!(format!("{:?}", vec![1, 2, 3]), "[1, 2, 3]");
     assert!(format!("{:?}", vec![vec![], vec![1], vec![1, 1]]) == "[[], [1], [1, 1]]");
@@ -871,6 +871,6 @@ fn test_from_char() {
 fn test_str_concat() {
     let a: String = "hello".to_string();
     let b: String = "world".to_string();
-    let s: String = format!("{}{}", a, b);
+    let s: String = format!("{a}{b}");
     assert_eq!(s.as_bytes()[9], 'd' as u8);
 }
index 705914b44971c4fd011a2de1c48a4b220e897c93..ca0fcc855c7b8d03e7ab110e10214cd7e3e5d20b 100644 (file)
@@ -100,7 +100,7 @@ fn test_debug_fmt() {
     assert_eq!("[0, 1]", format!("{:?}", vec2));
 
     let slice: &[isize] = &[4, 5];
-    assert_eq!("[4, 5]", format!("{:?}", slice));
+    assert_eq!("[4, 5]", format!("{slice:?}"));
 }
 
 #[test]
@@ -918,7 +918,7 @@ fn test_into_iter_as_mut_slice() {
 fn test_into_iter_debug() {
     let vec = vec!['a', 'b', 'c'];
     let into_iter = vec.into_iter();
-    let debug = format!("{:?}", into_iter);
+    let debug = format!("{into_iter:?}");
     assert_eq!(debug, "IntoIter(['a', 'b', 'c'])");
 }
 
@@ -2336,7 +2336,7 @@ fn drop(&mut self) {
     let ok = vec.iter().zip(expected.iter()).all(|(x, y)| x.index == y.index);
 
     if !ok {
-        panic!("expected: {:?}\ngot: {:?}\n", expected, vec);
+        panic!("expected: {expected:?}\ngot: {vec:?}\n");
     }
 }
 
index 18954f094c671c2633d7dadbd080589500179ff3..89cc7f905be2cb304ef72dbad88b8524a0ca6bcf 100644 (file)
@@ -647,10 +647,10 @@ fn test_ord() {
 #[test]
 fn test_show() {
     let ringbuf: VecDeque<_> = (0..10).collect();
-    assert_eq!(format!("{:?}", ringbuf), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
+    assert_eq!(format!("{ringbuf:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
 
     let ringbuf: VecDeque<_> = vec!["just", "one", "test", "more"].iter().cloned().collect();
-    assert_eq!(format!("{:?}", ringbuf), "[\"just\", \"one\", \"test\", \"more\"]");
+    assert_eq!(format!("{ringbuf:?}"), "[\"just\", \"one\", \"test\", \"more\"]");
 }
 
 #[test]
index a1ce33d0bb49ef90f8f065874273e4cda9f39a3e..32fd5e626bc1f1334e79728b50586fb538450daa 100644 (file)
@@ -12,7 +12,7 @@ mod strategy {
 pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
     match decode(v).1 {
         FullDecoded::Finite(decoded) => decoded,
-        full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
+        full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
     }
 }
 
index 76425731e1ddda955c2bae64ed8f0a73c36f871b..8e47a046cdea5fc330308a9f91160c4d57dd820b 100644 (file)
@@ -6,7 +6,7 @@
 pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
     match decode(v).1 {
         FullDecoded::Finite(decoded) => decoded,
-        full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
+        full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
     }
 }
 
index 72528185707a67fec8cca43880bde8311444285e..3b15ab1e6895bfb84ff4e2fa10f65457e03d6282 100644 (file)
@@ -62,7 +62,7 @@
 //!             println!("String ({}): {}", as_string.len(), as_string);
 //!         }
 //!         None => {
-//!             println!("{:?}", value);
+//!             println!("{value:?}");
 //!         }
 //!     }
 //! }
index ee79021ed536e69555e6a8ba2c470549143fd7e8..20dfbc6347c4fb761f24ab5ee32ef864470ca301 100644 (file)
@@ -276,9 +276,10 @@ fn into_iter(self) -> IterMut<'a, T> {
 }
 
 #[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
-impl<T, I, const N: usize> Index<I> for [T; N]
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<T, I, const N: usize> const Index<I> for [T; N]
 where
-    [T]: Index<I>,
+    [T]: ~const Index<I>,
 {
     type Output = <[T] as Index<I>>::Output;
 
@@ -289,9 +290,10 @@ fn index(&self, index: I) -> &Self::Output {
 }
 
 #[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
-impl<T, I, const N: usize> IndexMut<I> for [T; N]
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<T, I, const N: usize> const IndexMut<I> for [T; N]
 where
-    [T]: IndexMut<I>,
+    [T]: ~const IndexMut<I>,
 {
     #[inline]
     fn index_mut(&mut self, index: I) -> &mut Self::Output {
index 532208e41afa2ba2b01169da64c061d0d5587347..8a4cb78cc7f92f5a2fabedad3f3342389d7b3b48 100644 (file)
@@ -98,22 +98,20 @@ pub fn escape_default(c: u8) -> EscapeDefault {
         b'\'' => ([b'\\', b'\'', 0, 0], 2),
         b'"' => ([b'\\', b'"', 0, 0], 2),
         b'\x20'..=b'\x7e' => ([c, 0, 0, 0], 1),
-        _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4),
+        _ => {
+            let hex_digits: &[u8; 16] = b"0123456789abcdef";
+            ([b'\\', b'x', hex_digits[(c >> 4) as usize], hex_digits[(c & 0xf) as usize]], 4)
+        }
     };
 
     return EscapeDefault { range: 0..len, data };
-
-    fn hexify(b: u8) -> u8 {
-        match b {
-            0..=9 => b'0' + b,
-            _ => b'a' + b - 10,
-        }
-    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Iterator for EscapeDefault {
     type Item = u8;
+
+    #[inline]
     fn next(&mut self) -> Option<u8> {
         self.range.next().map(|i| self.data[i as usize])
     }
index aef7ad77568036d29752182ea18a404ae1fc711b..9dbb5eecd469bd64a659435009fe58f93bfb401e 100644 (file)
@@ -85,7 +85,7 @@
 //!     // of scope then the subsequent borrow would cause a dynamic thread panic.
 //!     // This is the major hazard of using `RefCell`.
 //!     let total: i32 = shared_map.borrow().values().sum();
-//!     println!("{}", total);
+//!     println!("{total}");
 //! }
 //! ```
 //!
index 139841368d6a1c4096f329ee062e9041e194f64a..4ee0310b361fbce6f0d34a41c8e1b67b138d825f 100644 (file)
@@ -218,6 +218,8 @@ fn from(i: u8) -> Self {
 }
 
 /// An error which can be returned when parsing a char.
+///
+/// This `struct` is created when using the [`char::from_str`] method.
 #[stable(feature = "char_from_str", since = "1.20.0")]
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ParseCharError {
@@ -300,7 +302,10 @@ fn try_from(i: u32) -> Result<Self, Self::Error> {
     }
 }
 
-/// The error type returned when a conversion from u32 to char fails.
+/// The error type returned when a conversion from [`prim@u32`] to [`prim@char`] fails.
+///
+/// This `struct` is created by the [`char::try_from<u32>`](char#impl-TryFrom<u32>) method.
+/// See its documentation for more.
 #[stable(feature = "try_from", since = "1.34.0")]
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub struct CharTryFromError(());
index c4c0a5a6c78ad5059a882f1198aafa38da8cd7fd..66de94d1b92dc220b4cbd317270bab06aac578f2 100644 (file)
@@ -370,7 +370,7 @@ pub const fn to_digit(self, radix: u32) -> Option<u32> {
     ///
     /// ```
     /// for c in '❤'.escape_unicode() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
@@ -448,7 +448,7 @@ pub(crate) fn escape_debug_ext(self, args: EscapeDebugExtArgs) -> EscapeDebug {
     ///
     /// ```
     /// for c in '\n'.escape_debug() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
@@ -504,7 +504,7 @@ pub fn escape_debug(self) -> EscapeDebug {
     ///
     /// ```
     /// for c in '"'.escape_default() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
@@ -949,7 +949,7 @@ pub fn is_numeric(self) -> bool {
     ///
     /// ```
     /// for c in 'İ'.to_lowercase() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
@@ -1016,7 +1016,7 @@ pub fn to_lowercase(self) -> ToLowercase {
     ///
     /// ```
     /// for c in 'ß'.to_uppercase() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
index 6f9579043c37d0fc74973ec66a6ea0609598931e..1912694412b9874178aceb93db1234c9edbe78ae 100644 (file)
@@ -127,7 +127,11 @@ pub trait Clone: Sized {
     /// allocations.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    fn clone_from(&mut self, source: &Self) {
+    #[default_method_body_is_const]
+    fn clone_from(&mut self, source: &Self)
+    where
+        Self: ~const Drop,
+    {
         *self = source.clone()
     }
 }
@@ -178,7 +182,8 @@ macro_rules! impl_clone {
         ($($t:ty)*) => {
             $(
                 #[stable(feature = "rust1", since = "1.0.0")]
-                impl Clone for $t {
+                #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+                impl const Clone for $t {
                     #[inline]
                     fn clone(&self) -> Self {
                         *self
@@ -196,7 +201,8 @@ fn clone(&self) -> Self {
     }
 
     #[unstable(feature = "never_type", issue = "35121")]
-    impl Clone for ! {
+    #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+    impl const Clone for ! {
         #[inline]
         fn clone(&self) -> Self {
             *self
@@ -204,7 +210,8 @@ fn clone(&self) -> Self {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized> Clone for *const T {
+    #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+    impl<T: ?Sized> const Clone for *const T {
         #[inline]
         fn clone(&self) -> Self {
             *self
@@ -212,7 +219,8 @@ fn clone(&self) -> Self {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized> Clone for *mut T {
+    #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+    impl<T: ?Sized> const Clone for *mut T {
         #[inline]
         fn clone(&self) -> Self {
             *self
@@ -221,7 +229,8 @@ fn clone(&self) -> Self {
 
     /// Shared references can be cloned, but mutable references *cannot*!
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized> Clone for &T {
+    #[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+    impl<T: ?Sized> const Clone for &T {
         #[inline]
         #[rustc_diagnostic_item = "noop_method_clone"]
         fn clone(&self) -> Self {
index 0ceedf936333d6d4659998664d0e0b89d6b8d168..f5ea5f5ba50c0515df316aebc14376289edc3ae7 100644 (file)
@@ -300,7 +300,8 @@ pub trait Into<T>: Sized {
 /// that encapsulate multiple error types. See the "Examples" section and [the book][book] for more
 /// details.
 ///
-/// **Note: This trait must not fail**. If the conversion can fail, use [`TryFrom`].
+/// **Note: This trait must not fail**. The `From` trait is intended for perfect conversions.
+/// If the conversion can fail or is not perfect, use [`TryFrom`].
 ///
 /// # Generic Implementations
 ///
@@ -690,7 +691,8 @@ fn as_mut(&mut self) -> &mut str {
 pub enum Infallible {}
 
 #[stable(feature = "convert_infallible", since = "1.34.0")]
-impl Clone for Infallible {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl const Clone for Infallible {
     fn clone(&self) -> Infallible {
         match *self {}
     }
index 90c5719f486cb7674f9cd3c7ec5f5fe5a01ed378..84cf1753f86ba90913dcf73bbee66b323722aa3a 100644 (file)
@@ -64,7 +64,7 @@ pub mod rt {
 ///
 /// let pythagorean_triple = Triangle { a: 3.0, b: 4.0, c: 5.0 };
 ///
-/// assert_eq!(format!("{}", pythagorean_triple), "(3, 4, 5)");
+/// assert_eq!(format!("{pythagorean_triple}"), "(3, 4, 5)");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub type Result = result::Result<(), Error>;
@@ -174,7 +174,7 @@ fn write_char(&mut self, c: char) -> Result {
     /// use std::fmt::{Error, Write};
     ///
     /// fn writer<W: Write>(f: &mut W, s: &str) -> Result<(), Error> {
-    ///     f.write_fmt(format_args!("{}", s))
+    ///     f.write_fmt(format_args!("{s}"))
     /// }
     ///
     /// let mut buf = String::new();
@@ -562,7 +562,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// assert_eq!(format!("The origin is: {:?}", origin), "The origin is: Point { x: 0, y: 0 }");
+/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }");
 /// ```
 ///
 /// Manually implementing:
@@ -586,7 +586,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// assert_eq!(format!("The origin is: {:?}", origin), "The origin is: Point { x: 0, y: 0 }");
+/// assert_eq!(format!("The origin is: {origin:?}"), "The origin is: Point { x: 0, y: 0 }");
 /// ```
 ///
 /// There are a number of helper methods on the [`Formatter`] struct to help you with manual
@@ -627,7 +627,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// assert_eq!(format!("The origin is: {:#?}", origin),
+/// assert_eq!(format!("The origin is: {origin:#?}"),
 /// "The origin is: Point {
 ///     x: 0,
 ///     y: 0,
@@ -670,9 +670,9 @@ pub trait Debug {
     /// }
     ///
     /// let position = Position { longitude: 1.987, latitude: 2.983 };
-    /// assert_eq!(format!("{:?}", position), "(1.987, 2.983)");
+    /// assert_eq!(format!("{position:?}"), "(1.987, 2.983)");
     ///
-    /// assert_eq!(format!("{:#?}", position), "(
+    /// assert_eq!(format!("{position:#?}"), "(
     ///     1.987,
     ///     2.983,
     /// )");
@@ -724,7 +724,7 @@ pub(crate) mod macros {
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// assert_eq!(format!("The origin is: {}", origin), "The origin is: (0, 0)");
+/// assert_eq!(format!("The origin is: {origin}"), "The origin is: (0, 0)");
 /// ```
 #[rustc_on_unimplemented(
     on(
@@ -786,8 +786,8 @@ pub trait Display {
 /// ```
 /// let x = 42; // 42 is '52' in octal
 ///
-/// assert_eq!(format!("{:o}", x), "52");
-/// assert_eq!(format!("{:#o}", x), "0o52");
+/// assert_eq!(format!("{x:o}"), "52");
+/// assert_eq!(format!("{x:#o}"), "0o52");
 ///
 /// assert_eq!(format!("{:o}", -16), "37777777760");
 /// ```
@@ -809,9 +809,9 @@ pub trait Display {
 ///
 /// let l = Length(9);
 ///
-/// assert_eq!(format!("l as octal is: {:o}", l), "l as octal is: 11");
+/// assert_eq!(format!("l as octal is: {l:o}"), "l as octal is: 11");
 ///
-/// assert_eq!(format!("l as octal is: {:#06o}", l), "l as octal is: 0o0011");
+/// assert_eq!(format!("l as octal is: {l:#06o}"), "l as octal is: 0o0011");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Octal {
@@ -840,8 +840,8 @@ pub trait Octal {
 /// ```
 /// let x = 42; // 42 is '101010' in binary
 ///
-/// assert_eq!(format!("{:b}", x), "101010");
-/// assert_eq!(format!("{:#b}", x), "0b101010");
+/// assert_eq!(format!("{x:b}"), "101010");
+/// assert_eq!(format!("{x:#b}"), "0b101010");
 ///
 /// assert_eq!(format!("{:b}", -16), "11111111111111111111111111110000");
 /// ```
@@ -863,10 +863,10 @@ pub trait Octal {
 ///
 /// let l = Length(107);
 ///
-/// assert_eq!(format!("l as binary is: {:b}", l), "l as binary is: 1101011");
+/// assert_eq!(format!("l as binary is: {l:b}"), "l as binary is: 1101011");
 ///
 /// assert_eq!(
-///     format!("l as binary is: {:#032b}", l),
+///     format!("l as binary is: {l:#032b}"),
 ///     "l as binary is: 0b000000000000000000000001101011"
 /// );
 /// ```
@@ -898,8 +898,8 @@ pub trait Binary {
 /// ```
 /// let x = 42; // 42 is '2a' in hex
 ///
-/// assert_eq!(format!("{:x}", x), "2a");
-/// assert_eq!(format!("{:#x}", x), "0x2a");
+/// assert_eq!(format!("{x:x}"), "2a");
+/// assert_eq!(format!("{x:#x}"), "0x2a");
 ///
 /// assert_eq!(format!("{:x}", -16), "fffffff0");
 /// ```
@@ -921,9 +921,9 @@ pub trait Binary {
 ///
 /// let l = Length(9);
 ///
-/// assert_eq!(format!("l as hex is: {:x}", l), "l as hex is: 9");
+/// assert_eq!(format!("l as hex is: {l:x}"), "l as hex is: 9");
 ///
-/// assert_eq!(format!("l as hex is: {:#010x}", l), "l as hex is: 0x00000009");
+/// assert_eq!(format!("l as hex is: {l:#010x}"), "l as hex is: 0x00000009");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait LowerHex {
@@ -953,8 +953,8 @@ pub trait LowerHex {
 /// ```
 /// let x = 42; // 42 is '2A' in hex
 ///
-/// assert_eq!(format!("{:X}", x), "2A");
-/// assert_eq!(format!("{:#X}", x), "0x2A");
+/// assert_eq!(format!("{x:X}"), "2A");
+/// assert_eq!(format!("{x:#X}"), "0x2A");
 ///
 /// assert_eq!(format!("{:X}", -16), "FFFFFFF0");
 /// ```
@@ -976,9 +976,9 @@ pub trait LowerHex {
 ///
 /// let l = Length(i32::MAX);
 ///
-/// assert_eq!(format!("l as hex is: {:X}", l), "l as hex is: 7FFFFFFF");
+/// assert_eq!(format!("l as hex is: {l:X}"), "l as hex is: 7FFFFFFF");
 ///
-/// assert_eq!(format!("l as hex is: {:#010X}", l), "l as hex is: 0x7FFFFFFF");
+/// assert_eq!(format!("l as hex is: {l:#010X}"), "l as hex is: 0x7FFFFFFF");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait UpperHex {
@@ -1003,7 +1003,7 @@ pub trait UpperHex {
 /// ```
 /// let x = &42;
 ///
-/// let address = format!("{:p}", x); // this produces something like '0x7f06092ac6d0'
+/// let address = format!("{x:p}"); // this produces something like '0x7f06092ac6d0'
 /// ```
 ///
 /// Implementing `Pointer` on a type:
@@ -1024,9 +1024,9 @@ pub trait UpperHex {
 ///
 /// let l = Length(42);
 ///
-/// println!("l is in memory here: {:p}", l);
+/// println!("l is in memory here: {l:p}");
 ///
-/// let l_ptr = format!("{:018p}", l);
+/// let l_ptr = format!("{l:018p}");
 /// assert_eq!(l_ptr.len(), 18);
 /// assert_eq!(&l_ptr[..2], "0x");
 /// ```
@@ -1054,7 +1054,7 @@ pub trait Pointer {
 /// ```
 /// let x = 42.0; // 42.0 is '4.2e1' in scientific notation
 ///
-/// assert_eq!(format!("{:e}", x), "4.2e1");
+/// assert_eq!(format!("{x:e}"), "4.2e1");
 /// ```
 ///
 /// Implementing `LowerExp` on a type:
@@ -1074,12 +1074,12 @@ pub trait Pointer {
 /// let l = Length(100);
 ///
 /// assert_eq!(
-///     format!("l in scientific notation is: {:e}", l),
+///     format!("l in scientific notation is: {l:e}"),
 ///     "l in scientific notation is: 1e2"
 /// );
 ///
 /// assert_eq!(
-///     format!("l in scientific notation is: {:05e}", l),
+///     format!("l in scientific notation is: {l:05e}"),
 ///     "l in scientific notation is: 001e2"
 /// );
 /// ```
@@ -1105,7 +1105,7 @@ pub trait LowerExp {
 /// ```
 /// let x = 42.0; // 42.0 is '4.2E1' in scientific notation
 ///
-/// assert_eq!(format!("{:E}", x), "4.2E1");
+/// assert_eq!(format!("{x:E}"), "4.2E1");
 /// ```
 ///
 /// Implementing `UpperExp` on a type:
@@ -1125,12 +1125,12 @@ pub trait LowerExp {
 /// let l = Length(100);
 ///
 /// assert_eq!(
-///     format!("l in scientific notation is: {:E}", l),
+///     format!("l in scientific notation is: {l:E}"),
 ///     "l in scientific notation is: 1E2"
 /// );
 ///
 /// assert_eq!(
-///     format!("l in scientific notation is: {:05E}", l),
+///     format!("l in scientific notation is: {l:05E}"),
 ///     "l in scientific notation is: 001E2"
 /// );
 /// ```
@@ -1429,8 +1429,8 @@ fn write_prefix(f: &mut Formatter<'_>, sign: Option<char>, prefix: Option<&str>)
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{:<4}", Foo), "Foo ");
-    /// assert_eq!(&format!("{:0>4}", Foo), "0Foo");
+    /// assert_eq!(&format!("{Foo:<4}"), "Foo ");
+    /// assert_eq!(&format!("{Foo:0>4}"), "0Foo");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn pad(&mut self, s: &str) -> Result {
@@ -1613,8 +1613,8 @@ fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result {
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{}", Foo), "Foo");
-    /// assert_eq!(&format!("{:0>8}", Foo), "Foo");
+    /// assert_eq!(&format!("{Foo}"), "Foo");
+    /// assert_eq!(&format!("{Foo:0>8}"), "Foo");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn write_str(&mut self, data: &str) -> Result {
@@ -1670,18 +1670,18 @@ pub fn flags(&self) -> u32 {
     ///         let c = formatter.fill();
     ///         if let Some(width) = formatter.width() {
     ///             for _ in 0..width {
-    ///                 write!(formatter, "{}", c)?;
+    ///                 write!(formatter, "{c}")?;
     ///             }
     ///             Ok(())
     ///         } else {
-    ///             write!(formatter, "{}", c)
+    ///             write!(formatter, "{c}")
     ///         }
     ///     }
     /// }
     ///
     /// // We set alignment to the right with ">".
-    /// assert_eq!(&format!("{:G>3}", Foo), "GGG");
-    /// assert_eq!(&format!("{:t>6}", Foo), "tttttt");
+    /// assert_eq!(&format!("{Foo:G>3}"), "GGG");
+    /// assert_eq!(&format!("{Foo:t>6}"), "tttttt");
     /// ```
     #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
@@ -1711,14 +1711,14 @@ pub fn fill(&self) -> char {
     ///         } else {
     ///             "into the void"
     ///         };
-    ///         write!(formatter, "{}", s)
+    ///         write!(formatter, "{s}")
     ///     }
     /// }
     ///
-    /// assert_eq!(&format!("{:<}", Foo), "left");
-    /// assert_eq!(&format!("{:>}", Foo), "right");
-    /// assert_eq!(&format!("{:^}", Foo), "center");
-    /// assert_eq!(&format!("{}", Foo), "into the void");
+    /// assert_eq!(&format!("{Foo:<}"), "left");
+    /// assert_eq!(&format!("{Foo:>}"), "right");
+    /// assert_eq!(&format!("{Foo:^}"), "center");
+    /// assert_eq!(&format!("{Foo}"), "into the void");
     /// ```
     #[must_use]
     #[stable(feature = "fmt_flags_align", since = "1.28.0")]
index 0912f8675fa84d18467f88806fd4ae83367097e1..8014dacdd98da6887b938cd1b377582b28f3e4a3 100644 (file)
@@ -9,20 +9,20 @@ pub trait IntoFuture {
 
     /// Which kind of future are we turning this into?
     #[unstable(feature = "into_future", issue = "67644")]
-    type Future: Future<Output = Self::Output>;
+    type IntoFuture: Future<Output = Self::Output>;
 
     /// Creates a future from a value.
     #[unstable(feature = "into_future", issue = "67644")]
     #[lang = "into_future"]
-    fn into_future(self) -> Self::Future;
+    fn into_future(self) -> Self::IntoFuture;
 }
 
 #[unstable(feature = "into_future", issue = "67644")]
 impl<F: Future> IntoFuture for F {
     type Output = F::Output;
-    type Future = F;
+    type IntoFuture = F;
 
-    fn into_future(self) -> Self::Future {
+    fn into_future(self) -> Self::IntoFuture {
         self
     }
 }
index 330c43d2948357f3951c7a4e3cdd69407499f3f9..58ea109c735b67afbde616c0d21cb46ce1890ca0 100644 (file)
@@ -173,3 +173,126 @@ pub fn spin_loop() {
 pub const fn black_box<T>(dummy: T) -> T {
     crate::intrinsics::black_box(dummy)
 }
+
+/// An identity function that causes an `unused_must_use` warning to be
+/// triggered if the given value is not used (returned, stored in a variable,
+/// etc) by the caller.
+///
+/// This is primarily intended for use in macro-generated code, in which a
+/// [`#[must_use]` attribute][must_use] either on a type or a function would not
+/// be convenient.
+///
+/// [must_use]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
+///
+/// # Example
+///
+/// ```
+/// #![feature(hint_must_use)]
+///
+/// use core::fmt;
+///
+/// pub struct Error(/* ... */);
+///
+/// #[macro_export]
+/// macro_rules! make_error {
+///     ($($args:expr),*) => {
+///         core::hint::must_use({
+///             let error = $crate::make_error(core::format_args!($($args),*));
+///             error
+///         })
+///     };
+/// }
+///
+/// // Implementation detail of make_error! macro.
+/// #[doc(hidden)]
+/// pub fn make_error(args: fmt::Arguments<'_>) -> Error {
+///     Error(/* ... */)
+/// }
+///
+/// fn demo() -> Option<Error> {
+///     if true {
+///         // Oops, meant to write `return Some(make_error!("..."));`
+///         Some(make_error!("..."));
+///     }
+///     None
+/// }
+/// #
+/// # // Make rustdoc not wrap the whole snippet in fn main, so that $crate::make_error works
+/// # fn main() {}
+/// ```
+///
+/// In the above example, we'd like an `unused_must_use` lint to apply to the
+/// value created by `make_error!`. However, neither `#[must_use]` on a struct
+/// nor `#[must_use]` on a function is appropriate here, so the macro expands
+/// using `core::hint::must_use` instead.
+///
+/// - We wouldn't want `#[must_use]` on the `struct Error` because that would
+///   make the following unproblematic code trigger a warning:
+///
+///   ```
+///   # struct Error;
+///   #
+///   fn f(arg: &str) -> Result<(), Error>
+///   # { Ok(()) }
+///
+///   #[test]
+///   fn t() {
+///       // Assert that `f` returns error if passed an empty string.
+///       // A value of type `Error` is unused here but that's not a problem.
+///       f("").unwrap_err();
+///   }
+///   ```
+///
+/// - Using `#[must_use]` on `fn make_error` can't help because the return value
+///   *is* used, as the right-hand side of a `let` statement. The `let`
+///   statement looks useless but is in fact necessary for ensuring that
+///   temporaries within the `format_args` expansion are not kept alive past the
+///   creation of the `Error`, as keeping them alive past that point can cause
+///   autotrait issues in async code:
+///
+///   ```
+///   # #![feature(hint_must_use)]
+///   #
+///   # struct Error;
+///   #
+///   # macro_rules! make_error {
+///   #     ($($args:expr),*) => {
+///   #         core::hint::must_use({
+///   #             // If `let` isn't used, then `f()` produces a non-Send future.
+///   #             let error = make_error(core::format_args!($($args),*));
+///   #             error
+///   #         })
+///   #     };
+///   # }
+///   #
+///   # fn make_error(args: core::fmt::Arguments<'_>) -> Error {
+///   #     Error
+///   # }
+///   #
+///   async fn f() {
+///       // Using `let` inside the make_error expansion causes temporaries like
+///       // `unsync()` to drop at the semicolon of that `let` statement, which
+///       // is prior to the await point. They would otherwise stay around until
+///       // the semicolon on *this* statement, which is after the await point,
+///       // and the enclosing Future would not implement Send.
+///       log(make_error!("look: {:p}", unsync())).await;
+///   }
+///
+///   async fn log(error: Error) {/* ... */}
+///
+///   // Returns something without a Sync impl.
+///   fn unsync() -> *const () {
+///       0 as *const ()
+///   }
+///   #
+///   # fn test() {
+///   #     fn assert_send(_: impl Send) {}
+///   #     assert_send(f());
+///   # }
+///   ```
+#[unstable(feature = "hint_must_use", issue = "94745")]
+#[rustc_const_unstable(feature = "hint_must_use", issue = "94745")]
+#[must_use] // <-- :)
+pub const fn must_use<T>(value: T) -> T {
+    value
+}
index d2077a63e150a96b6d589ec7d836fe7fab107be5..4b03449972c9a7273f078f6c01fed1da1882a742 100644 (file)
@@ -34,7 +34,7 @@
 ///
 /// for pair in ['a', 'b', 'c'].into_iter()
 ///                                .map(|letter| { c += 1; (letter, c) }) {
-///     println!("{:?}", pair);
+///     println!("{pair:?}");
 /// }
 /// ```
 ///
@@ -52,7 +52,7 @@
 /// for pair in ['a', 'b', 'c'].into_iter()
 ///                                .map(|letter| { c += 1; (letter, c) })
 ///                                .rev() {
-///     println!("{:?}", pair);
+///     println!("{pair:?}");
 /// }
 /// ```
 #[must_use = "iterators are lazy and do nothing unless consumed"]
index 65f56f64dbfa63ab850ed3b696d857ec4320b154..5a987733134a466739b3f5fd3461d816035bf295 100644 (file)
 //! let values = vec![1, 2, 3, 4, 5];
 //!
 //! for x in values {
-//!     println!("{}", x);
+//!     println!("{x}");
 //! }
 //! ```
 //!
 //! let values = vec![1, 2, 3, 4, 5];
 //!
 //! for x in values {
-//!     println!("{}", x);
+//!     println!("{x}");
 //! }
 //! ```
 //!
 //!                 None => break,
 //!             };
 //!             let x = next;
-//!             let () = { println!("{}", x); };
+//!             let () = { println!("{x}"); };
 //!         },
 //!     };
 //!     result
 //! ```
 //! # #![allow(unused_must_use)]
 //! let v = vec![1, 2, 3, 4, 5];
-//! v.iter().map(|x| println!("{}", x));
+//! v.iter().map(|x| println!("{x}"));
 //! ```
 //!
 //! This will not print any values, as we only created an iterator, rather than
 //! ```
 //! let v = vec![1, 2, 3, 4, 5];
 //!
-//! v.iter().for_each(|x| println!("{}", x));
+//! v.iter().for_each(|x| println!("{x}"));
 //! // or
 //! for x in &v {
-//!     println!("{}", x);
+//!     println!("{x}");
 //! }
 //! ```
 //!
 //! let five_numbers = numbers.take(5);
 //!
 //! for number in five_numbers {
-//!     println!("{}", number);
+//!     println!("{number}");
 //! }
 //! ```
 //!
 //! let ones = std::iter::repeat(1);
 //! let least = ones.min().unwrap(); // Oh no! An infinite loop!
 //! // `ones.min()` causes an infinite loop, so we won't reach this point!
-//! println!("The smallest number one is {}.", least);
+//! println!("The smallest number one is {least}.");
 //! ```
 //!
 //! [`take`]: Iterator::take
index 27bc3dcfd79e092c40765099519d3aee6a242e0a..6e9ed0d3c527806ff1568ebbc810b694ab06b8b1 100644 (file)
@@ -48,7 +48,7 @@
 ///
 /// // this will give us all of the files in .foo as well as .foorc
 /// for f in files {
-///     println!("{:?}", f);
+///     println!("{f:?}");
 /// }
 /// ```
 #[stable(feature = "iter_once", since = "1.2.0")]
index cf6a3c115245295de66ae010f0c50b85c6501f13..d79f85c2559fedf5f3e2f0641f8ca69a71c57edd 100644 (file)
@@ -52,7 +52,7 @@
 ///
 /// // this will give us all of the files in .foo as well as .foorc
 /// for f in files {
-///     println!("{:?}", f);
+///     println!("{f:?}");
 /// }
 /// ```
 #[inline]
index 637d7bc44885e96902413d6eed0290f06004babf..7b75ab96ee7deea69f7f194b115490bc51702a64 100644 (file)
@@ -4,9 +4,11 @@
 /// created from an iterator. This is common for types which describe a
 /// collection of some kind.
 ///
-/// [`FromIterator::from_iter()`] is rarely called explicitly, and is instead
-/// used through [`Iterator::collect()`] method. See [`Iterator::collect()`]'s
-/// documentation for more examples.
+/// If you want to create a collection from the contents of an iterator, the
+/// [`Iterator::collect()`] method is preferred. However, when you need to
+/// specify the container type, [`FromIterator::from_iter()`] can be more
+/// readable than using a turbofish (e.g. `::<Vec<_>>()`). See the
+/// [`Iterator::collect()`] documentation for more examples of its use.
 ///
 /// See also: [`IntoIterator`].
 ///
 /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
 /// ```
 ///
+/// Using [`FromIterator::from_iter()`] as a more readable alternative to
+/// [`Iterator::collect()`]:
+///
+/// ```
+/// use std::collections::VecDeque;
+/// let first = (0..10).collect::<VecDeque<i32>>();
+/// let second = VecDeque::from_iter(0..10);
+///
+/// assert_eq!(first, second);
+/// ```
+///
 /// Implementing `FromIterator` for your type:
 ///
 /// ```
@@ -214,7 +227,7 @@ pub trait FromIterator<A>: Sized {
 /// {
 ///     collection
 ///         .into_iter()
-///         .map(|item| format!("{:?}", item))
+///         .map(|item| format!("{item:?}"))
 ///         .collect()
 /// }
 /// ```
@@ -332,7 +345,7 @@ fn into_iter(self) -> I {
 /// c.extend(vec![1, 2, 3]);
 ///
 /// // we've added these elements onto the end
-/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{:?}", c));
+/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{c:?}"));
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Extend<A> {
index a6aed6d210beb9ea50a34caef132f809246b5895..bdf94c792c27c34a3742392440ea53cb7e4adeda 100644 (file)
@@ -281,7 +281,7 @@ fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
     /// let zero = "0".to_string();
     ///
     /// let result = numbers.iter().rfold(zero, |acc, &x| {
-    ///     format!("({} + {})", x, acc)
+    ///     format!("({x} + {acc})")
     /// });
     ///
     /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))");
index f5c0a3b5cd849b0b3c71bf2652bb3aec3be9733d..d980f5930810bc1cf7ca5fad70f9203a9e69dffa 100644 (file)
@@ -34,6 +34,11 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
         note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
               to have a bounded `RangeInclusive`: `0..=end`"
     ),
+    on(
+        _Self = "[]",
+        label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
+    ),
+    on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
     on(
         _Self = "&str",
         label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
@@ -704,13 +709,13 @@ fn intersperse_with<G>(self, separator: G) -> IntersperseWith<Self, G>
     /// ```
     /// # #![allow(unused_must_use)]
     /// // don't do this:
-    /// (0..5).map(|x| println!("{}", x));
+    /// (0..5).map(|x| println!("{x}"));
     ///
     /// // it won't even execute, as it is lazy. Rust will warn you about this.
     ///
     /// // Instead, use for:
     /// for x in 0..5 {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     #[inline]
@@ -756,7 +761,7 @@ fn map<B, F>(self, f: F) -> Map<Self, F>
     /// (0..5).flat_map(|x| x * 100 .. x * 110)
     ///       .enumerate()
     ///       .filter(|&(i, x)| (i + x) % 3 == 0)
-    ///       .for_each(|(i, x)| println!("{}:{}", i, x));
+    ///       .for_each(|(i, x)| println!("{i}:{x}"));
     /// ```
     #[inline]
     #[stable(feature = "iterator_for_each", since = "1.21.0")]
@@ -1570,17 +1575,17 @@ fn fuse(self) -> Fuse<Self>
     ///     .filter(|x| x % 2 == 0)
     ///     .fold(0, |sum, i| sum + i);
     ///
-    /// println!("{}", sum);
+    /// println!("{sum}");
     ///
     /// // let's add some inspect() calls to investigate what's happening
     /// let sum = a.iter()
     ///     .cloned()
-    ///     .inspect(|x| println!("about to filter: {}", x))
+    ///     .inspect(|x| println!("about to filter: {x}"))
     ///     .filter(|x| x % 2 == 0)
-    ///     .inspect(|x| println!("made it through filter: {}", x))
+    ///     .inspect(|x| println!("made it through filter: {x}"))
     ///     .fold(0, |sum, i| sum + i);
     ///
-    /// println!("{}", sum);
+    /// println!("{sum}");
     /// ```
     ///
     /// This will print:
@@ -1606,13 +1611,13 @@ fn fuse(self) -> Fuse<Self>
     ///     .map(|line| line.parse::<i32>())
     ///     .inspect(|num| {
     ///         if let Err(ref e) = *num {
-    ///             println!("Parsing error: {}", e);
+    ///             println!("Parsing error: {e}");
     ///         }
     ///     })
     ///     .filter_map(Result::ok)
     ///     .sum();
     ///
-    /// println!("Sum: {}", sum);
+    /// println!("Sum: {sum}");
     /// ```
     ///
     /// This will print:
@@ -1859,6 +1864,77 @@ fn try_collect<B>(&mut self) -> ChangeOutputType<Self::Item, B>
         try_process(self, |i| i.collect())
     }
 
+    /// Collects all the items from an iterator into a collection.
+    ///
+    /// This method consumes the iterator and adds all its items to the
+    /// passed collection. The collection is then returned, so the call chain
+    /// can be continued.
+    ///
+    /// This is useful when you already have a collection and wants to add
+    /// the iterator items to it.
+    ///
+    /// This method is a convenience method to call [Extend::extend](trait.Extend.html),
+    /// but instead of being called on a collection, it's called on an iterator.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_collect_into)]
+    ///
+    /// let a = [1, 2, 3];
+    /// let mut vec: Vec::<i32> = vec![0, 1];
+    ///
+    /// a.iter().map(|&x| x * 2).collect_into(&mut vec);
+    /// a.iter().map(|&x| x * 10).collect_into(&mut vec);
+    ///
+    /// assert_eq!(vec![0, 1, 2, 4, 6, 10, 20, 30], vec);
+    /// ```
+    ///
+    /// `Vec` can have a manual set capacity to avoid reallocating it:
+    ///
+    /// ```
+    /// #![feature(iter_collect_into)]
+    ///
+    /// let a = [1, 2, 3];
+    /// let mut vec: Vec::<i32> = Vec::with_capacity(6);
+    ///
+    /// a.iter().map(|&x| x * 2).collect_into(&mut vec);
+    /// a.iter().map(|&x| x * 10).collect_into(&mut vec);
+    ///
+    /// assert_eq!(6, vec.capacity());
+    /// println!("{:?}", vec);
+    /// ```
+    ///
+    /// The returned mutable reference can be used to continue the call chain:
+    ///
+    /// ```
+    /// #![feature(iter_collect_into)]
+    ///
+    /// let a = [1, 2, 3];
+    /// let mut vec: Vec::<i32> = Vec::with_capacity(6);
+    ///
+    /// let count = a.iter().collect_into(&mut vec).iter().count();
+    ///
+    /// assert_eq!(count, vec.len());
+    /// println!("Vec len is {}", count);
+    ///
+    /// let count = a.iter().collect_into(&mut vec).iter().count();
+    ///
+    /// assert_eq!(count, vec.len());
+    /// println!("Vec len now is {}", count);
+    /// ```
+    #[inline]
+    #[unstable(feature = "iter_collect_into", reason = "new API", issue = "94780")]
+    fn collect_into<E: Extend<Self::Item>>(self, collection: &mut E) -> &mut E
+    where
+        Self: Sized,
+    {
+        collection.extend(self);
+        collection
+    }
+
     /// Consumes an iterator, creating two collections from it.
     ///
     /// The predicate passed to `partition()` can return `true`, or `false`.
@@ -2129,7 +2205,7 @@ fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
     ///
     /// let data = ["no_tea.txt", "stale_bread.json", "torrential_rain.png"];
     ///
-    /// let res = data.iter().try_for_each(|x| writeln!(stdout(), "{}", x));
+    /// let res = data.iter().try_for_each(|x| writeln!(stdout(), "{x}"));
     /// assert!(res.is_ok());
     ///
     /// let mut it = data.iter().cloned();
@@ -2243,7 +2319,7 @@ fn call<T, R>(mut f: impl FnMut(T) -> R) -> impl FnMut((), T) -> R {
     /// let zero = "0".to_string();
     ///
     /// let result = numbers.iter().fold(zero, |acc, &x| {
-    ///     format!("({} + {})", acc, x)
+    ///     format!("({acc} + {x})")
     /// });
     ///
     /// assert_eq!(result, "(((((0 + 1) + 2) + 3) + 4) + 5)");
index 45fbcf44b350cbe5a40acedcc53d0546b731c438..1ab7481b7baaec665f893cd12031ff92cc2f2377 100644 (file)
 #![feature(const_caller_location)]
 #![feature(const_cell_into_inner)]
 #![feature(const_char_convert)]
+#![feature(const_clone)]
 #![feature(const_discriminant)]
 #![feature(const_eval_select)]
 #![feature(const_float_bits_conv)]
 #![feature(variant_count)]
 #![feature(const_array_from_ref)]
 #![feature(const_slice_from_ref)]
+#![feature(const_slice_index)]
+#![feature(const_is_char_boundary)]
 //
 // Language features:
 #![feature(abi_unadjusted)]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_has_atomic_equal_alignment)]
 #![feature(const_fn_floating_point_arithmetic)]
-#![feature(const_fn_fn_ptr_basics)]
-#![feature(const_fn_trait_bound)]
-#![feature(const_impl_trait)]
+#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
+#![cfg_attr(bootstrap, feature(const_impl_trait))]
 #![feature(const_mut_refs)]
 #![feature(const_precise_live_drops)]
 #![feature(const_refs_to_cell)]
 #![feature(decl_macro)]
 #![feature(derive_default_enum)]
+#![cfg_attr(not(bootstrap), feature(deprecated_suggestion))]
 #![feature(doc_cfg)]
 #![feature(doc_notable_trait)]
 #![feature(rustdoc_internals)]
@@ -408,12 +412,10 @@ pub mod arch {
 #[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
 #[allow(rustdoc::bare_urls)]
 #[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(all(miri, doctest)))] // Skip SIMD doctests in Miri
 mod core_simd;
 
 #[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
 #[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(all(miri, doctest)))] // Skip SIMD doctests in Miri
 pub mod simd {
     #[unstable(feature = "portable_simd", issue = "86656")]
     pub use crate::core_simd::simd::*;
index 65a2c3ff6edc9ea6bf0ad4df9a22ee779507ac3a..ba7ae55ec6f4bbcd8d22a74a407fdd44bb447dfc 100644 (file)
@@ -895,7 +895,7 @@ macro_rules! format_args_nl {
     ///
     /// ```
     /// let path: &'static str = env!("PATH");
-    /// println!("the $PATH variable at the time of compiling was: {}", path);
+    /// println!("the $PATH variable at the time of compiling was: {path}");
     /// ```
     ///
     /// You can customize the error message by passing a string as the second
@@ -935,7 +935,7 @@ macro_rules! env {
     ///
     /// ```
     /// let key: Option<&'static str> = option_env!("SECRET_KEY");
-    /// println!("the secret key might be: {:?}", key);
+    /// println!("the secret key might be: {key:?}");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
@@ -1046,7 +1046,7 @@ macro_rules! concat {
     ///
     /// ```
     /// let current_line = line!();
-    /// println!("defined on line: {}", current_line);
+    /// println!("defined on line: {current_line}");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
@@ -1074,7 +1074,7 @@ macro_rules! line {
     ///
     /// ```
     /// let current_col = column!();
-    /// println!("defined on column: {}", current_col);
+    /// println!("defined on column: {current_col}");
     /// ```
     ///
     /// `column!` counts Unicode code points, not bytes or graphemes. As a result, the first two
@@ -1112,7 +1112,7 @@ macro_rules! column {
     ///
     /// ```
     /// let this_file = file!();
-    /// println!("defined in file: {}", this_file);
+    /// println!("defined in file: {this_file}");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
@@ -1176,7 +1176,7 @@ macro_rules! stringify {
     /// fn main() {
     ///     let my_str = include_str!("spanish.in");
     ///     assert_eq!(my_str, "adiós\n");
-    ///     print!("{}", my_str);
+    ///     print!("{my_str}");
     /// }
     /// ```
     ///
@@ -1325,7 +1325,7 @@ macro_rules! cfg {
     /// fn main() {
     ///     let my_string = include!("monkeys.in");
     ///     assert_eq!("🙈🙊🙉🙈🙊🙉", my_string);
-    ///     println!("{}", my_string);
+    ///     println!("{my_string}");
     /// }
     /// ```
     ///
index 71eea43aa54e1451a46d4eb23d0255a834bd4839..82bac2640b40596bd6b97e7a9ac5beb35412f716 100644 (file)
@@ -219,7 +219,7 @@ pub trait StructuralEq {
 ///
 /// // `x` has moved into `y`, and so cannot be used
 ///
-/// // println!("{:?}", x); // error: use of moved value
+/// // println!("{x:?}"); // error: use of moved value
 /// ```
 ///
 /// However, if a type implements `Copy`, it instead has 'copy semantics':
@@ -236,7 +236,7 @@ pub trait StructuralEq {
 ///
 /// // `y` is a copy of `x`
 ///
-/// println!("{:?}", x); // A-OK!
+/// println!("{x:?}"); // A-OK!
 /// ```
 ///
 /// It's important to note that in these two examples, the only difference is whether you
index 2b280773e4c50a2f64abbf7fa8a0386d067b2d7c..541adb69b8e2b400b9cfb04184e0e895644222ac 100644 (file)
@@ -112,21 +112,24 @@ impl FromStr for $t {
             /// * '2.5E-10'
             /// * '5.'
             /// * '.5', or, equivalently, '0.5'
-            /// * 'inf', '-inf', 'NaN'
+            /// * 'inf', '-inf', '+infinity', 'NaN'
+            ///
+            /// Note that alphabetical characters are not case-sensitive.
             ///
             /// Leading and trailing whitespace represent an error.
             ///
             /// # Grammar
             ///
-            /// All strings that adhere to the following [EBNF] grammar
-            /// will result in an [`Ok`] being returned:
+            /// All strings that adhere to the following [EBNF] grammar when
+            /// lowercased will result in an [`Ok`] being returned:
             ///
             /// ```txt
-            /// Float  ::= Sign? ( 'inf' | 'NaN' | Number )
+            /// Float  ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number )
             /// Number ::= ( Digit+ |
+            ///              '.' Digit* |
             ///              Digit+ '.' Digit* |
             ///              Digit* '.' Digit+ ) Exp?
-            /// Exp    ::= [eE] Sign? Digit+
+            /// Exp    ::= 'e' Sign? Digit+
             /// Sign   ::= [+-]
             /// Digit  ::= [0-9]
             /// ```
@@ -163,7 +166,7 @@ fn from_str(src: &str) -> Result<Self, ParseFloatError> {
 /// use std::str::FromStr;
 ///
 /// if let Err(e) = f64::from_str("a.12") {
-///     println!("Failed conversion to f64: {}", e);
+///     println!("Failed conversion to f64: {e}");
 /// }
 /// ```
 #[derive(Debug, Clone, PartialEq, Eq)]
index 8a9ecbe98dff604a3bc158005236aa66e8dda68e..1a223016dae0fa18850d17d981dd7e57613d17f3 100644 (file)
@@ -61,7 +61,7 @@ fn from(never: !) -> TryFromIntError {
 ///
 /// ```
 /// if let Err(e) = i32::from_str_radix("a12", 10) {
-///     println!("Failed conversion to i32: {}", e);
+///     println!("Failed conversion to i32: {e}");
 /// }
 /// ```
 #[derive(Debug, Clone, PartialEq, Eq)]
index 199af081560f592e23fecc9f10b8de007cf83ad3..3665573ab0ff2577ee00c296113d8061be4f1b5d 100644 (file)
@@ -2166,7 +2166,8 @@ pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
 
             let r = try_opt!(self.checked_rem(rhs));
             let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
-                try_opt!(r.checked_add(rhs))
+                // r + rhs cannot overflow because they have opposite signs
+                r + rhs
             } else {
                 r
             };
@@ -2174,7 +2175,8 @@ pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
             if m == 0 {
                 Some(self)
             } else {
-                self.checked_add(try_opt!(rhs.checked_sub(m)))
+                // rhs - m cannot overflow because m has the same sign as rhs
+                self.checked_add(rhs - m)
             }
         }
 
index 72105888f9447f2eac6c277754d157d38dd0b6c3..07fd317e07486ff9493c992699974070d54bf852 100644 (file)
@@ -809,7 +809,7 @@ pub fn escape_ascii(self) -> ascii::EscapeDefault {
         ascii::escape_default(self)
     }
 
-    pub(crate) fn is_utf8_char_boundary(self) -> bool {
+    pub(crate) const fn is_utf8_char_boundary(self) -> bool {
         // This is bit magic equivalent to: b < 128 || b >= 192
         (self as i8) >= -0x40
     }
index 1ebd1c58f2b59dc3b8b02e743becc57cc17b6ed3..5bdd78aa2dea4d9808041546c80d7786750b6eb8 100644 (file)
@@ -989,3 +989,104 @@ pub const fn is_power_of_two(self) -> bool {
 }
 
 nonzero_unsigned_is_power_of_two! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize }
+
+macro_rules! nonzero_min_max_unsigned {
+    ( $( $Ty: ident($Int: ident); )+ ) => {
+        $(
+            impl $Ty {
+                /// The smallest value that can be represented by this non-zero
+                /// integer type, 1.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_min_max)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), 1", stringify!($Int), ");")]
+                /// ```
+                #[unstable(feature = "nonzero_min_max", issue = "89065")]
+                pub const MIN: Self = Self::new(1).unwrap();
+
+                /// The largest value that can be represented by this non-zero
+                /// integer type,
+                #[doc = concat!("equal to [`", stringify!($Int), "::MAX`].")]
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_min_max)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")]
+                /// ```
+                #[unstable(feature = "nonzero_min_max", issue = "89065")]
+                pub const MAX: Self = Self::new(<$Int>::MAX).unwrap();
+            }
+        )+
+    }
+}
+
+macro_rules! nonzero_min_max_signed {
+    ( $( $Ty: ident($Int: ident); )+ ) => {
+        $(
+            impl $Ty {
+                /// The smallest value that can be represented by this non-zero
+                /// integer type,
+                #[doc = concat!("equal to [`", stringify!($Int), "::MIN`].")]
+                ///
+                /// Note: While most integer types are defined for every whole
+                /// number between `MIN` and `MAX`, signed non-zero integers are
+                /// a special case. They have a "gap" at 0.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_min_max)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), ", stringify!($Int), "::MIN);")]
+                /// ```
+                #[unstable(feature = "nonzero_min_max", issue = "89065")]
+                pub const MIN: Self = Self::new(<$Int>::MIN).unwrap();
+
+                /// The largest value that can be represented by this non-zero
+                /// integer type,
+                #[doc = concat!("equal to [`", stringify!($Int), "::MAX`].")]
+                ///
+                /// Note: While most integer types are defined for every whole
+                /// number between `MIN` and `MAX`, signed non-zero integers are
+                /// a special case. They have a "gap" at 0.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_min_max)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")]
+                /// ```
+                #[unstable(feature = "nonzero_min_max", issue = "89065")]
+                pub const MAX: Self = Self::new(<$Int>::MAX).unwrap();
+            }
+        )+
+    }
+}
+
+nonzero_min_max_unsigned! {
+    NonZeroU8(u8);
+    NonZeroU16(u16);
+    NonZeroU32(u32);
+    NonZeroU64(u64);
+    NonZeroU128(u128);
+    NonZeroUsize(usize);
+}
+
+nonzero_min_max_signed! {
+    NonZeroI8(i8);
+    NonZeroI16(i16);
+    NonZeroI32(i32);
+    NonZeroI64(i64);
+    NonZeroI128(i128);
+    NonZeroIsize(isize);
+}
index feec448ebbdb318e687386ef772b49bdd579e1b9..baa23e08fe774fa70f6ed20bdc168f33312edf89 100644 (file)
@@ -2119,7 +2119,8 @@ pub const fn next_multiple_of(self, rhs: Self) -> Self {
         pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
             match try_opt!(self.checked_rem(rhs)) {
                 0 => Some(self),
-                r => self.checked_add(try_opt!(rhs.checked_sub(r)))
+                // rhs - r cannot overflow because r is smaller than rhs
+                r => self.checked_add(rhs - r)
             }
         }
 
index 964378cc9c3c6d394ab8a37d789c90e8e7c9ca29..e2e569cb7ea81aa0ddc9a7e8da43ccc3c4711646 100644 (file)
@@ -106,7 +106,7 @@ pub trait Index<Idx: ?Sized> {
 ///     type Output = Weight;
 ///
 ///     fn index(&self, index: Side) -> &Self::Output {
-///         println!("Accessing {:?}-side of balance immutably", index);
+///         println!("Accessing {index:?}-side of balance immutably");
 ///         match index {
 ///             Side::Left => &self.left,
 ///             Side::Right => &self.right,
@@ -116,7 +116,7 @@ pub trait Index<Idx: ?Sized> {
 ///
 /// impl IndexMut<Side> for Balance {
 ///     fn index_mut(&mut self, index: Side) -> &mut Self::Output {
-///         println!("Accessing {:?}-side of balance mutably", index);
+///         println!("Accessing {index:?}-side of balance mutably");
 ///         match index {
 ///             Side::Left => &mut self.left,
 ///             Side::Right => &mut self.right,
index 1136722067874250be22bfba32ef44aa126a213b..a3b14847342cbcdc4ad9f57e54165ac24b9fb327 100644 (file)
@@ -446,7 +446,7 @@ impl RangeInclusive<usize> {
     /// Converts to an exclusive `Range` for `SliceIndex` implementations.
     /// The caller is responsible for dealing with `end == usize::MAX`.
     #[inline]
-    pub(crate) fn into_slice_range(self) -> Range<usize> {
+    pub(crate) const fn into_slice_range(self) -> Range<usize> {
         // If we're not exhausted, we want to simply slice `start..end + 1`.
         // If we are exhausted, then slicing with `end + 1..end + 1` gives us an
         // empty range that is still subject to bounds-checks for that endpoint.
@@ -653,7 +653,7 @@ pub fn contains<U>(&self, item: &U) -> bool
 /// map.insert(8, "c");
 ///
 /// for (key, value) in map.range((Excluded(3), Included(8))) {
-///     println!("{}: {}", key, value);
+///     println!("{key}: {value}");
 /// }
 ///
 /// assert_eq!(Some((&3, &"a")), map.range((Unbounded, Included(5))).next());
index 508837f63c3bee8d7bad27fc71c02b68f8f36e9b..de1628f83ade8adbbfa26327b7be9d6b8da3dd4f 100644 (file)
@@ -34,7 +34,7 @@
 //! // Pattern match to retrieve the value
 //! match result {
 //!     // The division was valid
-//!     Some(x) => println!("Result: {}", x),
+//!     Some(x) => println!("Result: {x}"),
 //!     // The division was invalid
 //!     None    => println!("Cannot divide by 0"),
 //! }
@@ -66,7 +66,7 @@
 //!
 //! fn check_optional(optional: Option<Box<i32>>) {
 //!     match optional {
-//!         Some(p) => println!("has value {}", p),
+//!         Some(p) => println!("has value {p}"),
 //!         None => println!("has no value"),
 //!     }
 //! }
 //! }
 //!
 //! match name_of_biggest_animal {
-//!     Some(name) => println!("the biggest animal is {}", name),
+//!     Some(name) => println!("the biggest animal is {name}"),
 //!     None => println!("there are no animals :("),
 //! }
 //! ```
@@ -551,7 +551,7 @@ pub const fn is_some(&self) -> bool {
         matches!(*self, Some(_))
     }
 
-    /// Returns `true` if the option is a [`Some`] wrapping a value matching the predicate.
+    /// Returns `true` if the option is a [`Some`] and the value inside of it matches a predicate.
     ///
     /// # Examples
     ///
@@ -559,18 +559,18 @@ pub const fn is_some(&self) -> bool {
     /// #![feature(is_some_with)]
     ///
     /// let x: Option<u32> = Some(2);
-    /// assert_eq!(x.is_some_with(|&x| x > 1), true);
+    /// assert_eq!(x.is_some_and(|&x| x > 1), true);
     ///
     /// let x: Option<u32> = Some(0);
-    /// assert_eq!(x.is_some_with(|&x| x > 1), false);
+    /// assert_eq!(x.is_some_and(|&x| x > 1), false);
     ///
     /// let x: Option<u32> = None;
-    /// assert_eq!(x.is_some_with(|&x| x > 1), false);
+    /// assert_eq!(x.is_some_and(|&x| x > 1), false);
     /// ```
     #[must_use]
     #[inline]
     #[unstable(feature = "is_some_with", issue = "93050")]
-    pub fn is_some_with(&self, f: impl FnOnce(&T) -> bool) -> bool {
+    pub fn is_some_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
         matches!(self, Some(x) if f(x))
     }
 
@@ -615,7 +615,7 @@ pub const fn is_none(&self) -> bool {
     /// // First, cast `Option<String>` to `Option<&String>` with `as_ref`,
     /// // then consume *that* with `map`, leaving `text` on the stack.
     /// let text_length: Option<usize> = text.as_ref().map(|s| s.len());
-    /// println!("still can print text: {:?}", text);
+    /// println!("still can print text: {text:?}");
     /// ```
     #[inline]
     #[rustc_const_stable(feature = "const_option", since = "1.48.0")]
@@ -918,10 +918,10 @@ pub const fn map<U, F>(self, f: F) -> Option<U>
     /// let v = vec![1, 2, 3, 4, 5];
     ///
     /// // prints "got: 4"
-    /// let x: Option<&usize> = v.get(3).inspect(|x| println!("got: {}", x));
+    /// let x: Option<&usize> = v.get(3).inspect(|x| println!("got: {x}"));
     ///
     /// // prints nothing
-    /// let x: Option<&usize> = v.get(5).inspect(|x| println!("got: {}", x));
+    /// let x: Option<&usize> = v.get(5).inspect(|x| println!("got: {x}"));
     /// ```
     #[inline]
     #[unstable(feature = "result_option_inspect", issue = "91345")]
@@ -1857,7 +1857,11 @@ const fn expect_failed(msg: &str) -> ! {
 /////////////////////////////////////////////////////////////////////////////
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone> Clone for Option<T> {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl<T> const Clone for Option<T>
+where
+    T: ~const Clone + ~const Drop,
+{
     #[inline]
     fn clone(&self) -> Self {
         match self {
@@ -1972,7 +1976,7 @@ impl<'a, T> const From<&'a Option<T>> for Option<&'a T> {
     /// let s: Option<String> = Some(String::from("Hello, Rustaceans!"));
     /// let o: Option<usize> = Option::from(&s).map(|ss: &String| ss.len());
     ///
-    /// println!("Can still print s: {:?}", s);
+    /// println!("Can still print s: {s:?}");
     ///
     /// assert_eq!(o, Some(18));
     /// ```
index be8598fae09d793a8859a0e9dac14e2cd9fa3dbe..1923155ebc15f388aa484464b5534b70d7e09f3d 100644 (file)
@@ -16,7 +16,7 @@
 ///
 /// panic::set_hook(Box::new(|panic_info| {
 ///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
-///         println!("panic occurred: {:?}", s);
+///         println!("panic occurred: {s:?}");
 ///     } else {
 ///         println!("panic occurred");
 ///     }
@@ -75,7 +75,7 @@ pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
     ///
     /// panic::set_hook(Box::new(|panic_info| {
     ///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
-    ///         println!("panic occurred: {:?}", s);
+    ///         println!("panic occurred: {s:?}");
     ///     } else {
     ///         println!("panic occurred");
     ///     }
index 89cebaa653f4ba9ebee10cba5958555c1ec7f9ab..a908b1f3ba4ce7ed46911d8279e3c9f3a3e43818 100644 (file)
@@ -39,7 +39,7 @@
 #[rustc_const_unstable(feature = "core_panic", issue = "none")]
 #[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
 pub const fn panic(expr: &'static str) -> ! {
-    // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
+    // Use Arguments::new_v1 instead of format_args!("{expr}") to potentially
     // reduce size overhead. The format_args! macro uses str's Display trait to
     // write expr, which calls Formatter::pad, which must accommodate string
     // truncation and padding (even though none is used here). Using
@@ -81,7 +81,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
         super::intrinsics::abort()
     }
 
-    panic!("index out of bounds: the len is {} but the index is {}", len, index)
+    panic!("index out of bounds: the len is {len} but the index is {index}")
 }
 
 // This function is called directly by the codegen backend, and must not have
index 775d2ded9daad2c1933df0769d9d47b9b44cd88f..cef6a68b4d329e5d2f7ef343ce53880bcc33b888 100644 (file)
@@ -954,7 +954,7 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
 /// stuff(pin!(Foo { /* … */ }));
 /// ```
 ///
-/// ### Manually polling a `Future` (wihout `Unpin` bounds)
+/// ### Manually polling a `Future` (without `Unpin` bounds)
 ///
 /// ```rust
 /// #![feature(pin_macro)]
index ebb1d8971b99ddd63cf89315cea88df043983ebd..225a679efd22132ced410bf29008fbd7e3212ee0 100644 (file)
@@ -607,7 +607,7 @@ mod prim_pointer {}
 ///
 /// // This loop prints: 0 1 2
 /// for x in array {
-///     print!("{} ", x);
+///     print!("{x} ");
 /// }
 /// ```
 ///
@@ -646,19 +646,19 @@ mod prim_pointer {}
 /// // This creates a slice iterator, producing references to each value.
 /// for item in array.into_iter().enumerate() {
 ///     let (i, x): (usize, &i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 ///
 /// // The `array_into_iter` lint suggests this change for future compatibility:
 /// for item in array.iter().enumerate() {
 ///     let (i, x): (usize, &i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 ///
 /// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
 /// for item in IntoIterator::into_iter(array).enumerate() {
 ///     let (i, x): (usize, i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 /// ```
 ///
@@ -673,13 +673,13 @@ mod prim_pointer {}
 /// // This iterates by reference:
 /// for item in array.iter().enumerate() {
 ///     let (i, x): (usize, &i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 ///
 /// // This iterates by value:
 /// for item in array.into_iter().enumerate() {
 ///     let (i, x): (usize, i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 /// ```
 ///
@@ -702,26 +702,26 @@ mod prim_pointer {}
 /// // This iterates by reference:
 /// for item in array.iter() {
 ///     let x: &i32 = item;
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // This iterates by value:
 /// for item in IntoIterator::into_iter(array) {
 ///     let x: i32 = item;
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // This iterates by value:
 /// for item in array {
 ///     let x: i32 = item;
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // IntoIter can also start a chain.
 /// // This iterates by value:
 /// for item in IntoIterator::into_iter(array).enumerate() {
 ///     let (i, x): (usize, i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 /// ```
 ///
index 485a5965f4cf740c4b17084c83141645dbef53a3..753220669831fee882e9c5bf2e8ed527ea8aa356 100644 (file)
@@ -153,7 +153,7 @@ pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata)
     ///
     /// unsafe {
     ///     if let Some(val_back) = ptr.as_ref() {
-    ///         println!("We got back the value: {}!", val_back);
+    ///         println!("We got back the value: {val_back}!");
     ///     }
     /// }
     /// ```
@@ -169,7 +169,7 @@ pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata)
     ///
     /// unsafe {
     ///     let val_back = &*ptr;
-    ///     println!("We got back the value: {}!", val_back);
+    ///     println!("We got back the value: {val_back}!");
     /// }
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
@@ -1032,10 +1032,11 @@ pub const fn as_ptr(self) -> *const T {
     /// }
     /// ```
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
+    pub const unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
     where
-        I: SliceIndex<[T]>,
+        I: ~const SliceIndex<[T]>,
     {
         // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
         unsafe { index.get_unchecked(self) }
index 1412e836ebfc28b94759befa73195ea0c0c52965..861412703d3c668acdfbe7f1041f25fcc2563248 100644 (file)
@@ -160,7 +160,7 @@ pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
     ///
     /// unsafe {
     ///     if let Some(val_back) = ptr.as_ref() {
-    ///         println!("We got back the value: {}!", val_back);
+    ///         println!("We got back the value: {val_back}!");
     ///     }
     /// }
     /// ```
@@ -176,7 +176,7 @@ pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
     ///
     /// unsafe {
     ///     let val_back = &*ptr;
-    ///     println!("We got back the value: {}!", val_back);
+    ///     println!("We got back the value: {val_back}!");
     /// }
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
@@ -409,7 +409,7 @@ pub const fn wrapping_offset(self, count: isize) -> *mut T
     /// let first_value = unsafe { ptr.as_mut().unwrap() };
     /// *first_value = 4;
     /// # assert_eq!(s, [4, 2, 3]);
-    /// println!("{:?}", s); // It'll print: "[4, 2, 3]".
+    /// println!("{s:?}"); // It'll print: "[4, 2, 3]".
     /// ```
     ///
     /// # Null-unchecked version
@@ -424,7 +424,7 @@ pub const fn wrapping_offset(self, count: isize) -> *mut T
     /// let first_value = unsafe { &mut *ptr };
     /// *first_value = 4;
     /// # assert_eq!(s, [4, 2, 3]);
-    /// println!("{:?}", s); // It'll print: "[4, 2, 3]".
+    /// println!("{s:?}"); // It'll print: "[4, 2, 3]".
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
     #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
@@ -1302,10 +1302,11 @@ pub const fn as_mut_ptr(self) -> *mut T {
     /// }
     /// ```
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline(always)]
-    pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
+    pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
     where
-        I: SliceIndex<[T]>,
+        I: ~const SliceIndex<[T]>,
     {
         // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
         unsafe { index.get_unchecked_mut(self) }
index 0aa8e9960a8dd706db63cd1575f4a4ced3804880..a698aec51ca71ef662b3c5dfc0b8f8a0893ec25a 100644 (file)
@@ -314,7 +314,7 @@ pub const fn as_ptr(self) -> *mut T {
     /// let ptr = NonNull::new(&mut x as *mut _).expect("ptr is null!");
     ///
     /// let ref_x = unsafe { ptr.as_ref() };
-    /// println!("{}", ref_x);
+    /// println!("{ref_x}");
     /// ```
     ///
     /// [the module documentation]: crate::ptr#safety
@@ -630,10 +630,11 @@ pub const fn as_mut_ptr(self) -> *mut T {
     /// }
     /// ```
     #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
+    pub const unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
     where
-        I: SliceIndex<[T]>,
+        I: ~const SliceIndex<[T]>,
     {
         // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
         // As a consequence, the resulting pointer cannot be null.
@@ -642,7 +643,8 @@ pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> Clone for NonNull<T> {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl<T: ?Sized> const Clone for NonNull<T> {
     #[inline]
     fn clone(&self) -> Self {
         *self
index 661d111c99d5294b7d7bf79db10aad7c5bb2b936..cff68f64f78e08c3d793ee051aec959c8369920b 100644 (file)
@@ -146,7 +146,8 @@ pub const fn cast<U>(self) -> Unique<U> {
 }
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> Clone for Unique<T> {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl<T: ?Sized> const Clone for Unique<T> {
     #[inline]
     fn clone(&self) -> Self {
         *self
index 801e3a0b3a4ccaf34038d70ed286bd3185d7802f..9a243cbc3a2a0a1311a8336ed52782cc09d3f770 100644 (file)
@@ -35,8 +35,8 @@
 //!
 //! let version = parse_version(&[1, 2, 3, 4]);
 //! match version {
-//!     Ok(v) => println!("working with version: {:?}", v),
-//!     Err(e) => println!("error parsing header: {:?}", e),
+//!     Ok(v) => println!("working with version: {v:?}"),
+//!     Err(e) => println!("error parsing header: {e:?}"),
 //! }
 //! ```
 //!
 //!    .collect();
 //! assert_eq!(errs.len(), 3);
 //! assert_eq!(nums, [17, 99]);
-//! println!("results {:?}", results);
-//! println!("errs {:?}", errs);
-//! println!("nums {:?}", nums);
+//! println!("results {results:?}");
+//! println!("errs {errs:?}");
+//! println!("nums {nums:?}");
 //! ```
 //!
 //! ## Collecting into `Result`
@@ -542,7 +542,7 @@ pub const fn is_ok(&self) -> bool {
         matches!(*self, Ok(_))
     }
 
-    /// Returns `true` if the result is [`Ok`] wrapping a value matching the predicate.
+    /// Returns `true` if the result is [`Ok`] and the value inside of it matches a predicate.
     ///
     /// # Examples
     ///
@@ -550,18 +550,18 @@ pub const fn is_ok(&self) -> bool {
     /// #![feature(is_some_with)]
     ///
     /// let x: Result<u32, &str> = Ok(2);
-    /// assert_eq!(x.is_ok_with(|&x| x > 1), true);
+    /// assert_eq!(x.is_ok_and(|&x| x > 1), true);
     ///
     /// let x: Result<u32, &str> = Ok(0);
-    /// assert_eq!(x.is_ok_with(|&x| x > 1), false);
+    /// assert_eq!(x.is_ok_and(|&x| x > 1), false);
     ///
     /// let x: Result<u32, &str> = Err("hey");
-    /// assert_eq!(x.is_ok_with(|&x| x > 1), false);
+    /// assert_eq!(x.is_ok_and(|&x| x > 1), false);
     /// ```
     #[must_use]
     #[inline]
     #[unstable(feature = "is_some_with", issue = "93050")]
-    pub fn is_ok_with(&self, f: impl FnOnce(&T) -> bool) -> bool {
+    pub fn is_ok_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
         matches!(self, Ok(x) if f(x))
     }
 
@@ -586,7 +586,7 @@ pub const fn is_err(&self) -> bool {
         !self.is_ok()
     }
 
-    /// Returns `true` if the result is [`Err`] wrapping a value matching the predicate.
+    /// Returns `true` if the result is [`Err`] and the value inside of it matches a predicate.
     ///
     /// # Examples
     ///
@@ -595,18 +595,18 @@ pub const fn is_err(&self) -> bool {
     /// use std::io::{Error, ErrorKind};
     ///
     /// let x: Result<u32, Error> = Err(Error::new(ErrorKind::NotFound, "!"));
-    /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), true);
+    /// assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), true);
     ///
     /// let x: Result<u32, Error> = Err(Error::new(ErrorKind::PermissionDenied, "!"));
-    /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false);
+    /// assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);
     ///
     /// let x: Result<u32, Error> = Ok(123);
-    /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false);
+    /// assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);
     /// ```
     #[must_use]
     #[inline]
     #[unstable(feature = "is_some_with", issue = "93050")]
-    pub fn is_err_with(&self, f: impl FnOnce(&E) -> bool) -> bool {
+    pub fn is_err_and(&self, f: impl FnOnce(&E) -> bool) -> bool {
         matches!(self, Err(x) if f(x))
     }
 
@@ -632,10 +632,16 @@ pub fn is_err_with(&self, f: impl FnOnce(&E) -> bool) -> bool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn ok(self) -> Option<T> {
+    #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
+    pub const fn ok(self) -> Option<T>
+    where
+        E: ~const Drop,
+    {
         match self {
             Ok(x) => Some(x),
-            Err(_) => None,
+            // FIXME: ~const Drop doesn't quite work right yet
+            #[allow(unused_variables)]
+            Err(x) => None,
         }
     }
 
@@ -657,9 +663,15 @@ pub fn ok(self) -> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn err(self) -> Option<E> {
+    #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
+    pub const fn err(self) -> Option<E>
+    where
+        T: ~const Drop,
+    {
         match self {
-            Ok(_) => None,
+            // FIXME: ~const Drop doesn't quite work right yet
+            #[allow(unused_variables)]
+            Ok(x) => None,
             Err(x) => Some(x),
         }
     }
@@ -744,7 +756,7 @@ pub const fn as_mut(&mut self) -> Result<&mut T, &mut E> {
     ///
     /// for num in line.lines() {
     ///     match num.parse::<i32>().map(|i| i * 2) {
-    ///         Ok(n) => println!("{}", n),
+    ///         Ok(n) => println!("{n}"),
     ///         Err(..) => {}
     ///     }
     /// }
@@ -826,7 +838,7 @@ pub fn map_or_else<U, D: FnOnce(E) -> U, F: FnOnce(T) -> U>(self, default: D, f:
     /// Basic usage:
     ///
     /// ```
-    /// fn stringify(x: u32) -> String { format!("error code: {}", x) }
+    /// fn stringify(x: u32) -> String { format!("error code: {x}") }
     ///
     /// let x: Result<u32, u32> = Ok(2);
     /// assert_eq!(x.map_err(stringify), Ok(2));
@@ -852,7 +864,7 @@ pub fn map_err<F, O: FnOnce(E) -> F>(self, op: O) -> Result<T, F> {
     ///
     /// let x: u8 = "4"
     ///     .parse::<u8>()
-    ///     .inspect(|x| println!("original: {}", x))
+    ///     .inspect(|x| println!("original: {x}"))
     ///     .map(|x| x.pow(3))
     ///     .expect("failed to parse number");
     /// ```
@@ -877,7 +889,7 @@ pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self {
     ///
     /// fn read() -> io::Result<String> {
     ///     fs::read_to_string("address.txt")
-    ///         .inspect_err(|e| eprintln!("failed to read file: {}", e))
+    ///         .inspect_err(|e| eprintln!("failed to read file: {e}"))
     /// }
     /// ```
     #[inline]
@@ -1186,7 +1198,7 @@ pub fn unwrap_err(self) -> E
     /// }
     ///
     /// let s: String = only_good_news().into_ok();
-    /// println!("{}", s);
+    /// println!("{s}");
     /// ```
     #[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
     #[inline]
@@ -1223,7 +1235,7 @@ pub fn into_ok(self) -> T
     /// }
     ///
     /// let error: String = only_bad_news().into_err();
-    /// println!("{}", error);
+    /// println!("{error}");
     /// ```
     #[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
     #[inline]
@@ -1266,10 +1278,18 @@ pub fn into_err(self) -> E
     /// assert_eq!(x.and(y), Ok("different result type"));
     /// ```
     #[inline]
+    #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn and<U>(self, res: Result<U, E>) -> Result<U, E> {
+    pub const fn and<U>(self, res: Result<U, E>) -> Result<U, E>
+    where
+        T: ~const Drop,
+        U: ~const Drop,
+        E: ~const Drop,
+    {
         match self {
-            Ok(_) => res,
+            // FIXME: ~const Drop doesn't quite work right yet
+            #[allow(unused_variables)]
+            Ok(x) => res,
             Err(e) => Err(e),
         }
     }
@@ -1343,11 +1363,19 @@ pub fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E> {
     /// assert_eq!(x.or(y), Ok(2));
     /// ```
     #[inline]
+    #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn or<F>(self, res: Result<T, F>) -> Result<T, F> {
+    pub const fn or<F>(self, res: Result<T, F>) -> Result<T, F>
+    where
+        T: ~const Drop,
+        E: ~const Drop,
+        F: ~const Drop,
+    {
         match self {
             Ok(v) => Ok(v),
-            Err(_) => res,
+            // FIXME: ~const Drop doesn't quite work right yet
+            #[allow(unused_variables)]
+            Err(e) => res,
         }
     }
 
@@ -1399,11 +1427,18 @@ pub fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F> {
     /// assert_eq!(x.unwrap_or(default), default);
     /// ```
     #[inline]
+    #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_or(self, default: T) -> T {
+    pub const fn unwrap_or(self, default: T) -> T
+    where
+        T: ~const Drop,
+        E: ~const Drop,
+    {
         match self {
             Ok(t) => t,
-            Err(_) => default,
+            // FIXME: ~const Drop doesn't quite work right yet
+            #[allow(unused_variables)]
+            Err(e) => default,
         }
     }
 
@@ -1746,7 +1781,7 @@ pub const fn into_ok_or_err(self) -> T {
 #[cold]
 #[track_caller]
 fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
-    panic!("{}: {:?}", msg, error)
+    panic!("{msg}: {error:?}")
 }
 
 // This is a separate function to avoid constructing a `dyn Debug`
@@ -1766,7 +1801,12 @@ fn unwrap_failed<T>(_msg: &str, _error: &T) -> ! {
 /////////////////////////////////////////////////////////////////////////////
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone, E: Clone> Clone for Result<T, E> {
+#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
+impl<T, E> const Clone for Result<T, E>
+where
+    T: ~const Clone + ~const Drop,
+    E: ~const Clone + ~const Drop,
+{
     #[inline]
     fn clone(&self) -> Self {
         match self {
index 0298bba8d329eb9c2fb078196344741d5c93cf33..3353c239866af4440020d16981acf3dd6890fe53 100644 (file)
@@ -1,12 +1,14 @@
 //! Indexing implementations for `[T]`.
 
+use crate::intrinsics::const_eval_select;
 use crate::ops;
 use crate::ptr;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, I> ops::Index<I> for [T]
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<T, I> const ops::Index<I> for [T]
 where
-    I: SliceIndex<[T]>,
+    I: ~const SliceIndex<[T]>,
 {
     type Output = I::Output;
 
@@ -17,9 +19,10 @@ fn index(&self, index: I) -> &I::Output {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, I> ops::IndexMut<I> for [T]
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<T, I> const ops::IndexMut<I> for [T]
 where
-    I: SliceIndex<[T]>,
+    I: ~const SliceIndex<[T]>,
 {
     #[inline]
     fn index_mut(&mut self, index: I) -> &mut I::Output {
@@ -31,31 +34,72 @@ fn index_mut(&mut self, index: I) -> &mut I::Output {
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
-fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
-    panic!("range start index {} out of range for slice of length {}", index, len);
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
+    // SAFETY: we are just panicking here
+    unsafe {
+        const_eval_select(
+            (index, len),
+            slice_start_index_len_fail_ct,
+            slice_start_index_len_fail_rt,
+        )
+    }
+}
+
+// FIXME const-hack
+fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! {
+    panic!("range start index {index} out of range for slice of length {len}");
+}
+
+const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
+    panic!("slice start index is out of range for slice");
 }
 
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
-fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
-    panic!("range end index {} out of range for slice of length {}", index, len);
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
+    // SAFETY: we are just panicking here
+    unsafe {
+        const_eval_select((index, len), slice_end_index_len_fail_ct, slice_end_index_len_fail_rt)
+    }
+}
+
+// FIXME const-hack
+fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! {
+    panic!("range end index {index} out of range for slice of length {len}");
+}
+
+const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
+    panic!("slice end index is out of range for slice");
 }
 
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
-fn slice_index_order_fail(index: usize, end: usize) -> ! {
-    panic!("slice index starts at {} but ends at {}", index, end);
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+const fn slice_index_order_fail(index: usize, end: usize) -> ! {
+    // SAFETY: we are just panicking here
+    unsafe { const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt) }
+}
+
+// FIXME const-hack
+fn slice_index_order_fail_rt(index: usize, end: usize) -> ! {
+    panic!("slice index starts at {index} but ends at {end}");
+}
+
+const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! {
+    panic!("slice index start is larger than end");
 }
 
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
-fn slice_start_index_overflow_fail() -> ! {
+const fn slice_start_index_overflow_fail() -> ! {
     panic!("attempted to index slice from after maximum usize");
 }
 
@@ -63,7 +107,7 @@ fn slice_start_index_overflow_fail() -> ! {
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
-fn slice_end_index_overflow_fail() -> ! {
+const fn slice_end_index_overflow_fail() -> ! {
     panic!("attempted to index slice up to maximum usize");
 }
 
@@ -153,7 +197,8 @@ pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for usize {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for usize {
     type Output = T;
 
     #[inline]
@@ -197,7 +242,8 @@ fn index_mut(self, slice: &mut [T]) -> &mut T {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
     type Output = [T];
 
     #[inline]
@@ -261,7 +307,8 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeTo<usize> {
     type Output = [T];
 
     #[inline]
@@ -298,7 +345,8 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
     type Output = [T];
 
     #[inline]
@@ -343,7 +391,8 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeFull {
     type Output = [T];
 
     #[inline]
@@ -378,7 +427,8 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
 }
 
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
     type Output = [T];
 
     #[inline]
@@ -421,7 +471,8 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
 }
 
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::RangeToInclusive<usize> {
     type Output = [T];
 
     #[inline]
index d260cc69469cf00b5c512c3804090fba8ea403d5..82bd7dbcf6cd2e54ad6b13dea88538da0ca248db 100644 (file)
@@ -55,7 +55,7 @@ fn size_from_ptr<T>(_: *const T) -> usize {
 ///
 /// // Then, we iterate over it:
 /// for element in slice.iter() {
-///     println!("{}", element);
+///     println!("{element}");
 /// }
 /// ```
 ///
@@ -176,7 +176,7 @@ fn as_ref(&self) -> &[T] {
 /// }
 ///
 /// // We now have "[2, 3, 4]":
-/// println!("{:?}", slice);
+/// println!("{slice:?}");
 /// ```
 ///
 /// [`iter_mut`]: slice::iter_mut
@@ -266,7 +266,7 @@ pub(super) fn new(slice: &'a mut [T]) -> Self {
     ///     *iter.next().unwrap() += 1;
     /// }
     /// // Now slice is "[2, 2, 3]":
-    /// println!("{:?}", slice);
+    /// println!("{slice:?}");
     /// ```
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "iter_to_slice", since = "1.4.0")]
index 9467c7f54bac7d56d5062017675b0ef520da4d27..32d8988f1492ef8807c927410674ad26a70a5689 100644 (file)
@@ -16,7 +16,6 @@
 use crate::ptr;
 use crate::result::Result;
 use crate::result::Result::{Err, Ok};
-#[cfg(not(all(miri, doctest)))] // Miri skips SIMD doctests
 use crate::simd::{self, Simd};
 use crate::slice;
 
@@ -324,10 +323,11 @@ pub const fn last_mut(&mut self) -> Option<&mut T> {
     /// assert_eq!(None, v.get(0..4));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub fn get<I>(&self, index: I) -> Option<&I::Output>
+    pub const fn get<I>(&self, index: I) -> Option<&I::Output>
     where
-        I: SliceIndex<Self>,
+        I: ~const SliceIndex<Self>,
     {
         index.get(self)
     }
@@ -348,10 +348,11 @@ pub fn get<I>(&self, index: I) -> Option<&I::Output>
     /// assert_eq!(x, &[0, 42, 2]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
+    pub const fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
     where
-        I: SliceIndex<Self>,
+        I: ~const SliceIndex<Self>,
     {
         index.get_mut(self)
     }
@@ -379,10 +380,11 @@ pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
+    pub const unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
     where
-        I: SliceIndex<Self>,
+        I: ~const SliceIndex<Self>,
     {
         // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`;
         // the slice is dereferenceable because `self` is a safe reference.
@@ -415,10 +417,11 @@ pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
     /// assert_eq!(x, &[1, 13, 4]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
+    pub const unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
     where
-        I: SliceIndex<Self>,
+        I: ~const SliceIndex<Self>,
     {
         // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`;
         // the slice is dereferenceable because `self` is a safe reference.
@@ -2008,7 +2011,7 @@ pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<'_, T, F>
     /// let v = [10, 40, 30, 20, 60, 50];
     ///
     /// for group in v.splitn(2, |num| *num % 3 == 0) {
-    ///     println!("{:?}", group);
+    ///     println!("{group:?}");
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -2063,7 +2066,7 @@ pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F>
     /// let v = [10, 40, 30, 20, 60, 50];
     ///
     /// for group in v.rsplitn(2, |num| *num % 3 == 0) {
-    ///     println!("{:?}", group);
+    ///     println!("{group:?}");
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -3540,7 +3543,6 @@ pub unsafe fn align_to_mut<U>(&mut self) -> (&mut [T], &mut [U], &mut [T]) {
     /// assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0);
     /// ```
     #[unstable(feature = "portable_simd", issue = "86656")]
-    #[cfg(not(all(miri, doctest)))] // Miri skips SIMD doctests
     pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
     where
         Simd<T, LANES>: AsRef<[T; LANES]>,
@@ -3584,7 +3586,6 @@ pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
     /// be lifted in a way that would make it possible to see panics from this
     /// method for something like `LANES == 3`.
     #[unstable(feature = "portable_simd", issue = "86656")]
-    #[cfg(not(all(miri, doctest)))] // Miri skips SIMD doctests
     pub fn as_simd_mut<const LANES: usize>(&mut self) -> (&mut [T], &mut [Simd<T, LANES>], &mut [T])
     where
         Simd<T, LANES>: AsMut<[T; LANES]>,
index 09709dc3cf6dfbd187f2ecfe020ad0a6a07fbe33..b1d36f2710737980efb8983f57be581005db892b 100644 (file)
 #[inline(never)]
 #[cold]
 #[track_caller]
-fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
+#[rustc_allow_const_fn_unstable(const_eval_select)]
+const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
+    // SAFETY: panics for both branches
+    unsafe {
+        crate::intrinsics::const_eval_select(
+            (s, begin, end),
+            slice_error_fail_ct,
+            slice_error_fail_rt,
+        )
+    }
+}
+
+const fn slice_error_fail_ct(_: &str, _: usize, _: usize) -> ! {
+    panic!("failed to slice string");
+}
+
+fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! {
     const MAX_DISPLAY_LENGTH: usize = 256;
     let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH);
     let s_trunc = &s[..trunc_len];
@@ -88,7 +104,7 @@ fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
     // 1. out of bounds
     if begin > s.len() || end > s.len() {
         let oob_index = if begin > s.len() { begin } else { end };
-        panic!("byte index {} is out of bounds of `{}`{}", oob_index, s_trunc, ellipsis);
+        panic!("byte index {oob_index} is out of bounds of `{s_trunc}`{ellipsis}");
     }
 
     // 2. begin <= end
@@ -189,8 +205,9 @@ pub const fn is_empty(&self) -> bool {
     /// ```
     #[must_use]
     #[stable(feature = "is_char_boundary", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_is_char_boundary", issue = "none")]
     #[inline]
-    pub fn is_char_boundary(&self, index: usize) -> bool {
+    pub const fn is_char_boundary(&self, index: usize) -> bool {
         // 0 is always ok.
         // Test for 0 explicitly so that it can optimize out the check
         // easily and skip reading string data for that case.
@@ -418,8 +435,9 @@ pub fn as_mut_ptr(&mut self) -> *mut u8 {
     /// assert!(v.get(..42).is_none());
     /// ```
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
+    pub const fn get<I: ~const SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
         i.get(self)
     }
 
@@ -450,8 +468,9 @@ pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
     /// assert_eq!("HEllo", v);
     /// ```
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
+    pub const fn get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
         i.get_mut(self)
     }
 
@@ -482,8 +501,9 @@ pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
     /// }
     /// ```
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
+    pub const unsafe fn get_unchecked<I: ~const SliceIndex<str>>(&self, i: I) -> &I::Output {
         // SAFETY: the caller must uphold the safety contract for `get_unchecked`;
         // the slice is dereferenceable because `self` is a safe reference.
         // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
@@ -517,8 +537,12 @@ pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
     /// }
     /// ```
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
+    #[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
     #[inline]
-    pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
+    pub const unsafe fn get_unchecked_mut<I: ~const SliceIndex<str>>(
+        &mut self,
+        i: I,
+    ) -> &mut I::Output {
         // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
         // the slice is dereferenceable because `self` is a safe reference.
         // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
@@ -2422,7 +2446,7 @@ pub fn make_ascii_lowercase(&mut self) {
     ///
     /// ```
     /// for c in "❤\n!".escape_debug() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
@@ -2468,7 +2492,7 @@ pub fn escape_debug(&self) -> EscapeDebug<'_> {
     ///
     /// ```
     /// for c in "❤\n!".escape_default() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
@@ -2506,7 +2530,7 @@ pub fn escape_default(&self) -> EscapeDefault<'_> {
     ///
     /// ```
     /// for c in "❤\n!".escape_unicode() {
-    ///     print!("{}", c);
+    ///     print!("{c}");
     /// }
     /// println!();
     /// ```
index 952676247489f938b1db7970fc9e97d94134e7b3..8b6b4fa02f8334525efd44c2f4a1a8de620cb6e1 100644 (file)
@@ -53,9 +53,10 @@ fn partial_cmp(&self, other: &str) -> Option<Ordering> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ops::Index<I> for str
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<I> const ops::Index<I> for str
 where
-    I: SliceIndex<str>,
+    I: ~const SliceIndex<str>,
 {
     type Output = I::Output;
 
@@ -66,9 +67,10 @@ fn index(&self, index: I) -> &I::Output {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ops::IndexMut<I> for str
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+impl<I> const ops::IndexMut<I> for str
 where
-    I: SliceIndex<str>,
+    I: ~const SliceIndex<str>,
 {
     #[inline]
     fn index_mut(&mut self, index: I) -> &mut I::Output {
@@ -79,7 +81,7 @@ fn index_mut(&mut self, index: I) -> &mut I::Output {
 #[inline(never)]
 #[cold]
 #[track_caller]
-fn str_index_overflow_fail() -> ! {
+const fn str_index_overflow_fail() -> ! {
     panic!("attempted to index str up to maximum usize");
 }
 
@@ -96,7 +98,8 @@ fn str_index_overflow_fail() -> ! {
 ///
 /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
 #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::RangeFull {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeFull {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -160,7 +163,8 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
 /// // &s[3 .. 100];
 /// ```
 #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::Range<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::Range<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -247,7 +251,8 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
 /// Panics if `end` does not point to the starting byte offset of a
 /// character (as defined by `is_char_boundary`), or if `end > len`.
 #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeTo<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -317,7 +322,8 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
 /// Panics if `begin` does not point to the starting byte offset of
 /// a character (as defined by `is_char_boundary`), or if `begin > len`.
 #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeFrom<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -393,7 +399,8 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
 /// to the ending byte offset of a character (`end + 1` is either a starting
 /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`.
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeInclusive<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -444,7 +451,8 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
 /// (`end + 1` is either a starting byte offset as defined by
 /// `is_char_boundary`, or equal to `len`), or if `end >= len`.
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl SliceIndex<str> for ops::RangeToInclusive<usize> {
+#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
+unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
index 2b8bbe1924450a41a8f20d01e3018631f6da3aae..62103f5b075aea42aa022d35e5e4e33906976e22 100644 (file)
@@ -94,7 +94,7 @@
 //!     }
 //!
 //!     if let Err(panic) = thread.join() {
-//!         println!("Thread had an error: {:?}", panic);
+//!         println!("Thread had an error: {panic:?}");
 //!     }
 //! }
 //! ```
@@ -352,7 +352,7 @@ pub fn from_mut(v: &mut bool) -> &mut Self {
     /// let a = &*AtomicBool::from_mut_slice(&mut some_bools);
     /// std::thread::scope(|s| {
     ///     for i in 0..a.len() {
-    ///         s.spawn(move |_| a[i].store(true, Ordering::Relaxed));
+    ///         s.spawn(move || a[i].store(true, Ordering::Relaxed));
     ///     }
     /// });
     /// assert_eq!(some_bools, [true; 10]);
@@ -984,7 +984,7 @@ pub fn from_mut(v: &mut *mut T) -> &mut Self {
     /// let a = &*AtomicPtr::from_mut_slice(&mut some_ptrs);
     /// std::thread::scope(|s| {
     ///     for i in 0..a.len() {
-    ///         s.spawn(move |_| {
+    ///         s.spawn(move || {
     ///             let name = Box::new(format!("thread{i}"));
     ///             a[i].store(Box::into_raw(name), Ordering::Relaxed);
     ///         });
@@ -1345,7 +1345,7 @@ impl const From<bool> for AtomicBool {
     /// ```
     /// use std::sync::atomic::AtomicBool;
     /// let atomic_bool = AtomicBool::from(true);
-    /// assert_eq!(format!("{:?}", atomic_bool), "true")
+    /// assert_eq!(format!("{atomic_bool:?}"), "true")
     /// ```
     #[inline]
     fn from(b: bool) -> Self {
@@ -1533,7 +1533,7 @@ pub fn from_mut(v: &mut $int_type) -> &mut Self {
             #[doc = concat!("let a = &*", stringify!($atomic_type), "::from_mut_slice(&mut some_ints);")]
             /// std::thread::scope(|s| {
             ///     for i in 0..a.len() {
-            ///         s.spawn(move |_| a[i].store(i as _, Ordering::Relaxed));
+            ///         s.spawn(move || a[i].store(i as _, Ordering::Relaxed));
             ///     }
             /// });
             /// for (i, n) in some_ints.into_iter().enumerate() {
index 243c044b5d9d0a55ee918885637f9177d49226e7..bd72d82b71c00a15d8ce79dc1aa8d0f03df374f3 100644 (file)
@@ -1214,7 +1214,7 @@ fn fmt_decimal(
 /// use std::time::Duration;
 ///
 /// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
-///     println!("Failed conversion to Duration: {}", e);
+///     println!("Failed conversion to Duration: {e}");
 /// }
 /// ```
 #[derive(Debug, Clone, PartialEq, Eq)]
index f41f4a5e94a76ee5b585b9575636cfa4b7e66aab..6656dd5c40bebdcf18aa0e49942e550049517fab 100644 (file)
@@ -9,7 +9,7 @@
 /// use std::io::*;
 /// let data = vec![1, 2, 3, 4, 5];
 /// let res: Result<()> = data.iter()
-///     .map(|x| writeln!(stdout(), "{}", x))
+///     .map(|x| writeln!(stdout(), "{x}"))
 ///     .collect();
 /// assert!(res.is_ok());
 /// ```
index b36d6f0d4040598b0ea86718d0489681d8c19781..eccddcbbf59fe02c62b3ad871fd241e48395df34 100644 (file)
@@ -46,12 +46,12 @@ fn any_downcast_ref() {
 
     match a.downcast_ref::<usize>() {
         Some(&5) => {}
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 
     match a.downcast_ref::<Test>() {
         None => {}
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 }
 
@@ -69,7 +69,7 @@ fn any_downcast_mut() {
             assert_eq!(*x, 5);
             *x = 612;
         }
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 
     match b_r.downcast_mut::<usize>() {
@@ -77,27 +77,27 @@ fn any_downcast_mut() {
             assert_eq!(*x, 7);
             *x = 413;
         }
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 
     match a_r.downcast_mut::<Test>() {
         None => (),
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 
     match b_r.downcast_mut::<Test>() {
         None => (),
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 
     match a_r.downcast_mut::<usize>() {
         Some(&mut 612) => {}
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 
     match b_r.downcast_mut::<usize>() {
         Some(&mut 413) => {}
-        x => panic!("Unexpected value {:?}", x),
+        x => panic!("Unexpected value {x:?}"),
     }
 }
 
index 4707cc7076ec0fa8038fb84659f1e76474ec1742..f15e03076caf7f0df9732ed09d20613803a65afd 100644 (file)
@@ -62,10 +62,10 @@ fn cell_update() {
 #[test]
 fn cell_has_sensible_show() {
     let x = Cell::new("foo bar");
-    assert!(format!("{:?}", x).contains(x.get()));
+    assert!(format!("{x:?}").contains(x.get()));
 
     x.set("baz qux");
-    assert!(format!("{:?}", x).contains(x.get()));
+    assert!(format!("{x:?}").contains(x.get()));
 }
 
 #[test]
@@ -73,11 +73,11 @@ fn ref_and_refmut_have_sensible_show() {
     let refcell = RefCell::new("foo");
 
     let refcell_refmut = refcell.borrow_mut();
-    assert!(format!("{:?}", refcell_refmut).contains("foo"));
+    assert!(format!("{refcell_refmut:?}").contains("foo"));
     drop(refcell_refmut);
 
     let refcell_ref = refcell.borrow();
-    assert!(format!("{:?}", refcell_ref).contains("foo"));
+    assert!(format!("{refcell_ref:?}").contains("foo"));
     drop(refcell_ref);
 }
 
index 9567479c8137b5d4f0a7e8e0f07d7ee8edc0da12..487ce46be28d7a3f5ac2e3559ad77751c5753f4d 100644 (file)
@@ -11,8 +11,8 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("Foo", format!("{:?}", Foo));
-        assert_eq!("Foo", format!("{:#?}", Foo));
+        assert_eq!("Foo", format!("{Foo:?}"));
+        assert_eq!("Foo", format!("{Foo:#?}"));
     }
 
     #[test]
@@ -25,12 +25,12 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("Foo { bar: true }", format!("{:?}", Foo));
+        assert_eq!("Foo { bar: true }", format!("{Foo:?}"));
         assert_eq!(
             "Foo {
     bar: true,
 }",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -47,13 +47,13 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("Foo { bar: true, baz: 10/20 }", format!("{:?}", Foo));
+        assert_eq!("Foo { bar: true, baz: 10/20 }", format!("{Foo:?}"));
         assert_eq!(
             "Foo {
     bar: true,
     baz: 10/20,
 }",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -80,7 +80,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 
         assert_eq!(
             "Bar { foo: Foo { bar: true, baz: 10/20 }, hello: \"world\" }",
-            format!("{:?}", Bar)
+            format!("{Bar:?}")
         );
         assert_eq!(
             "Bar {
@@ -90,7 +90,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     },
     hello: \"world\",
 }",
-            format!("{:#?}", Bar)
+            format!("{Bar:#?}")
         );
     }
 
@@ -104,8 +104,8 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("Foo { .. }", format!("{:?}", Foo));
-        assert_eq!("Foo { .. }", format!("{:#?}", Foo));
+        assert_eq!("Foo { .. }", format!("{Foo:?}"));
+        assert_eq!("Foo { .. }", format!("{Foo:#?}"));
     }
 
     #[test]
@@ -121,14 +121,14 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{:?}", Foo));
+        assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{Foo:?}"));
         assert_eq!(
             "Foo {
     bar: true,
     baz: 10/20,
     ..
 }",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -158,7 +158,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 
         assert_eq!(
             "Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: \"world\", .. }",
-            format!("{:?}", Bar)
+            format!("{Bar:?}")
         );
         assert_eq!(
             "Bar {
@@ -170,7 +170,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     hello: \"world\",
     ..
 }",
-            format!("{:#?}", Bar)
+            format!("{Bar:#?}")
         );
     }
 }
@@ -188,8 +188,8 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("Foo", format!("{:?}", Foo));
-        assert_eq!("Foo", format!("{:#?}", Foo));
+        assert_eq!("Foo", format!("{Foo:?}"));
+        assert_eq!("Foo", format!("{Foo:#?}"));
     }
 
     #[test]
@@ -202,12 +202,12 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("Foo(true)", format!("{:?}", Foo));
+        assert_eq!("Foo(true)", format!("{Foo:?}"));
         assert_eq!(
             "Foo(
     true,
 )",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -221,13 +221,13 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("Foo(true, 10/20)", format!("{:?}", Foo));
+        assert_eq!("Foo(true, 10/20)", format!("{Foo:?}"));
         assert_eq!(
             "Foo(
     true,
     10/20,
 )",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -249,7 +249,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("Bar(Foo(true, 10/20), \"world\")", format!("{:?}", Bar));
+        assert_eq!("Bar(Foo(true, 10/20), \"world\")", format!("{Bar:?}"));
         assert_eq!(
             "Bar(
     Foo(
@@ -258,7 +258,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     ),
     \"world\",
 )",
-            format!("{:#?}", Bar)
+            format!("{Bar:#?}")
         );
     }
 }
@@ -276,8 +276,8 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("{}", format!("{:?}", Foo));
-        assert_eq!("{}", format!("{:#?}", Foo));
+        assert_eq!("{}", format!("{Foo:?}"));
+        assert_eq!("{}", format!("{Foo:#?}"));
     }
 
     #[test]
@@ -298,15 +298,15 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!(format!("{:?}", Entry), format!("{:?}", KeyValue));
-        assert_eq!(format!("{:#?}", Entry), format!("{:#?}", KeyValue));
+        assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}"));
+        assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}"));
 
-        assert_eq!("{\"bar\": true}", format!("{:?}", Entry));
+        assert_eq!("{\"bar\": true}", format!("{Entry:?}"));
         assert_eq!(
             "{
     \"bar\": true,
 }",
-            format!("{:#?}", Entry)
+            format!("{Entry:#?}")
         );
     }
 
@@ -336,16 +336,16 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!(format!("{:?}", Entry), format!("{:?}", KeyValue));
-        assert_eq!(format!("{:#?}", Entry), format!("{:#?}", KeyValue));
+        assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}"));
+        assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}"));
 
-        assert_eq!("{\"bar\": true, 10: 10/20}", format!("{:?}", Entry));
+        assert_eq!("{\"bar\": true, 10: 10/20}", format!("{Entry:?}"));
         assert_eq!(
             "{
     \"bar\": true,
     10: 10/20,
 }",
-            format!("{:#?}", Entry)
+            format!("{Entry:#?}")
         );
     }
 
@@ -373,7 +373,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         assert_eq!(
             "{\"foo\": {\"bar\": true, 10: 10/20}, \
                     {\"bar\": true, 10: 10/20}: \"world\"}",
-            format!("{:?}", Bar)
+            format!("{Bar:?}")
         );
         assert_eq!(
             "{
@@ -386,7 +386,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         10: 10/20,
     }: \"world\",
 }",
-            format!("{:#?}", Bar)
+            format!("{Bar:#?}")
         );
     }
 
@@ -441,7 +441,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        format!("{:?}", Foo);
+        format!("{Foo:?}");
     }
 
     #[test]
@@ -455,7 +455,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        format!("{:?}", Foo);
+        format!("{Foo:?}");
     }
 
     #[test]
@@ -469,7 +469,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        format!("{:?}", Foo);
+        format!("{Foo:?}");
     }
 }
 
@@ -486,8 +486,8 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("{}", format!("{:?}", Foo));
-        assert_eq!("{}", format!("{:#?}", Foo));
+        assert_eq!("{}", format!("{Foo:?}"));
+        assert_eq!("{}", format!("{Foo:#?}"));
     }
 
     #[test]
@@ -500,12 +500,12 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("{true}", format!("{:?}", Foo));
+        assert_eq!("{true}", format!("{Foo:?}"));
         assert_eq!(
             "{
     true,
 }",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -519,13 +519,13 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("{true, 10/20}", format!("{:?}", Foo));
+        assert_eq!("{true, 10/20}", format!("{Foo:?}"));
         assert_eq!(
             "{
     true,
     10/20,
 }",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -547,7 +547,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("{{true, 10/20}, \"world\"}", format!("{:?}", Bar));
+        assert_eq!("{{true, 10/20}, \"world\"}", format!("{Bar:?}"));
         assert_eq!(
             "{
     {
@@ -556,7 +556,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     },
     \"world\",
 }",
-            format!("{:#?}", Bar)
+            format!("{Bar:#?}")
         );
     }
 }
@@ -574,8 +574,8 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("[]", format!("{:?}", Foo));
-        assert_eq!("[]", format!("{:#?}", Foo));
+        assert_eq!("[]", format!("{Foo:?}"));
+        assert_eq!("[]", format!("{Foo:#?}"));
     }
 
     #[test]
@@ -588,12 +588,12 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("[true]", format!("{:?}", Foo));
+        assert_eq!("[true]", format!("{Foo:?}"));
         assert_eq!(
             "[
     true,
 ]",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -607,13 +607,13 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("[true, 10/20]", format!("{:?}", Foo));
+        assert_eq!("[true, 10/20]", format!("{Foo:?}"));
         assert_eq!(
             "[
     true,
     10/20,
 ]",
-            format!("{:#?}", Foo)
+            format!("{Foo:#?}")
         );
     }
 
@@ -635,7 +635,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             }
         }
 
-        assert_eq!("[[true, 10/20], \"world\"]", format!("{:?}", Bar));
+        assert_eq!("[[true, 10/20], \"world\"]", format!("{Bar:?}"));
         assert_eq!(
             "[
     [
@@ -644,7 +644,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     ],
     \"world\",
 ]",
-            format!("{:#?}", Bar)
+            format!("{Bar:#?}")
         );
     }
 }
@@ -668,13 +668,13 @@ struct Foo {
     set.insert(1024);
     set.insert(7);
 
-    assert_eq!(format!("{:03?}", struct_), "Foo { bar: 1024, baz: 007 }");
-    assert_eq!(format!("{:03?}", tuple), "(1024, 007)");
-    assert_eq!(format!("{:03?}", list), "[1024, 007]");
-    assert_eq!(format!("{:03?}", map), r#"{"bar": 1024, "baz": 007}"#);
-    assert_eq!(format!("{:03?}", set), "{007, 1024}");
+    assert_eq!(format!("{struct_:03?}"), "Foo { bar: 1024, baz: 007 }");
+    assert_eq!(format!("{tuple:03?}"), "(1024, 007)");
+    assert_eq!(format!("{list:03?}"), "[1024, 007]");
+    assert_eq!(format!("{map:03?}"), r#"{"bar": 1024, "baz": 007}"#);
+    assert_eq!(format!("{set:03?}"), "{007, 1024}");
     assert_eq!(
-        format!("{:#03?}", struct_),
+        format!("{struct_:#03?}"),
         "
 Foo {
     bar: 1024,
@@ -684,7 +684,7 @@ struct Foo {
         .trim()
     );
     assert_eq!(
-        format!("{:#03?}", tuple),
+        format!("{tuple:#03?}"),
         "
 (
     1024,
@@ -694,7 +694,7 @@ struct Foo {
         .trim()
     );
     assert_eq!(
-        format!("{:#03?}", list),
+        format!("{list:#03?}"),
         "
 [
     1024,
@@ -704,7 +704,7 @@ struct Foo {
         .trim()
     );
     assert_eq!(
-        format!("{:#03?}", map),
+        format!("{map:#03?}"),
         r#"
 {
     "bar": 1024,
@@ -714,7 +714,7 @@ struct Foo {
         .trim()
     );
     assert_eq!(
-        format!("{:#03?}", set),
+        format!("{set:#03?}"),
         "
 {
     007,
index 7b281ce48e6aa4e102ea048daabaa53708b66080..61807635813c404b09a6a3873f3f9b4075c5d00b 100644 (file)
@@ -6,7 +6,7 @@
 fn test_format_flags() {
     // No residual flags left by pointer formatting
     let p = "".as_ptr();
-    assert_eq!(format!("{:p} {:x}", p, 16), format!("{:p} 10", p));
+    assert_eq!(format!("{:p} {:x}", p, 16), format!("{p:p} 10"));
 
     assert_eq!(format!("{: >3}", 'a'), "  a");
 }
@@ -15,8 +15,8 @@ fn test_format_flags() {
 fn test_pointer_formats_data_pointer() {
     let b: &[u8] = b"";
     let s: &str = "";
-    assert_eq!(format!("{:p}", s), format!("{:p}", s.as_ptr()));
-    assert_eq!(format!("{:p}", b), format!("{:p}", b.as_ptr()));
+    assert_eq!(format!("{s:p}"), format!("{:p}", s.as_ptr()));
+    assert_eq!(format!("{b:p}"), format!("{:p}", b.as_ptr()));
 }
 
 #[test]
@@ -41,5 +41,5 @@ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         }
     }
 
-    assert_eq!(format!("{:<03}", Bar), "1  0051  ");
+    assert_eq!(format!("{Bar:<03}"), "1  0051  ");
 }
index b958422d14f84b6e7c39543e7857e56e34a300ee..b9ede65c9ff0925a7147030e8fcf98255f50598c 100644 (file)
@@ -126,7 +126,7 @@ fn test_format_int_exp_limits() {
 fn test_format_int_exp_precision() {
     //test that float and integer match
     let big_int: u32 = 314_159_265;
-    assert_eq!(format!("{:.1e}", big_int), format!("{:.1e}", f64::from(big_int)));
+    assert_eq!(format!("{big_int:.1e}"), format!("{:.1e}", f64::from(big_int)));
 
     //test adding precision
     assert_eq!(format!("{:.10e}", i8::MIN), "-1.2800000000e2");
index cf69f0a7a4d7e7e687bf781a33f4b050554a3c87..32bd68e3d2554a2c717d428c8635cff70ac1eaf8 100644 (file)
@@ -543,6 +543,14 @@ fn test_try_collect() {
     assert_eq!(v, Continue(vec![4, 5]));
 }
 
+#[test]
+fn test_collect_into() {
+    let a = vec![1, 2, 3, 4, 5];
+    let mut b = Vec::new();
+    a.iter().cloned().collect_into(&mut b);
+    assert!(a == b);
+}
+
 // just tests by whether or not this compiles
 fn _empty_impl_all_auto_traits<T>() {
     use std::panic::{RefUnwindSafe, UnwindSafe};
index 064024ab87b281243bec34b3351f1df415b208af..416d2b2dae41f81f80602d6975cacaa59bdc949a 100644 (file)
@@ -113,7 +113,7 @@ fn aliasing_in_get() {
     x.set(42).unwrap();
     let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option<T>` --+
     let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option<T>`   |
-    println!("{}", at_x); // <------- up until here ---------------------------+
+    println!("{at_x}"); // <------- up until here ---------------------------+
 }
 
 #[test]
index 2437f4afdeb5e860acf1ebce188c140d0a9058dc..dc3740228274bcbfc7525e86e13cad8b65f75c91 100644 (file)
@@ -62,6 +62,7 @@
 #![feature(slice_partition_dedup)]
 #![feature(int_log)]
 #![feature(iter_advance_by)]
+#![feature(iter_collect_into)]
 #![feature(iter_partition_in_place)]
 #![feature(iter_intersperse)]
 #![feature(iter_is_partitioned)]
index 4990d4a083df62e5faa3b01979f74b4ee8654915..c4e105cba600d008c76b3f8042ec91a0ee566c0f 100644 (file)
@@ -15,7 +15,7 @@ macro_rules! test_literal {
         for input in inputs {
             assert_eq!(input.parse(), Ok(x64));
             assert_eq!(input.parse(), Ok(x32));
-            let neg_input = &format!("-{}", input);
+            let neg_input = &format!("-{input}");
             assert_eq!(neg_input.parse(), Ok(-x64));
             assert_eq!(neg_input.parse(), Ok(-x32));
         }
@@ -123,9 +123,9 @@ fn inf() {
 #[test]
 fn massive_exponent() {
     let max = i64::MAX;
-    assert_eq!(format!("1e{}000", max).parse(), Ok(f64::INFINITY));
-    assert_eq!(format!("1e-{}000", max).parse(), Ok(0.0));
-    assert_eq!(format!("1e{}000", max).parse(), Ok(f64::INFINITY));
+    assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY));
+    assert_eq!(format!("1e-{max}000").parse(), Ok(0.0));
+    assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY));
 }
 
 #[test]
index 473feacc91fa95eb48fb8b32ee468ab7c87cedfb..edc77377d58206224c89c9b6b7113237b4d6e221 100644 (file)
@@ -46,7 +46,7 @@ fn valid() {
     assert_eq!(parse_positive(b".1e300"), Some(new_number(299, 1)));
     assert_eq!(parse_positive(b"101e-33"), Some(new_number(-33, 101)));
     let zeros = "0".repeat(25);
-    let s = format!("1.5e{}", zeros);
+    let s = format!("1.5e{zeros}");
     assert_eq!(parse_positive(s.as_bytes()), Some(new_number(-1, 15)));
 }
 
index 4874e8ec09f8cfa4910f334158b431baa735f1c4..798473bbde377bd7aa48a90c69ec037c73395a24 100644 (file)
@@ -20,7 +20,7 @@ mod strategy {
 pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
     match decode(v).1 {
         FullDecoded::Finite(decoded) => decoded,
-        full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
+        full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
     }
 }
 
index 57b3dcf8e1e04fed5504e48029be9d5abb97f033..d0950039314ac571befd78339ffe40b18ebf10cd 100644 (file)
@@ -15,7 +15,7 @@
 pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
     match decode(v).1 {
         FullDecoded::Finite(decoded) => decoded,
-        full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
+        full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
     }
 }
 
index 9c65871ac4b4cfc9fa4190b76fbf9e01e8cf9b00..af8e78f1f4e169edd1d8cdf5f0fc518d2ba6348f 100644 (file)
@@ -550,7 +550,7 @@ fn dyn_metadata() {
     assert_eq!(meta.align_of(), std::mem::align_of::<Something>());
     assert_eq!(meta.layout(), std::alloc::Layout::new::<Something>());
 
-    assert!(format!("{:?}", meta).starts_with("DynMetadata(0x"));
+    assert!(format!("{meta:?}").starts_with("DynMetadata(0x"));
 }
 
 #[test]
index 1652c1b83de3383fc36a7b01d06b5d3ddda625d8..98b870512b046a0fe6675f923343476e58af2fbc 100644 (file)
@@ -80,9 +80,9 @@ fn test_fmt_default() {
     let ok: Result<isize, &'static str> = Ok(100);
     let err: Result<isize, &'static str> = Err("Err");
 
-    let s = format!("{:?}", ok);
+    let s = format!("{ok:?}");
     assert_eq!(s, "Ok(100)");
-    let s = format!("{:?}", err);
+    let s = format!("{err:?}");
     assert_eq!(s, "Err(\"Err\")");
 }
 
index 7b1e6840f6424f2f0f232f909c0eaf57e56c2223..b16b952f71e862982162a8a8286854475ee49aab 100644 (file)
@@ -187,7 +187,7 @@ fn test() {
 fn main() {
     {
         let (energy_before, energy_after) = nbody::run(1000);
-        println!("Energy before: {}", energy_before);
-        println!("Energy after:  {}", energy_after);
+        println!("Energy before: {energy_before}");
+        println!("Energy after:  {energy_after}");
     }
 }
index c5afca6d56a2d29a33255a1330dc74b579541284..5338cd077572ce58983e988439e13d189631e468 100644 (file)
@@ -20,8 +20,8 @@
 #![feature(rustc_allow_const_fn_unstable)]
 #![feature(nll)]
 #![feature(staged_api)]
-#![feature(const_fn_trait_bound)]
-#![feature(const_fn_fn_ptr_basics)]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
+#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
 #![feature(allow_internal_unstable)]
 #![feature(decl_macro)]
 #![feature(extern_types)]
@@ -1106,7 +1106,7 @@ impl Literal {
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     pub fn f32_unsuffixed(n: f32) -> Literal {
         if !n.is_finite() {
-            panic!("Invalid float literal {}", n);
+            panic!("Invalid float literal {n}");
         }
         let mut repr = n.to_string();
         if !repr.contains('.') {
@@ -1131,7 +1131,7 @@ pub fn f32_unsuffixed(n: f32) -> Literal {
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     pub fn f32_suffixed(n: f32) -> Literal {
         if !n.is_finite() {
-            panic!("Invalid float literal {}", n);
+            panic!("Invalid float literal {n}");
         }
         Literal(bridge::client::Literal::f32(&n.to_string()))
     }
@@ -1151,7 +1151,7 @@ pub fn f32_suffixed(n: f32) -> Literal {
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     pub fn f64_unsuffixed(n: f64) -> Literal {
         if !n.is_finite() {
-            panic!("Invalid float literal {}", n);
+            panic!("Invalid float literal {n}");
         }
         let mut repr = n.to_string();
         if !repr.contains('.') {
@@ -1176,7 +1176,7 @@ pub fn f64_unsuffixed(n: f64) -> Literal {
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
     pub fn f64_suffixed(n: f64) -> Literal {
         if !n.is_finite() {
-            panic!("Invalid float literal {}", n);
+            panic!("Invalid float literal {n}");
         }
         Literal(bridge::client::Literal::f64(&n.to_string()))
     }
index 8ee55234cea430e788fb8b03dbe5b6ab477a587e..a880439624690e423e495f3f380e255c128a4075 100644 (file)
@@ -83,7 +83,7 @@
 ///
 /// fn main() {
 ///     let a = Box::new(4); // Allocates from the system allocator.
-///     println!("{}", a);
+///     println!("{a}");
 /// }
 /// ```
 ///
index f5da93f93fd932b0e7ed6134e1893c18b6d02d2a..4dfbf88e83ebc50a835fee30e127cd86e9e75abf 100644 (file)
@@ -57,10 +57,10 @@ fn test_debug() {
     \n    { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\
     \n]";
 
-    assert_eq!(format!("{:#?}", backtrace), expected);
+    assert_eq!(format!("{backtrace:#?}"), expected);
 
     // Format the backtrace a second time, just to make sure lazily resolved state is stable
-    assert_eq!(format!("{:#?}", backtrace), expected);
+    assert_eq!(format!("{backtrace:#?}"), expected);
 }
 
 #[test]
@@ -91,5 +91,5 @@ fn test_frames() {
 
     let mut iter = frames.iter().zip(expected.iter());
 
-    assert!(iter.all(|(f, e)| format!("{:#?}", f) == *e));
+    assert!(iter.all(|(f, e)| format!("{f:#?}") == *e));
 }
index c0524352193f947b45367a3470d5aa1557afe91f..6b63191eb583d7602ec0455a4c5fb46e5813830c 100644 (file)
 /// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"];
 /// for &book in &to_find {
 ///     match book_reviews.get(book) {
-///         Some(review) => println!("{}: {}", book, review),
-///         None => println!("{} is unreviewed.", book)
+///         Some(review) => println!("{book}: {review}"),
+///         None => println!("{book} is unreviewed.")
 ///     }
 /// }
 ///
 ///
 /// // Iterate over everything.
 /// for (book, review) in &book_reviews {
-///     println!("{}: \"{}\"", book, review);
+///     println!("{book}: \"{review}\"");
 /// }
 /// ```
 ///
 ///
 /// // Use derived implementation to print the status of the vikings.
 /// for (viking, health) in &vikings {
-///     println!("{:?} has {} hp", viking, health);
+///     println!("{viking:?} has {health} hp");
 /// }
 /// ```
 
@@ -341,7 +341,7 @@ pub fn capacity(&self) -> usize {
     /// ]);
     ///
     /// for key in map.keys() {
-    ///     println!("{}", key);
+    ///     println!("{key}");
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -392,7 +392,7 @@ pub fn into_keys(self) -> IntoKeys<K, V> {
     /// ]);
     ///
     /// for val in map.values() {
-    ///     println!("{}", val);
+    ///     println!("{val}");
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -419,7 +419,7 @@ pub fn values(&self) -> Values<'_, K, V> {
     /// }
     ///
     /// for val in map.values() {
-    ///     println!("{}", val);
+    ///     println!("{val}");
     /// }
     /// ```
     #[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -470,7 +470,7 @@ pub fn into_values(self) -> IntoValues<K, V> {
     /// ]);
     ///
     /// for (key, val) in map.iter() {
-    ///     println!("key: {} val: {}", key, val);
+    ///     println!("key: {key} val: {val}");
     /// }
     /// ```
     #[rustc_lint_query_instability]
@@ -500,7 +500,7 @@ pub fn iter(&self) -> Iter<'_, K, V> {
     /// }
     ///
     /// for (key, val) in &map {
-    ///     println!("key: {} val: {}", key, val);
+    ///     println!("key: {key} val: {val}");
     /// }
     /// ```
     #[rustc_lint_query_instability]
@@ -621,7 +621,7 @@ pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
+    /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`.
     /// The elements are visited in unsorted (and unspecified) order.
     ///
     /// # Examples
index 30da22b80849c9c2553d88f77fbb627f89540a7e..7ebc41588b3df2e9a250a5290bb92234ac493ab1 100644 (file)
@@ -515,10 +515,10 @@ fn test_show() {
     map.insert(1, 2);
     map.insert(3, 4);
 
-    let map_str = format!("{:?}", map);
+    let map_str = format!("{map:?}");
 
     assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}");
-    assert_eq!(format!("{:?}", empty), "{}");
+    assert_eq!(format!("{empty:?}"), "{}");
 }
 
 #[test]
@@ -702,7 +702,7 @@ fn test_entry_take_doesnt_corrupt() {
     // Test for #19292
     fn check(m: &HashMap<i32, ()>) {
         for k in m.keys() {
-            assert!(m.contains_key(k), "{} is in keys() but not in the map?", k);
+            assert!(m.contains_key(k), "{k} is in keys() but not in the map?");
         }
     }
 
index 2eb4cacabb83100c3bf4d00ecc4d356b995042ee..fa471a3c3f323df88416f1f411a6bfe3ea844406 100644 (file)
@@ -66,7 +66,7 @@
 ///
 /// // Iterate over everything.
 /// for book in &books {
-///     println!("{}", book);
+///     println!("{book}");
 /// }
 /// ```
 ///
@@ -91,7 +91,7 @@
 ///
 /// // Use derived implementation to print the vikings.
 /// for x in &vikings {
-///     println!("{:?}", x);
+///     println!("{x:?}");
 /// }
 /// ```
 ///
@@ -181,7 +181,7 @@ pub fn capacity(&self) -> usize {
     ///
     /// // Will print in an arbitrary order.
     /// for x in set.iter() {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     #[inline]
@@ -244,7 +244,7 @@ pub fn is_empty(&self) -> bool {
     ///
     /// // print 1, 2, 3 in an arbitrary order
     /// for i in set.drain() {
-    ///     println!("{}", i);
+    ///     println!("{i}");
     /// }
     ///
     /// assert!(set.is_empty());
@@ -300,7 +300,7 @@ pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
 
     /// Retains only the elements specified by the predicate.
     ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+    /// In other words, remove all elements `e` for which `f(&e)` returns `false`.
     /// The elements are visited in unsorted (and unspecified) order.
     ///
     /// # Examples
@@ -525,7 +525,7 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
     ///
     /// // Can be seen as `a - b`.
     /// for x in a.difference(&b) {
-    ///     println!("{}", x); // Print 1
+    ///     println!("{x}"); // Print 1
     /// }
     ///
     /// let diff: HashSet<_> = a.difference(&b).collect();
@@ -555,7 +555,7 @@ pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S
     ///
     /// // Print 1, 4 in arbitrary order.
     /// for x in a.symmetric_difference(&b) {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     ///
     /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect();
@@ -586,7 +586,7 @@ pub fn symmetric_difference<'a>(
     ///
     /// // Print 2, 3 in arbitrary order.
     /// for x in a.intersection(&b) {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     ///
     /// let intersection: HashSet<_> = a.intersection(&b).collect();
@@ -615,7 +615,7 @@ pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a,
     ///
     /// // Print 1, 2, 3, 4 in arbitrary order.
     /// for x in a.union(&b) {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     ///
     /// let union: HashSet<_> = a.union(&b).collect();
@@ -1451,7 +1451,7 @@ impl<T, S> IntoIterator for HashSet<T, S> {
     ///
     /// // Will print in an arbitrary order.
     /// for x in &v {
-    ///     println!("{}", x);
+    ///     println!("{x}");
     /// }
     /// ```
     #[inline]
index 6a625e6243c2157f4416502f28b3240b56480e3b..233db276b9e618e61ce0a76ba357e863532eac82 100644 (file)
@@ -301,10 +301,10 @@ fn test_show() {
     set.insert(1);
     set.insert(2);
 
-    let set_str = format!("{:?}", set);
+    let set_str = format!("{set:?}");
 
     assert!(set_str == "{1, 2}" || set_str == "{2, 1}");
-    assert_eq!(format!("{:?}", empty), "{}");
+    assert_eq!(format!("{empty:?}"), "{}");
 }
 
 #[test]
index b5e81deb4808007b4082c80e241789cf19da2102..0caec8fe05aa7ea6b67b46cb6d12f696c8831ab6 100644 (file)
 //! ```
 //! let vec = vec![1, 2, 3, 4];
 //! for x in vec.iter() {
-//!    println!("vec contained {}", x);
+//!    println!("vec contained {x:?}");
 //! }
 //! ```
 //!
 //! ```
 //! let vec = vec![1, 2, 3, 4];
 //! for x in vec.iter().rev() {
-//!    println!("vec contained {}", x);
+//!    println!("vec contained {x:?}");
 //! }
 //! ```
 //!
 //!
 //! println!("Number of occurrences of each character");
 //! for (char, count) in &count {
-//!     println!("{}: {}", char, count);
+//!     println!("{char}: {count}");
 //! }
 //! ```
 //!
 //!     // Check if they're sober enough to have another beer.
 //!     if person.blood_alcohol > 0.3 {
 //!         // Too drunk... for now.
-//!         println!("Sorry {}, I have to cut you off", id);
+//!         println!("Sorry {id}, I have to cut you off");
 //!     } else {
 //!         // Have another!
 //!         person.blood_alcohol += 0.1;
index 5ed9fa9d6f0fd1a956c3a0ce84e16066d33befa8..05f08c498e68387736edb0a8897f24d6f34bceed 100644 (file)
@@ -118,7 +118,7 @@ pub struct VarsOs {
 /// // We will iterate through the references to the element returned by
 /// // env::vars();
 /// for (key, value) in env::vars() {
-///     println!("{}: {}", key, value);
+///     println!("{key}: {value}");
 /// }
 /// ```
 ///
@@ -148,7 +148,7 @@ pub fn vars() -> Vars {
 /// // We will iterate through the references to the element returned by
 /// // env::vars_os();
 /// for (key, value) in env::vars_os() {
-///     println!("{:?}: {:?}", key, value);
+///     println!("{key:?}: {value:?}");
 /// }
 /// ```
 #[must_use]
@@ -212,8 +212,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 ///
 /// let key = "HOME";
 /// match env::var(key) {
-///     Ok(val) => println!("{}: {:?}", key, val),
-///     Err(e) => println!("couldn't interpret {}: {}", key, e),
+///     Ok(val) => println!("{key}: {val:?}"),
+///     Err(e) => println!("couldn't interpret {key}: {e}"),
 /// }
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
@@ -252,8 +252,8 @@ fn _var(key: &OsStr) -> Result<String, VarError> {
 ///
 /// let key = "HOME";
 /// match env::var_os(key) {
-///     Some(val) => println!("{}: {:?}", key, val),
-///     None => println!("{} is not defined in the environment.", key)
+///     Some(val) => println!("{key}: {val:?}"),
+///     None => println!("{key} is not defined in the environment.")
 /// }
 /// ```
 #[must_use]
@@ -343,7 +343,7 @@ pub fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) {
 
 fn _set_var(key: &OsStr, value: &OsStr) {
     os_imp::setenv(key, value).unwrap_or_else(|e| {
-        panic!("failed to set environment variable `{:?}` to `{:?}`: {}", key, value, e)
+        panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}")
     })
 }
 
@@ -385,7 +385,7 @@ pub fn remove_var<K: AsRef<OsStr>>(key: K) {
 
 fn _remove_var(key: &OsStr) {
     os_imp::unsetenv(key)
-        .unwrap_or_else(|e| panic!("failed to remove environment variable `{:?}`: {}", key, e))
+        .unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}"))
 }
 
 /// An iterator that splits an environment variable into paths according to
@@ -421,7 +421,7 @@ pub struct SplitPaths<'a> {
 ///             println!("'{}'", path.display());
 ///         }
 ///     }
-///     None => println!("{} is not defined in the environment.", key)
+///     None => println!("{key} is not defined in the environment.")
 /// }
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
@@ -684,7 +684,7 @@ pub fn temp_dir() -> PathBuf {
 /// match env::current_exe() {
 ///     Ok(exe_path) => println!("Path of this executable is: {}",
 ///                              exe_path.display()),
-///     Err(e) => println!("failed to get current exe path: {}", e),
+///     Err(e) => println!("failed to get current exe path: {e}"),
 /// };
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
@@ -755,7 +755,7 @@ pub struct ArgsOs {
 ///
 /// // Prints each argument on a separate line
 /// for argument in env::args() {
-///     println!("{}", argument);
+///     println!("{argument}");
 /// }
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
@@ -790,7 +790,7 @@ pub fn args() -> Args {
 ///
 /// // Prints each argument on a separate line
 /// for argument in env::args_os() {
-///     println!("{:?}", argument);
+///     println!("{argument:?}");
 /// }
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
index 1a96b9c928289b3e5be32ed09efe242632290992..c3cb71a5dee636c1d231a8707351bef4f6887070 100644 (file)
@@ -96,7 +96,7 @@ pub trait Error: Debug + Display {
     /// fn main() {
     ///     match get_super_error() {
     ///         Err(e) => {
-    ///             println!("Error: {}", e);
+    ///             println!("Error: {e}");
     ///             println!("Caused by: {}", e.source().unwrap());
     ///         }
     ///         _ => println!("No error"),
@@ -139,7 +139,7 @@ fn backtrace(&self) -> Option<&Backtrace> {
     /// ```
     /// if let Err(e) = "xc".parse::<u32>() {
     ///     // Print `e` itself, no need for description().
-    ///     eprintln!("Error: {}", e);
+    ///     eprintln!("Error: {e}");
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1074,7 +1074,7 @@ impl<E> Report<E> {
     ///
     /// let error = SuperError { source: SuperErrorSideKick };
     /// let report = Report::new(error).pretty(true);
-    /// eprintln!("Error: {:?}", report);
+    /// eprintln!("Error: {report:?}");
     /// ```
     ///
     /// This example produces the following output:
@@ -1135,7 +1135,7 @@ impl<E> Report<E> {
     /// let source = SuperErrorSideKick { source };
     /// let error = SuperError { source };
     /// let report = Report::new(error).pretty(true);
-    /// eprintln!("Error: {:?}", report);
+    /// eprintln!("Error: {report:?}");
     /// ```
     ///
     /// This example produces the following output:
@@ -1210,7 +1210,7 @@ pub fn pretty(mut self, pretty: bool) -> Self {
     /// let source = SuperErrorSideKick::new();
     /// let error = SuperError { source };
     /// let report = Report::new(error).pretty(true).show_backtrace(true);
-    /// eprintln!("Error: {:?}", report);
+    /// eprintln!("Error: {report:?}");
     /// ```
     ///
     /// This example produces something similar to the following output:
@@ -1267,7 +1267,7 @@ fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
 
         for cause in sources {
-            write!(f, ": {}", cause)?;
+            write!(f, ": {cause}")?;
         }
 
         Ok(())
@@ -1278,7 +1278,7 @@ fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let error = &self.error;
 
-        write!(f, "{}", error)?;
+        write!(f, "{error}")?;
 
         if let Some(cause) = error.source() {
             write!(f, "\n\nCaused by:")?;
@@ -1289,9 +1289,9 @@ fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 writeln!(f)?;
                 let mut indented = Indented { inner: f };
                 if multiple {
-                    write!(indented, "{: >4}: {}", ind, error)?;
+                    write!(indented, "{ind: >4}: {error}")?;
                 } else {
-                    write!(indented, "      {}", error)?;
+                    write!(indented, "      {error}")?;
                 }
             }
         }
@@ -1333,7 +1333,7 @@ fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
 
         for cause in sources {
-            write!(f, ": {}", cause)?;
+            write!(f, ": {cause}")?;
         }
 
         Ok(())
@@ -1344,7 +1344,7 @@ fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let error = &self.error;
 
-        write!(f, "{}", error)?;
+        write!(f, "{error}")?;
 
         if let Some(cause) = error.source() {
             write!(f, "\n\nCaused by:")?;
@@ -1355,9 +1355,9 @@ fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 writeln!(f)?;
                 let mut indented = Indented { inner: f };
                 if multiple {
-                    write!(indented, "{: >4}: {}", ind, error)?;
+                    write!(indented, "{ind: >4}: {error}")?;
                 } else {
-                    write!(indented, "      {}", error)?;
+                    write!(indented, "      {error}")?;
                 }
             }
         }
index eae5f43ff3cfb060b424b6a59aa0d8e40e35b2ad..a2a35d96ec918a5b91ead9e51053df3524fb24fa 100644 (file)
@@ -130,7 +130,7 @@ fn error_with_backtrace_outputs_correctly_with_one_source() {
     error.backtrace = Some(trace);
     let report = Report::new(error).pretty(true).show_backtrace(true);
 
-    println!("Error: {}", report);
+    println!("Error: {report}");
     assert_eq!(expected.trim_end(), report.to_string());
 }
 
@@ -155,7 +155,7 @@ fn error_with_backtrace_outputs_correctly_with_two_sources() {
     let error = GenericError::new_with_source("Error with two sources", error);
     let report = Report::new(error).pretty(true).show_backtrace(true);
 
-    println!("Error: {}", report);
+    println!("Error: {report}");
     assert_eq!(expected.trim_end(), report.to_string());
 }
 
@@ -355,7 +355,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    1: The message goes on and on.";
 
     let actual = report.to_string();
-    println!("{}", actual);
+    println!("{actual}");
     assert_eq!(expected, actual);
 }
 
index 1678367290e5103d1b85f2a5a3edc3a7f6a7904e..b833d0e2ca5072bbf2a3ff0543a08789d159e9c3 100644 (file)
@@ -1120,7 +1120,7 @@ impl fmt::Display for FromBytesWithNulError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.write_str(self.description())?;
         if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
-            write!(f, " at byte pos {}", pos)?;
+            write!(f, " at byte pos {pos}")?;
         }
         Ok(())
     }
@@ -1134,7 +1134,7 @@ impl fmt::Display for FromVecWithNulError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.error_kind {
             FromBytesWithNulErrorKind::InteriorNul(pos) => {
-                write!(f, "data provided contains an interior nul byte at pos {}", pos)
+                write!(f, "data provided contains an interior nul byte at pos {pos}")
             }
             FromBytesWithNulErrorKind::NotNulTerminated => {
                 write!(f, "data provided is not nul terminated")
index 00ba5460821ff356601febf2f8d13452725e0bb7..8d603229315c08ff5b2d4d57410c81b428f54481 100644 (file)
@@ -35,7 +35,7 @@ fn build_with_zero2() {
 #[test]
 fn formatted() {
     let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
-    assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
+    assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
 }
 
 #[test]
index 0b65336a5a7dac2b6d499026dec5ebd7f334a04e..c99d9b279a92881c0b05619b8fe3588b2d710519 100644 (file)
@@ -1123,7 +1123,7 @@ pub fn permissions(&self) -> Permissions {
     ///     let metadata = fs::metadata("foo.txt")?;
     ///
     ///     if let Ok(time) = metadata.modified() {
-    ///         println!("{:?}", time);
+    ///         println!("{time:?}");
     ///     } else {
     ///         println!("Not supported on this platform");
     ///     }
@@ -1158,7 +1158,7 @@ pub fn modified(&self) -> io::Result<SystemTime> {
     ///     let metadata = fs::metadata("foo.txt")?;
     ///
     ///     if let Ok(time) = metadata.accessed() {
-    ///         println!("{:?}", time);
+    ///         println!("{time:?}");
     ///     } else {
     ///         println!("Not supported on this platform");
     ///     }
@@ -1190,7 +1190,7 @@ pub fn accessed(&self) -> io::Result<SystemTime> {
     ///     let metadata = fs::metadata("foo.txt")?;
     ///
     ///     if let Ok(time) = metadata.created() {
-    ///         println!("{:?}", time);
+    ///         println!("{time:?}");
     ///     } else {
     ///         println!("Not supported on this platform or filesystem");
     ///     }
index 16b8bf68242ef5bd1ebf9f781c283caf344162bf..6d67c396c623a759ba323ce421f22c01577d894e 100644 (file)
@@ -1,5 +1,6 @@
 use crate::io::prelude::*;
 
+use crate::env;
 use crate::fs::{self, File, OpenOptions};
 use crate::io::{ErrorKind, SeekFrom};
 use crate::path::Path;
@@ -30,7 +31,7 @@ macro_rules! check {
     ($e:expr) => {
         match $e {
             Ok(t) => t,
-            Err(e) => panic!("{} failed with: {}", stringify!($e), e),
+            Err(e) => panic!("{} failed with: {e}", stringify!($e)),
         }
     };
 }
@@ -470,7 +471,7 @@ fn file_test_directoryinfo_readdir() {
     check!(fs::create_dir(dir));
     let prefix = "foo";
     for n in 0..3 {
-        let f = dir.join(&format!("{}.txt", n));
+        let f = dir.join(&format!("{n}.txt"));
         let mut w = check!(File::create(&f));
         let msg_str = format!("{}{}", prefix, n.to_string());
         let msg = msg_str.as_bytes();
@@ -906,7 +907,14 @@ fn read_link() {
         // junction
         assert_eq!(check!(fs::read_link(r"C:\Users\Default User")), Path::new(r"C:\Users\Default"));
         // junction with special permissions
-        assert_eq!(check!(fs::read_link(r"C:\Documents and Settings\")), Path::new(r"C:\Users"));
+        // Since not all localized windows versions contain the folder "Documents and Settings" in english,
+        // we will briefly check, if it exists and otherwise skip the test. Except during CI we will always execute the test.
+        if Path::new(r"C:\Documents and Settings\").exists() || env::var_os("CI").is_some() {
+            assert_eq!(
+                check!(fs::read_link(r"C:\Documents and Settings\")),
+                Path::new(r"C:\Users")
+            );
+        }
     }
     let tmpdir = tmpdir();
     let link = tmpdir.join("link");
@@ -1329,7 +1337,7 @@ fn dir_entry_methods() {
                 assert!(file.file_type().unwrap().is_file());
                 assert!(file.metadata().unwrap().is_file());
             }
-            f => panic!("unknown file name: {:?}", f),
+            f => panic!("unknown file name: {f:?}"),
         }
     }
 }
@@ -1340,7 +1348,7 @@ fn dir_entry_debug() {
     File::create(&tmpdir.join("b")).unwrap();
     let mut read_dir = tmpdir.path().read_dir().unwrap();
     let dir_entry = read_dir.next().unwrap().unwrap();
-    let actual = format!("{:?}", dir_entry);
+    let actual = format!("{dir_entry:?}");
     let expected = format!("DirEntry({:?})", dir_entry.0.path());
     assert_eq!(actual, expected);
 }
@@ -1409,7 +1417,7 @@ fn metadata_access_times() {
                     || e1.kind() == ErrorKind::Unsupported
                         && e2.kind() == ErrorKind::Unsupported => {}
             (a, b) => {
-                panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,)
+                panic!("creation time must be always supported or not supported: {a:?} {b:?}")
             }
         }
     }
index e7eee4436249b5073e76038d84c1f7be60ba27b9..989cec976b72fb58343247b9d51be3c0c5f27f7d 100644 (file)
@@ -41,7 +41,7 @@
 ///
 ///     let mut line = String::new();
 ///     let len = reader.read_line(&mut line)?;
-///     println!("First line is {} bytes long", len);
+///     println!("First line is {len} bytes long");
 ///     Ok(())
 /// }
 /// ```
index 17e2b97545a94d43878659b6a972ebbb95452267..4a50e647c640ef5bc813abbbe67f73a8b7b2af82 100644 (file)
@@ -457,7 +457,7 @@ impl From<ErrorKind> for Error {
     ///
     /// let not_found = ErrorKind::NotFound;
     /// let error = Error::from(not_found);
-    /// assert_eq!("entity not found", format!("{}", error));
+    /// assert_eq!("entity not found", format!("{error}"));
     /// ```
     #[inline]
     fn from(kind: ErrorKind) -> Error {
@@ -561,7 +561,7 @@ pub(crate) const fn from_static_message(msg: &'static SimpleMessage) -> Error {
     /// use std::io::Error;
     ///
     /// let os_error = Error::last_os_error();
-    /// println!("last OS error: {:?}", os_error);
+    /// println!("last OS error: {os_error:?}");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
@@ -618,7 +618,7 @@ pub fn from_raw_os_error(code: i32) -> Error {
     ///
     /// fn print_os_error(err: &Error) {
     ///     if let Some(raw_os_err) = err.raw_os_error() {
-    ///         println!("raw OS error: {:?}", raw_os_err);
+    ///         println!("raw OS error: {raw_os_err:?}");
     ///     } else {
     ///         println!("Not an OS error");
     ///     }
@@ -657,7 +657,7 @@ pub fn raw_os_error(&self) -> Option<i32> {
     ///
     /// fn print_error(err: &Error) {
     ///     if let Some(inner_err) = err.get_ref() {
-    ///         println!("Inner error: {:?}", inner_err);
+    ///         println!("Inner error: {inner_err:?}");
     ///     } else {
     ///         println!("No inner error");
     ///     }
@@ -731,7 +731,7 @@ pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
     ///
     /// fn print_error(err: &Error) {
     ///     if let Some(inner_err) = err.get_ref() {
-    ///         println!("Inner error: {}", inner_err);
+    ///         println!("Inner error: {inner_err}");
     ///     } else {
     ///         println!("No inner error");
     ///     }
@@ -770,7 +770,7 @@ pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'stat
     ///
     /// fn print_error(err: Error) {
     ///     if let Some(inner_err) = err.into_inner() {
-    ///         println!("Inner error: {}", inner_err);
+    ///         println!("Inner error: {inner_err}");
     ///     } else {
     ///         println!("No inner error");
     ///     }
@@ -852,7 +852,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.repr.data() {
             ErrorData::Os(code) => {
                 let detail = sys::os::error_string(code);
-                write!(fmt, "{} (os error {})", detail, code)
+                write!(fmt, "{detail} (os error {code})")
             }
             ErrorData::Custom(ref c) => c.error.fmt(fmt),
             ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()),
index 4301e941b3dce1b57efbe10f446b078e744a23e4..1a0538f861a1e0b5f59b319acc6a641dc0b7e966 100644 (file)
@@ -161,8 +161,7 @@ pub(super) fn new_os(code: i32) -> Self {
         // only run in libstd's tests, unless the user uses -Zbuild-std)
         debug_assert!(
             matches!(res.data(), ErrorData::Os(c) if c == code),
-            "repr(os) encoding failed for {}",
-            code,
+            "repr(os) encoding failed for {code}"
         );
         res
     }
index c2c51553b208c25253eff217e4891d2f9b2f5dce..6fd15fa80488b0eac8bedf3c1664ae4d72eaac08 100644 (file)
@@ -33,7 +33,7 @@ fn test_debug_error() {
          }}",
         code, kind, msg
     );
-    assert_eq!(format!("{:?}", err), expected);
+    assert_eq!(format!("{err:?}"), expected);
 }
 
 #[test]
@@ -65,8 +65,8 @@ fn test_const() {
 
     assert_eq!(E.kind(), ErrorKind::NotFound);
     assert_eq!(E.to_string(), "hello");
-    assert!(format!("{:?}", E).contains("\"hello\""));
-    assert!(format!("{:?}", E).contains("NotFound"));
+    assert!(format!("{E:?}").contains("\"hello\""));
+    assert!(format!("{E:?}").contains("NotFound"));
 }
 
 #[test]
@@ -101,7 +101,7 @@ macro_rules! check_simple_msg {
             let e = &$err;
             // Check that the public api is right.
             assert_eq!(e.kind(), $kind);
-            assert!(format!("{:?}", e).contains($msg));
+            assert!(format!("{e:?}").contains($msg));
             // and we got what we expected
             assert_matches!(
                 e.repr.data(),
index 3fa965d08e6981b629f39fa4e6a4fdba30287eb5..6005270a75fec1b9d231ef7a46f014cebdac0fdd 100644 (file)
@@ -91,7 +91,7 @@
 //!     // read a line into buffer
 //!     reader.read_line(&mut buffer)?;
 //!
-//!     println!("{}", buffer);
+//!     println!("{buffer}");
 //!     Ok(())
 //! }
 //! ```
@@ -1035,7 +1035,7 @@ fn take(self, limit: u64) -> Take<Self>
 /// fn main() -> io::Result<()> {
 ///     let stdin = io::read_to_string(io::stdin())?;
 ///     println!("Stdin was:");
-///     println!("{}", stdin);
+///     println!("{stdin}");
 ///     Ok(())
 /// }
 /// ```
@@ -1761,7 +1761,7 @@ pub trait Seek {
     ///     .open("foo.txt").unwrap();
     ///
     /// let hello = "Hello!\n";
-    /// write!(f, "{}", hello).unwrap();
+    /// write!(f, "{hello}").unwrap();
     /// f.rewind().unwrap();
     ///
     /// let mut buf = String::new();
@@ -1804,7 +1804,7 @@ fn rewind(&mut self) -> Result<()> {
     ///     let mut f = File::open("foo.txt")?;
     ///
     ///     let len = f.stream_len()?;
-    ///     println!("The file is currently {} bytes long", len);
+    ///     println!("The file is currently {len} bytes long");
     ///     Ok(())
     /// }
     /// ```
@@ -1988,7 +1988,7 @@ pub trait BufRead: Read {
     /// let buffer = stdin.fill_buf().unwrap();
     ///
     /// // work with buffer
-    /// println!("{:?}", buffer);
+    /// println!("{buffer:?}");
     ///
     /// // ensure the bytes we worked with aren't returned again later
     /// let length = buffer.len();
@@ -2042,7 +2042,7 @@ pub trait BufRead: Read {
     ///     let mut line = String::new();
     ///     stdin.read_line(&mut line).unwrap();
     ///     // work with line
-    ///     println!("{:?}", line);
+    ///     println!("{line:?}");
     /// }
     /// ```
     #[unstable(feature = "buf_read_has_data_left", reason = "recently added", issue = "86423")]
index 5414ff648d4d5f5051ccf64d5a71e0aa3b5ed239..50344e602a958f5df8e72308f9a05d06573db11e 100644 (file)
@@ -349,10 +349,10 @@ pub fn lock(&self) -> StdinLock<'static> {
     /// let mut input = String::new();
     /// match io::stdin().read_line(&mut input) {
     ///     Ok(n) => {
-    ///         println!("{} bytes read", n);
-    ///         println!("{}", input);
+    ///         println!("{n} bytes read");
+    ///         println!("{input}");
     ///     }
-    ///     Err(error) => println!("error: {}", error),
+    ///     Err(error) => println!("error: {error}"),
     /// }
     /// ```
     ///
@@ -953,7 +953,7 @@ fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
     }
 
     if let Err(e) = global_s().write_fmt(args) {
-        panic!("failed printing to {}: {}", label, e);
+        panic!("failed printing to {label}: {e}");
     }
 }
 
index 5b76259afc11de8c0bf7f6830e1c33be675fae3e..542b793f6da05a7a764c1f900c6855a3db30c196 100644 (file)
@@ -64,7 +64,7 @@ mod as_keyword {}
 /// }
 ///
 /// assert_eq!(last, 12);
-/// println!("{}", last);
+/// println!("{last}");
 /// ```
 ///
 /// A break expression is normally associated with the innermost loop enclosing the
@@ -72,10 +72,10 @@ mod as_keyword {}
 ///
 ///```rust
 /// 'outer: for i in 1..=5 {
-///     println!("outer iteration (i): {}", i);
+///     println!("outer iteration (i): {i}");
 ///
 ///     '_inner: for j in 1..=200 {
-///         println!("    inner iteration (j): {}", j);
+///         println!("    inner iteration (j): {j}");
 ///         if j >= 3 {
 ///             // breaks from inner loop, lets outer loop continue.
 ///             break;
@@ -106,7 +106,7 @@ mod as_keyword {}
 /// };
 /// // first number in Fibonacci sequence over 10:
 /// assert_eq!(result, 13);
-/// println!("{}", result);
+/// println!("{result}");
 /// ```
 ///
 /// For more details consult the [Reference on "break expression"] and the [Reference on "break and
@@ -200,7 +200,7 @@ mod const_keyword {}
 ///     if number % 2 == 0 {
 ///         continue;
 ///     }
-///     println!("{}", number);
+///     println!("{number}");
 /// }
 ///```
 ///
@@ -515,7 +515,7 @@ mod fn_keyword {}
 /// }
 ///
 /// for i in std::iter::repeat(5) {
-///     println!("turns out {} never stops being 5", i);
+///     println!("turns out {i} never stops being 5");
 ///     break; // would loop forever otherwise
 /// }
 ///
@@ -776,7 +776,7 @@ mod in_keyword {}
 /// let shadowing_example = true;
 /// let shadowing_example = 123.4;
 /// let shadowing_example = shadowing_example as u32;
-/// let mut shadowing_example = format!("cool! {}", shadowing_example);
+/// let mut shadowing_example = format!("cool! {shadowing_example}");
 /// shadowing_example += " something else!"; // not shadowing
 /// ```
 ///
@@ -805,7 +805,7 @@ mod let_keyword {}
 /// let mut counter = 0;
 ///
 /// while counter < 10 {
-///     println!("{}", counter);
+///     println!("{counter}");
 ///     counter += 1;
 /// }
 /// ```
@@ -836,7 +836,7 @@ mod let_keyword {}
 ///     if i == 10 {
 ///         counter = None;
 ///     } else {
-///         println!("{}", i);
+///         println!("{i}");
 ///         counter = Some (i + 1);
 ///     }
 /// }
@@ -866,7 +866,7 @@ mod while_keyword {}
 ///
 /// let mut i = 1;
 /// loop {
-///     println!("i is {}", i);
+///     println!("i is {i}");
 ///     if i > 100 {
 ///         break;
 ///     }
@@ -920,8 +920,8 @@ mod loop_keyword {}
 ///
 /// let a_number = Option::Some(10);
 /// match a_number {
-///     Some(x) if x <= 5 => println!("0 to 5 num = {}", x),
-///     Some(x @ 6..=10) => println!("6 to 10 num = {}", x),
+///     Some(x) if x <= 5 => println!("0 to 5 num = {x}"),
+///     Some(x @ 6..=10) => println!("6 to 10 num = {x}"),
 ///     None => panic!(),
 ///     // all other numbers
 ///     _ => panic!(),
@@ -940,8 +940,8 @@ mod loop_keyword {}
 ///
 /// let get_inner = Outer::Double(None, Some(String::new()));
 /// match get_inner {
-///     Outer::Double(None, Some(st)) => println!("{}", st),
-///     Outer::Single(opt) => println!("{:?}", opt),
+///     Outer::Double(None, Some(st)) => println!("{st}"),
+///     Outer::Single(opt) => println!("{opt:?}"),
 ///     _ => panic!(),
 /// }
 /// ```
@@ -988,7 +988,7 @@ mod mod_keyword {}
 ///
 /// ```rust
 /// let data = vec![1, 2, 3];
-/// let closure = move || println!("captured {:?} by value", data);
+/// let closure = move || println!("captured {data:?} by value");
 ///
 /// // data is no longer available, it is owned by the closure
 /// ```
@@ -1001,7 +1001,7 @@ mod mod_keyword {}
 /// ```rust
 /// fn create_fn() -> impl Fn() {
 ///     let text = "Fn".to_owned();
-///     move || println!("This is a: {}", text)
+///     move || println!("This is a: {text}")
 /// }
 ///
 /// let fn_plain = create_fn();
@@ -1014,7 +1014,7 @@ mod mod_keyword {}
 /// let data = vec![1, 2, 3];
 ///
 /// std::thread::spawn(move || {
-///     println!("captured {:?} by value", data)
+///     println!("captured {data:?} by value")
 /// }).join().unwrap();
 ///
 /// // data was moved to the spawned thread, so we cannot use it here
@@ -1025,7 +1025,7 @@ mod mod_keyword {}
 /// ```rust
 /// let capture = "hello".to_owned();
 /// let block = async move {
-///     println!("rust says {} from async block", capture);
+///     println!("rust says {capture} from async block");
 /// };
 /// ```
 ///
@@ -1124,7 +1124,7 @@ mod pub_keyword {}
 /// let maybe_name = Some(String::from("Alice"));
 /// // The variable 'maybe_name' is consumed here ...
 /// match maybe_name {
-///     Some(n) => println!("Hello, {}", n),
+///     Some(n) => println!("Hello, {n}"),
 ///     _ => println!("Hello, world"),
 /// }
 /// // ... and is now unavailable.
@@ -1138,7 +1138,7 @@ mod pub_keyword {}
 /// let maybe_name = Some(String::from("Alice"));
 /// // Using `ref`, the value is borrowed, not moved ...
 /// match maybe_name {
-///     Some(ref n) => println!("Hello, {}", n),
+///     Some(ref n) => println!("Hello, {n}"),
 ///     _ => println!("Hello, world"),
 /// }
 /// // ... so it's available here!
@@ -1423,7 +1423,7 @@ mod self_upper_keyword {}
 /// // With a strictly read-only static, references will have the same address
 /// assert_eq!(r1, r2);
 /// // A static item can be used just like a variable in many cases
-/// println!("{:?}", FOO);
+/// println!("{FOO:?}");
 /// ```
 ///
 /// # Mutable `static`s
@@ -1675,7 +1675,7 @@ mod super_keyword {}
 /// # #![allow(dead_code)]
 /// fn debug_iter<I: Iterator>(it: I) where I::Item: std::fmt::Debug {
 ///     for elem in it {
-///         println!("{:#?}", elem);
+///         println!("{elem:#?}");
 ///     }
 /// }
 ///
@@ -2313,7 +2313,7 @@ mod dyn_keyword {}
 ///     match u {
 ///         IntOrFloat { i: 10 } => println!("Found exactly ten!"),
 ///         // Matching the field `f` provides an `f32`.
-///         IntOrFloat { f } => println!("Found f = {} !", f),
+///         IntOrFloat { f } => println!("Found f = {f} !"),
 ///     }
 /// }
 /// ```
@@ -2337,7 +2337,7 @@ mod dyn_keyword {}
 /// let i = unsafe { &mut u.i };
 ///
 /// *i = 10;
-/// println!("f = {} and i = {}", f, i);
+/// println!("f = {f} and i = {i}");
 /// ```
 ///
 /// See the [Reference][union] for more informations on `union`s.
index 36e6032b5e4e5204c4d51a4aa822cabe45ba7066..a464f2d4c7431f1102f87c42792912744f1af3c1 100644 (file)
 #![feature(assert_matches)]
 #![feature(associated_type_bounds)]
 #![feature(async_iterator)]
+#![feature(atomic_mut_ptr)]
 #![feature(bench_black_box)]
 #![feature(box_syntax)]
 #![feature(c_unwind)]
 #![feature(char_internals)]
 #![feature(concat_bytes)]
 #![feature(concat_idents)]
-#![feature(const_fn_fn_ptr_basics)]
-#![feature(const_fn_trait_bound)]
+#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
 #![feature(const_format_args)]
 #![feature(const_io_structs)]
 #![feature(const_ip)]
 #![feature(doc_cfg)]
 #![feature(doc_cfg_hide)]
 #![feature(rustdoc_internals)]
+#![cfg_attr(not(bootstrap), feature(deprecated_suggestion))]
 #![feature(doc_masked)]
 #![feature(doc_notable_trait)]
 #![feature(dropck_eyepatch)]
 #[macro_use]
 mod macros;
 
+// The runtime entry point and a few unstable public functions used by the
+// compiler
+#[macro_use]
+pub mod rt;
+
 // The Rust prelude
 pub mod prelude;
 
 #[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
 #[allow(rustdoc::bare_urls)]
 #[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
 mod std_float;
 
-#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
 #[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
 #[unstable(feature = "portable_simd", issue = "86656")]
 pub mod simd {
@@ -546,11 +551,6 @@ pub mod arch {
 #[stable(feature = "simd_x86", since = "1.27.0")]
 pub use std_detect::is_x86_feature_detected;
 
-// The runtime entry point and a few unstable public functions used by the
-// compiler
-#[macro_use]
-pub mod rt;
-
 // Platform-abstraction modules
 mod sys;
 mod sys_common;
index 40f5a84bcd520a3f19e1eaf90a34c39daae45802..585a17451a0b7ca225d670ec1dbad031fd98fa5e 100644 (file)
@@ -169,30 +169,30 @@ fn is_v6() {
 fn socket_v4_to_str() {
     let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080);
 
-    assert_eq!(format!("{}", socket), "192.168.0.1:8080");
-    assert_eq!(format!("{:<20}", socket), "192.168.0.1:8080    ");
-    assert_eq!(format!("{:>20}", socket), "    192.168.0.1:8080");
-    assert_eq!(format!("{:^20}", socket), "  192.168.0.1:8080  ");
-    assert_eq!(format!("{:.10}", socket), "192.168.0.");
+    assert_eq!(format!("{socket}"), "192.168.0.1:8080");
+    assert_eq!(format!("{socket:<20}"), "192.168.0.1:8080    ");
+    assert_eq!(format!("{socket:>20}"), "    192.168.0.1:8080");
+    assert_eq!(format!("{socket:^20}"), "  192.168.0.1:8080  ");
+    assert_eq!(format!("{socket:.10}"), "192.168.0.");
 }
 
 #[test]
 fn socket_v6_to_str() {
     let mut socket = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0);
 
-    assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53");
-    assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53    ");
-    assert_eq!(format!("{:>24}", socket), "    [2a02:6b8:0:1::1]:53");
-    assert_eq!(format!("{:^24}", socket), "  [2a02:6b8:0:1::1]:53  ");
-    assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::");
+    assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1]:53");
+    assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1]:53    ");
+    assert_eq!(format!("{socket:>24}"), "    [2a02:6b8:0:1::1]:53");
+    assert_eq!(format!("{socket:^24}"), "  [2a02:6b8:0:1::1]:53  ");
+    assert_eq!(format!("{socket:.15}"), "[2a02:6b8:0:1::");
 
     socket.set_scope_id(5);
 
-    assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1%5]:53");
-    assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1%5]:53  ");
-    assert_eq!(format!("{:>24}", socket), "  [2a02:6b8:0:1::1%5]:53");
-    assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1%5]:53 ");
-    assert_eq!(format!("{:.18}", socket), "[2a02:6b8:0:1::1%5");
+    assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1%5]:53");
+    assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1%5]:53  ");
+    assert_eq!(format!("{socket:>24}"), "  [2a02:6b8:0:1::1%5]:53");
+    assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1%5]:53 ");
+    assert_eq!(format!("{socket:.18}"), "[2a02:6b8:0:1::1%5");
 }
 
 #[test]
index cc4e4fd4fdc77585f40c0bf129cf2834dbd3d173..f5d3c4905e0813841f86c9c22badd0e0fb69fda9 100644 (file)
@@ -595,10 +595,10 @@ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
     ///             // via platform-specific APIs such as epoll or IOCP
     ///             wait_for_fd();
     ///         }
-    ///         Err(e) => panic!("encountered IO error: {}", e),
+    ///         Err(e) => panic!("encountered IO error: {e}"),
     ///     };
     /// };
-    /// println!("bytes: {:?}", buf);
+    /// println!("bytes: {buf:?}");
     /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
@@ -799,8 +799,8 @@ pub fn try_clone(&self) -> io::Result<TcpListener> {
     ///
     /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
     /// match listener.accept() {
-    ///     Ok((_socket, addr)) => println!("new client: {:?}", addr),
-    ///     Err(e) => println!("couldn't get client: {:?}", e),
+    ///     Ok((_socket, addr)) => println!("new client: {addr:?}"),
+    ///     Err(e) => println!("couldn't get client: {e:?}"),
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -991,7 +991,7 @@ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
     ///             wait_for_fd();
     ///             continue;
     ///         }
-    ///         Err(e) => panic!("encountered IO error: {}", e),
+    ///         Err(e) => panic!("encountered IO error: {e}"),
     ///     }
     /// }
     /// ```
index c2061c1351262595cf9f9d804da9a87f1a606f0e..8c0adcfb0ebbbaca3575a96b8d75bed3c4e47d81 100644 (file)
@@ -142,8 +142,7 @@ fn write_close() {
                     e.kind() == ErrorKind::ConnectionReset
                         || e.kind() == ErrorKind::BrokenPipe
                         || e.kind() == ErrorKind::ConnectionAborted,
-                    "unknown error: {}",
-                    e
+                    "unknown error: {e}"
                 );
             }
         }
@@ -508,7 +507,7 @@ fn close_readwrite_smoke() {
 }
 
 #[test]
-#[cfg(unix)] // test doesn't work on Windows, see #31657
+#[cfg_attr(target_env = "sgx", ignore)]
 fn close_read_wakes_up() {
     each_ip(&mut |addr| {
         let a = t!(TcpListener::bind(&addr));
@@ -655,7 +654,7 @@ fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Deb
         inner_name,
         render_inner(&listener)
     );
-    assert_eq!(format!("{:?}", listener), compare);
+    assert_eq!(format!("{listener:?}"), compare);
 
     let stream = t!(TcpStream::connect(&("localhost", socket_addr.port())));
     let compare = format!(
@@ -665,7 +664,7 @@ fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Deb
         inner_name,
         render_inner(&stream)
     );
-    assert_eq!(format!("{:?}", stream), compare);
+    assert_eq!(format!("{stream:?}"), compare);
 }
 
 // FIXME: re-enabled openbsd tests once their socket timeout code
@@ -832,7 +831,7 @@ fn set_nonblocking() {
     match stream.read(&mut buf) {
         Ok(_) => panic!("expected error"),
         Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
-        Err(e) => panic!("unexpected error {}", e),
+        Err(e) => panic!("unexpected error {e}"),
     }
 }
 
@@ -862,7 +861,7 @@ fn peek() {
         match c.peek(&mut b) {
             Ok(_) => panic!("expected error"),
             Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
-            Err(e) => panic!("unexpected error {}", e),
+            Err(e) => panic!("unexpected error {e}"),
         }
         t!(txdone.send(()));
     })
index 11a696e92c82565725411e01b018e8d1bf61c5fd..864e1b0f3450a6c992e3bef0fd200c6f4798cff9 100644 (file)
@@ -605,9 +605,9 @@ pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Re
     ///
     /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
     /// match socket.take_error() {
-    ///     Ok(Some(error)) => println!("UdpSocket error: {:?}", error),
+    ///     Ok(Some(error)) => println!("UdpSocket error: {error:?}"),
     ///     Ok(None) => println!("No error"),
-    ///     Err(error) => println!("UdpSocket.take_error failed: {:?}", error),
+    ///     Err(error) => println!("UdpSocket.take_error failed: {error:?}"),
     /// }
     /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
@@ -686,8 +686,8 @@ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
     /// socket.connect("127.0.0.1:8080").expect("connect function failed");
     /// let mut buf = [0; 10];
     /// match socket.recv(&mut buf) {
-    ///     Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]),
-    ///     Err(e) => println!("recv function failed: {:?}", e),
+    ///     Ok(received) => println!("received {received} bytes {:?}", &buf[..received]),
+    ///     Err(e) => println!("recv function failed: {e:?}"),
     /// }
     /// ```
     #[stable(feature = "net2_mutators", since = "1.9.0")]
@@ -726,8 +726,8 @@ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
     /// socket.connect("127.0.0.1:8080").expect("connect function failed");
     /// let mut buf = [0; 10];
     /// match socket.peek(&mut buf) {
-    ///     Ok(received) => println!("received {} bytes", received),
-    ///     Err(e) => println!("peek function failed: {:?}", e),
+    ///     Ok(received) => println!("received {received} bytes"),
+    ///     Err(e) => println!("peek function failed: {e:?}"),
     /// }
     /// ```
     #[stable(feature = "peek", since = "1.18.0")]
@@ -770,7 +770,7 @@ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
     ///             // via platform-specific APIs such as epoll or IOCP
     ///             wait_for_fd();
     ///         }
-    ///         Err(e) => panic!("encountered IO error: {}", e),
+    ///         Err(e) => panic!("encountered IO error: {e}"),
     ///     }
     /// };
     /// println!("bytes: {:?}", &buf[..num_bytes_read]);
index a51113dd9e74925aa6199dc7a579cfd99f830442..f82904ffbbf776cb5343f6371ea347b028ce8b96 100644 (file)
@@ -173,8 +173,8 @@ fn debug() {
 
     let udpsock = t!(UdpSocket::bind(&socket_addr));
     let udpsock_inner = udpsock.0.socket().as_raw();
-    let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner);
-    assert_eq!(format!("{:?}", udpsock), compare);
+    let compare = format!("UdpSocket {{ addr: {socket_addr:?}, {name}: {udpsock_inner:?} }}");
+    assert_eq!(format!("{udpsock:?}"), compare);
 }
 
 // FIXME: re-enabled openbsd/netbsd tests once their socket timeout code
@@ -359,7 +359,7 @@ fn set_nonblocking() {
         match socket.recv(&mut buf) {
             Ok(_) => panic!("expected error"),
             Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
-            Err(e) => panic!("unexpected error {}", e),
+            Err(e) => panic!("unexpected error {e}"),
         }
     })
 }
index 75d65e6d5fc036bff10c39ab60f6cd2636b62a79..3fc6cc44ce4c8291161deaee311a83a41050cac1 100644 (file)
@@ -47,7 +47,7 @@ pub trait FileExt {
     ///
     ///     // We now read 8 bytes from the offset 10.
     ///     let num_bytes_read = file.read_at(&mut buf, 10)?;
-    ///     println!("read {} bytes: {:?}", num_bytes_read, buf);
+    ///     println!("read {num_bytes_read} bytes: {buf:?}");
     ///     Ok(())
     /// }
     /// ```
@@ -861,7 +861,7 @@ pub trait DirEntryExt2: Sealed {
     ///     entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref()));
     ///
     ///     for p in entries {
-    ///         println!("{:?}", p);
+    ///         println!("{p:?}");
     ///     }
     ///
     ///     Ok(())
index 034fa301ba1ead4c434edf14adb9a41886f22844..a3ef4b2d92cc46213fe769f279ec98e1d7ad1c30 100644 (file)
@@ -86,7 +86,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// let socket = match UnixListener::bind("/tmp/sock") {
 ///     Ok(sock) => sock,
 ///     Err(e) => {
-///         println!("Couldn't bind: {:?}", e);
+///         println!("Couldn't bind: {e:?}");
 ///         return
 ///     }
 /// };
@@ -140,12 +140,11 @@ pub(super) fn from_parts(
     /// # Examples
     ///
     /// ```
-    /// #![feature(unix_socket_creation)]
     /// use std::os::unix::net::SocketAddr;
     /// use std::path::Path;
     ///
     /// # fn main() -> std::io::Result<()> {
-    /// let address = SocketAddr::from_path("/path/to/socket")?;
+    /// let address = SocketAddr::from_pathname("/path/to/socket")?;
     /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
     /// # Ok(())
     /// # }
@@ -154,13 +153,12 @@ pub(super) fn from_parts(
     /// Creating a `SocketAddr` with a NULL byte results in an error.
     ///
     /// ```
-    /// #![feature(unix_socket_creation)]
     /// use std::os::unix::net::SocketAddr;
     ///
-    /// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err());
+    /// assert!(SocketAddr::from_pathname("/path/with/\0/bytes").is_err());
     /// ```
-    #[unstable(feature = "unix_socket_creation", issue = "93423")]
-    pub fn from_path<P>(path: P) -> io::Result<SocketAddr>
+    #[stable(feature = "unix_socket_creation", since = "1.61.0")]
+    pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr>
     where
         P: AsRef<Path>,
     {
@@ -307,7 +305,7 @@ fn address(&self) -> AddressKind<'_> {
     ///     let listener = match UnixListener::bind_addr(&addr) {
     ///         Ok(sock) => sock,
     ///         Err(err) => {
-    ///             println!("Couldn't bind: {:?}", err);
+    ///             println!("Couldn't bind: {err:?}");
     ///             return Err(err);
     ///         }
     ///     };
@@ -346,7 +344,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.address() {
             AddressKind::Unnamed => write!(fmt, "(unnamed)"),
             AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
-            AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
+            AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"),
         }
     }
 }
index 6e6f5212b4651d934290ffbb4f07216b214be378..fb1ff4b725ced26b90ae9c27e9b0625220a751c6 100644 (file)
@@ -396,7 +396,7 @@ fn next(&mut self) -> Option<Self::Item> {
 ///     for ancillary_result in ancillary.messages() {
 ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
 ///             for fd in scm_rights {
-///                 println!("receive file descriptor: {}", fd);
+///                 println!("receive file descriptor: {fd}");
 ///             }
 ///         }
 ///     }
@@ -568,7 +568,7 @@ pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
     ///     for ancillary_result in ancillary.messages() {
     ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
     ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
+    ///                 println!("receive file descriptor: {fd}");
     ///             }
     ///         }
     ///     }
@@ -579,7 +579,7 @@ pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
     ///     for ancillary_result in ancillary.messages() {
     ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
     ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
+    ///                 println!("receive file descriptor: {fd}");
     ///             }
     ///         }
     ///     }
index a2caccc7849170f5ae3e8f68bea8ee2fb1b7ade3..59c91e9a82e1a55335034b227d4fb783d0b2e3ae 100644 (file)
@@ -95,7 +95,7 @@ impl UnixDatagram {
     /// let sock = match UnixDatagram::bind("/path/to/the/socket") {
     ///     Ok(sock) => sock,
     ///     Err(e) => {
-    ///         println!("Couldn't bind: {:?}", e);
+    ///         println!("Couldn't bind: {e:?}");
     ///         return
     ///     }
     /// };
@@ -127,7 +127,7 @@ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
     ///     let sock2 = match UnixDatagram::bind_addr(&addr) {
     ///         Ok(sock) => sock,
     ///         Err(err) => {
-    ///             println!("Couldn't bind: {:?}", err);
+    ///             println!("Couldn't bind: {err:?}");
     ///             return Err(err);
     ///         }
     ///     };
@@ -157,7 +157,7 @@ pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixDatagram> {
     /// let sock = match UnixDatagram::unbound() {
     ///     Ok(sock) => sock,
     ///     Err(e) => {
-    ///         println!("Couldn't unbound: {:?}", e);
+    ///         println!("Couldn't unbound: {e:?}");
     ///         return
     ///     }
     /// };
@@ -180,7 +180,7 @@ pub fn unbound() -> io::Result<UnixDatagram> {
     /// let (sock1, sock2) = match UnixDatagram::pair() {
     ///     Ok((sock1, sock2)) => (sock1, sock2),
     ///     Err(e) => {
-    ///         println!("Couldn't unbound: {:?}", e);
+    ///         println!("Couldn't unbound: {e:?}");
     ///         return
     ///     }
     /// };
@@ -210,7 +210,7 @@ pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
     ///     match sock.connect("/path/to/the/socket") {
     ///         Ok(sock) => sock,
     ///         Err(e) => {
-    ///             println!("Couldn't connect: {:?}", e);
+    ///             println!("Couldn't connect: {e:?}");
     ///             return Err(e)
     ///         }
     ///     };
@@ -243,7 +243,7 @@ pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
     ///     match sock.connect_addr(&addr) {
     ///         Ok(sock) => sock,
     ///         Err(e) => {
-    ///             println!("Couldn't connect: {:?}", e);
+    ///             println!("Couldn't connect: {e:?}");
     ///             return Err(e)
     ///         }
     ///     };
@@ -367,7 +367,7 @@ fn recv_from_flags(
     ///     let sock = UnixDatagram::unbound()?;
     ///     let mut buf = vec![0; 10];
     ///     let (size, sender) = sock.recv_from(buf.as_mut_slice())?;
-    ///     println!("received {} bytes from {:?}", size, sender);
+    ///     println!("received {size} bytes from {sender:?}");
     ///     Ok(())
     /// }
     /// ```
@@ -422,11 +422,11 @@ pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
     ///     let mut ancillary_buffer = [0; 128];
     ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
     ///     let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?;
-    ///     println!("received {}", size);
+    ///     println!("received {size}");
     ///     for ancillary_result in ancillary.messages() {
     ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
     ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
+    ///                 println!("receive file descriptor: {fd}");
     ///             }
     ///         }
     ///     }
@@ -479,11 +479,11 @@ pub fn recv_vectored_with_ancillary_from(
     ///     let mut ancillary_buffer = [0; 128];
     ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
     ///     let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
-    ///     println!("received {}", size);
+    ///     println!("received {size}");
     ///     for ancillary_result in ancillary.messages() {
     ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
     ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
+    ///                 println!("receive file descriptor: {fd}");
     ///             }
     ///         }
     ///     }
@@ -893,7 +893,7 @@ pub fn passcred(&self) -> io::Result<bool> {
     /// fn main() -> std::io::Result<()> {
     ///     let sock = UnixDatagram::unbound()?;
     ///     if let Ok(Some(err)) = sock.take_error() {
-    ///         println!("Got error: {:?}", err);
+    ///         println!("Got error: {err:?}");
     ///     }
     ///     Ok(())
     /// }
index b23dd6062f6822fce6576454ee8ec4ca0e33aaf3..8e11d32f13071dfb58ef3d91f1a734c0851cf4fb 100644 (file)
@@ -63,7 +63,7 @@ impl UnixListener {
     /// let listener = match UnixListener::bind("/path/to/the/socket") {
     ///     Ok(sock) => sock,
     ///     Err(e) => {
-    ///         println!("Couldn't connect: {:?}", e);
+    ///         println!("Couldn't connect: {e:?}");
     ///         return
     ///     }
     /// };
@@ -98,7 +98,7 @@ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
     ///     let listener2 = match UnixListener::bind_addr(&addr) {
     ///         Ok(sock) => sock,
     ///         Err(err) => {
-    ///             println!("Couldn't bind: {:?}", err);
+    ///             println!("Couldn't bind: {err:?}");
     ///             return Err(err);
     ///         }
     ///     };
@@ -136,8 +136,8 @@ pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixListener> {
     ///     let listener = UnixListener::bind("/path/to/the/socket")?;
     ///
     ///     match listener.accept() {
-    ///         Ok((socket, addr)) => println!("Got a client: {:?}", addr),
-    ///         Err(e) => println!("accept function failed: {:?}", e),
+    ///         Ok((socket, addr)) => println!("Got a client: {addr:?}"),
+    ///         Err(e) => println!("accept function failed: {e:?}"),
     ///     }
     ///     Ok(())
     /// }
@@ -226,7 +226,7 @@ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
     ///     let listener = UnixListener::bind("/tmp/sock")?;
     ///
     ///     if let Ok(Some(err)) = listener.take_error() {
-    ///         println!("Got error: {:?}", err);
+    ///         println!("Got error: {err:?}");
     ///     }
     ///     Ok(())
     /// }
index 583f861a92535c809946c664a10403c64a63edc4..3943b4fed0949c6803f8467678d37a68192dd62e 100644 (file)
@@ -57,7 +57,7 @@
 ///     stream.write_all(b"hello world")?;
 ///     let mut response = String::new();
 ///     stream.read_to_string(&mut response)?;
-///     println!("{}", response);
+///     println!("{response}");
 ///     Ok(())
 /// }
 /// ```
@@ -90,7 +90,7 @@ impl UnixStream {
     /// let socket = match UnixStream::connect("/tmp/sock") {
     ///     Ok(sock) => sock,
     ///     Err(e) => {
-    ///         println!("Couldn't connect: {:?}", e);
+    ///         println!("Couldn't connect: {e:?}");
     ///         return
     ///     }
     /// };
@@ -123,7 +123,7 @@ pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
     ///     let sock = match UnixStream::connect_addr(&addr) {
     ///         Ok(sock) => sock,
     ///         Err(e) => {
-    ///             println!("Couldn't connect: {:?}", e);
+    ///             println!("Couldn't connect: {e:?}");
     ///             return Err(e)
     ///         }
     ///     };
@@ -155,7 +155,7 @@ pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result<UnixStream> {
     /// let (sock1, sock2) = match UnixStream::pair() {
     ///     Ok((sock1, sock2)) => (sock1, sock2),
     ///     Err(e) => {
-    ///         println!("Couldn't create a pair of sockets: {:?}", e);
+    ///         println!("Couldn't create a pair of sockets: {e:?}");
     ///         return
     ///     }
     /// };
@@ -443,7 +443,7 @@ pub fn passcred(&self) -> io::Result<bool> {
     /// fn main() -> std::io::Result<()> {
     ///     let socket = UnixStream::connect("/tmp/sock")?;
     ///     if let Ok(Some(err)) = socket.take_error() {
-    ///         println!("Got error: {:?}", err);
+    ///         println!("Got error: {err:?}");
     ///     }
     ///     Ok(())
     /// }
@@ -530,11 +530,11 @@ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
     ///     let mut ancillary_buffer = [0; 128];
     ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
     ///     let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
-    ///     println!("received {}", size);
+    ///     println!("received {size}");
     ///     for ancillary_result in ancillary.messages() {
     ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
     ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
+    ///                 println!("receive file descriptor: {fd}");
     ///             }
     ///         }
     ///     }
index 7ad4a02611e0726a05f889affb57cbd2230ee5e6..aa0df61c1920d628c6e8f3963c936ef488fb0147 100644 (file)
@@ -29,7 +29,7 @@ macro_rules! or_panic {
     ($e:expr) => {
         match $e {
             Ok(e) => e,
-            Err(e) => panic!("{}", e),
+            Err(e) => panic!("{e}"),
         }
     };
 }
@@ -161,19 +161,19 @@ fn long_path() {
     );
     match UnixStream::connect(&socket_path) {
         Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
-        Err(e) => panic!("unexpected error {}", e),
+        Err(e) => panic!("unexpected error {e}"),
         Ok(_) => panic!("unexpected success"),
     }
 
     match UnixListener::bind(&socket_path) {
         Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
-        Err(e) => panic!("unexpected error {}", e),
+        Err(e) => panic!("unexpected error {e}"),
         Ok(_) => panic!("unexpected success"),
     }
 
     match UnixDatagram::bind(&socket_path) {
         Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
-        Err(e) => panic!("unexpected error {}", e),
+        Err(e) => panic!("unexpected error {e}"),
         Ok(_) => panic!("unexpected success"),
     }
 }
@@ -524,7 +524,7 @@ fn test_abstract_namespace_too_long() {
         jklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
     ) {
         Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
-        Err(e) => panic!("unexpected error {}", e),
+        Err(e) => panic!("unexpected error {e}"),
         Ok(_) => panic!("unexpected success"),
     }
 }
@@ -564,7 +564,7 @@ fn test_unix_stream_peek() {
     match stream.peek(&mut buf) {
         Ok(_) => panic!("expected error"),
         Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
-        Err(e) => panic!("unexpected error: {}", e),
+        Err(e) => panic!("unexpected error: {e}"),
     }
 
     or_panic!(txdone.send(()));
index 2b9ae3210de250ed5d567ab4378c4c615d351a53..03de7eed6d4c8868b014ee87337a68a43a89d8a8 100644 (file)
@@ -283,7 +283,7 @@ fn default_hook(info: &PanicInfo<'_>) {
     let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
 
     let write = |err: &mut dyn crate::io::Write| {
-        let _ = writeln!(err, "thread '{}' panicked at '{}', {}", name, msg, location);
+        let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
 
         static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
 
@@ -677,7 +677,7 @@ fn rust_panic_with_hook(
             // Unfortunately, this does not print a backtrace, because creating
             // a `Backtrace` will allocate, which we must to avoid here.
             let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
-            rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo);
+            rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n");
         }
         crate::sys::abort_internal();
     }
@@ -745,5 +745,5 @@ fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! {
         let obj = &mut msg as *mut &mut dyn BoxMeUp;
         __rust_start_panic(obj)
     };
-    rtabort!("failed to initiate panic, error {}", code)
+    rtabort!("failed to initiate panic, error {code}")
 }
index e544608f83c299c9ad3f2262b2ffc50062a48298..bcf5c9328b79c6d73c951aa8959c06f1e870ca2b 100644 (file)
@@ -592,7 +592,7 @@ fn as_ref(&self) -> &Path {
 /// let path = Path::new("/tmp/foo/bar.txt");
 ///
 /// for component in path.components() {
-///     println!("{:?}", component);
+///     println!("{component:?}");
 /// }
 /// ```
 ///
index 6e863787b7f39bf1515c4217037acd43febff119..c8dc768d3fc8eca8bfcadc7ae9496d30ab0d25ee 100644 (file)
@@ -1586,17 +1586,17 @@ fn test_components_debug() {
     let mut components = path.components();
 
     let expected = "Components([RootDir, Normal(\"tmp\")])";
-    let actual = format!("{:?}", components);
+    let actual = format!("{components:?}");
     assert_eq!(expected, actual);
 
     let _ = components.next().unwrap();
     let expected = "Components([Normal(\"tmp\")])";
-    let actual = format!("{:?}", components);
+    let actual = format!("{components:?}");
     assert_eq!(expected, actual);
 
     let _ = components.next().unwrap();
     let expected = "Components([])";
-    let actual = format!("{:?}", components);
+    let actual = format!("{components:?}");
     assert_eq!(expected, actual);
 }
 
@@ -1608,17 +1608,17 @@ fn test_iter_debug() {
     let mut iter = path.iter();
 
     let expected = "Iter([\"/\", \"tmp\"])";
-    let actual = format!("{:?}", iter);
+    let actual = format!("{iter:?}");
     assert_eq!(expected, actual);
 
     let _ = iter.next().unwrap();
     let expected = "Iter([\"tmp\"])";
-    let actual = format!("{:?}", iter);
+    let actual = format!("{iter:?}");
     assert_eq!(expected, actual);
 
     let _ = iter.next().unwrap();
     let expected = "Iter([])";
-    let actual = format!("{:?}", iter);
+    let actual = format!("{iter:?}");
     assert_eq!(expected, actual);
 }
 
@@ -1770,7 +1770,7 @@ macro_rules! unchanged(
 fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
     let prefix = "my/home";
     let mut paths: Vec<_> =
-        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
 
     paths.sort();
 
@@ -1783,7 +1783,7 @@ fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
 fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
     let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
     let paths: Vec<_> =
-        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
 
     let mut set = BTreeSet::new();
 
@@ -1801,7 +1801,7 @@ fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
 fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
     let prefix = "my/home";
     let paths: Vec<_> =
-        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
 
     let mut set = BTreeSet::new();
 
@@ -1819,7 +1819,7 @@ fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
 fn bench_path_hashset(b: &mut test::Bencher) {
     let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
     let paths: Vec<_> =
-        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
 
     let mut set = HashSet::new();
 
@@ -1837,7 +1837,7 @@ fn bench_path_hashset(b: &mut test::Bencher) {
 fn bench_path_hashset_miss(b: &mut test::Bencher) {
     let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
     let paths: Vec<_> =
-        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect();
 
     let mut set = HashSet::new();
 
index ebb1d8971b99ddd63cf89315cea88df043983ebd..225a679efd22132ced410bf29008fbd7e3212ee0 100644 (file)
@@ -607,7 +607,7 @@ mod prim_pointer {}
 ///
 /// // This loop prints: 0 1 2
 /// for x in array {
-///     print!("{} ", x);
+///     print!("{x} ");
 /// }
 /// ```
 ///
@@ -646,19 +646,19 @@ mod prim_pointer {}
 /// // This creates a slice iterator, producing references to each value.
 /// for item in array.into_iter().enumerate() {
 ///     let (i, x): (usize, &i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 ///
 /// // The `array_into_iter` lint suggests this change for future compatibility:
 /// for item in array.iter().enumerate() {
 ///     let (i, x): (usize, &i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 ///
 /// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
 /// for item in IntoIterator::into_iter(array).enumerate() {
 ///     let (i, x): (usize, i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 /// ```
 ///
@@ -673,13 +673,13 @@ mod prim_pointer {}
 /// // This iterates by reference:
 /// for item in array.iter().enumerate() {
 ///     let (i, x): (usize, &i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 ///
 /// // This iterates by value:
 /// for item in array.into_iter().enumerate() {
 ///     let (i, x): (usize, i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 /// ```
 ///
@@ -702,26 +702,26 @@ mod prim_pointer {}
 /// // This iterates by reference:
 /// for item in array.iter() {
 ///     let x: &i32 = item;
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // This iterates by value:
 /// for item in IntoIterator::into_iter(array) {
 ///     let x: i32 = item;
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // This iterates by value:
 /// for item in array {
 ///     let x: i32 = item;
-///     println!("{}", x);
+///     println!("{x}");
 /// }
 ///
 /// // IntoIter can also start a chain.
 /// // This iterates by value:
 /// for item in IntoIterator::into_iter(array).enumerate() {
 ///     let (i, x): (usize, i32) = item;
-///     println!("array[{}] = {}", i, x);
+///     println!("array[{i}] = {x}");
 /// }
 /// ```
 ///
index e3fff155e47224b6728fa5c355d4de98ca9acbe1..d88ab6253712abb2f13d74c50d38808268d4e374 100644 (file)
@@ -915,7 +915,7 @@ pub fn output(&mut self) -> io::Result<Output> {
     ///                      .status()
     ///                      .expect("failed to execute process");
     ///
-    /// println!("process finished with: {}", status);
+    /// println!("process finished with: {status}");
     ///
     /// assert!(status.success());
     /// ```
@@ -1434,7 +1434,7 @@ impl ExitStatus {
     ///                      .status()
     ///                      .expect("ls could not be executed");
     ///
-    /// println!("ls: {}", status);
+    /// println!("ls: {status}");
     /// status.exit_ok().expect_err("/dev/nonexistent could be listed!");
     /// # } // cfg!(unix)
     /// ```
@@ -1459,7 +1459,7 @@ pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
     /// if status.success() {
     ///     println!("'projects/' directory created");
     /// } else {
-    ///     println!("failed to create 'projects/' directory: {}", status);
+    ///     println!("failed to create 'projects/' directory: {status}");
     /// }
     /// ```
     #[must_use]
@@ -1490,7 +1490,7 @@ pub fn success(&self) -> bool {
     ///                      .expect("failed to execute mkdir");
     ///
     /// match status.code() {
-    ///     Some(code) => println!("Exited with status code: {}", code),
+    ///     Some(code) => println!("Exited with status code: {code}"),
     ///     None       => println!("Process terminated by signal")
     /// }
     /// ```
@@ -1806,13 +1806,13 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
     /// let mut child = Command::new("ls").spawn().unwrap();
     ///
     /// match child.try_wait() {
-    ///     Ok(Some(status)) => println!("exited with: {}", status),
+    ///     Ok(Some(status)) => println!("exited with: {status}"),
     ///     Ok(None) => {
     ///         println!("status not ready yet, let's really wait");
     ///         let res = child.wait();
-    ///         println!("result: {:?}", res);
+    ///         println!("result: {res:?}");
     ///     }
-    ///     Err(e) => println!("error attempting to wait: {}", e),
+    ///     Err(e) => println!("error attempting to wait: {e}"),
     /// }
     /// ```
     #[stable(feature = "process_try_wait", since = "1.18.0")]
@@ -1912,7 +1912,7 @@ pub fn wait_with_output(mut self) -> io::Result<Output> {
 ///     std::process::exit(match run_app() {
 ///         Ok(_) => 0,
 ///         Err(err) => {
-///             eprintln!("error: {:?}", err);
+///             eprintln!("error: {err:?}");
 ///             1
 ///         }
 ///     });
@@ -2071,7 +2071,7 @@ fn report(self) -> ExitCode {
 impl<E: fmt::Debug> Termination for Result<!, E> {
     fn report(self) -> ExitCode {
         let Err(err) = self;
-        eprintln!("Error: {:?}", err);
+        eprintln!("Error: {err:?}");
         ExitCode::FAILURE.report()
     }
 }
index e5cdc4737068a4a06a642657a11ee1b9d11d94ef..4f779ab4e786c65788a1e51e6c2f8a7c3ae67361 100644 (file)
@@ -64,7 +64,7 @@ fn signal_reported_right() {
     p.kill().unwrap();
     match p.wait().unwrap().signal() {
         Some(9) => {}
-        result => panic!("not terminated by signal 9 (instead, {:?})", result),
+        result => panic!("not terminated by signal 9 (instead, {result:?})"),
     }
 }
 
@@ -252,8 +252,7 @@ fn test_override_env() {
 
     assert!(
         output.contains("RUN_TEST_NEW_ENV=123"),
-        "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
-        output
+        "didn't find RUN_TEST_NEW_ENV inside of:\n\n{output}",
     );
 }
 
@@ -265,8 +264,7 @@ fn test_add_to_env() {
 
     assert!(
         output.contains("RUN_TEST_NEW_ENV=123"),
-        "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}",
-        output
+        "didn't find RUN_TEST_NEW_ENV inside of:\n\n{output}"
     );
 }
 
@@ -288,13 +286,11 @@ fn test_capture_env_at_spawn() {
 
     assert!(
         output.contains("RUN_TEST_NEW_ENV1=123"),
-        "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}",
-        output
+        "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{output}"
     );
     assert!(
         output.contains("RUN_TEST_NEW_ENV2=456"),
-        "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}",
-        output
+        "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{output}"
     );
 }
 
index ee35598bab5fe1fb99b38155d4e770ffedf9a3bc..87d01daeafc4cc18e5427a82d900c9261ae0e2d1 100644 (file)
@@ -19,7 +19,7 @@
 //!         B = 4;
 //!         A = A + B;
 //!         C = B;
-//!         println!("{} {} {}", A, B, C);
+//!         println!("{A} {B} {C}");
 //!         C = A;
 //!     }
 //! }
index 2e54321e127c0e3e882e048d3689c82774d08cbd..e85a87239651884e56c3deac672876cef1f362be 100644 (file)
 //!
 //! // Unbounded receiver waiting for all senders to complete.
 //! while let Ok(msg) = rx.recv() {
-//!     println!("{}", msg);
+//!     println!("{msg}");
 //! }
 //!
 //! println!("completed");
@@ -376,7 +376,7 @@ impl<T> !Sync for Receiver<T> {}
 /// });
 ///
 /// for x in recv.iter() {
-///     println!("Got: {}", x);
+///     println!("Got: {x}");
 /// }
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -419,7 +419,7 @@ pub struct Iter<'a, T: 'a> {
 /// thread::sleep(Duration::from_secs(2)); // block for two seconds
 ///
 /// for x in receiver.try_iter() {
-///     println!("Got: {}", x);
+///     println!("Got: {x}");
 /// }
 /// ```
 #[stable(feature = "receiver_try_iter", since = "1.15.0")]
@@ -453,7 +453,7 @@ pub struct TryIter<'a, T: 'a> {
 /// });
 ///
 /// for x in recv.into_iter() {
-///     println!("Got: {}", x);
+///     println!("Got: {x}");
 /// }
 /// ```
 #[stable(feature = "receiver_into_iter", since = "1.1.0")]
@@ -544,16 +544,16 @@ impl<T> !Sync for Sender<T> {}
 /// let mut msg;
 ///
 /// msg = receiver.recv().unwrap();
-/// println!("message {} received", msg);
+/// println!("message {msg} received");
 ///
 /// // "Thread unblocked!" will be printed now
 ///
 /// msg = receiver.recv().unwrap();
-/// println!("message {} received", msg);
+/// println!("message {msg} received");
 ///
 /// msg = receiver.recv().unwrap();
 ///
-/// println!("message {} received", msg);
+/// println!("message {msg} received");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SyncSender<T> {
@@ -996,14 +996,14 @@ pub fn send(&self, t: T) -> Result<(), SendError<T>> {
     ///
     /// let mut msg;
     /// msg = receiver.recv().unwrap();
-    /// println!("message {} received", msg);
+    /// println!("message {msg} received");
     ///
     /// msg = receiver.recv().unwrap();
-    /// println!("message {} received", msg);
+    /// println!("message {msg} received");
     ///
     /// // Third message may have never been sent
     /// match receiver.try_recv() {
-    ///     Ok(msg) => println!("message {} received", msg),
+    ///     Ok(msg) => println!("message {msg} received"),
     ///     Err(_) => println!("the third message was never sent"),
     /// }
     /// ```
index 8487a5f8b50d3215790285d4841ac2ec1021afc4..561626555441045ac7129266a43ce3c6e38b4cbb 100644 (file)
@@ -369,7 +369,7 @@ pub fn drop_chan(&self) {
         match self.channels.fetch_sub(1, Ordering::SeqCst) {
             1 => {}
             n if n > 1 => return,
-            n => panic!("bad number of channels left {}", n),
+            n => panic!("bad number of channels left {n}"),
         }
 
         match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) {
index a1b5aeddcb66a7740fb2c0e9e20dd9f47a45940c..93900566f1194371e5ae34cbcc343389b42095b9 100644 (file)
@@ -94,7 +94,7 @@ fn test_into_inner_poison() {
     assert!(m.is_poisoned());
     match Arc::try_unwrap(m).unwrap().into_inner() {
         Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
-        Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x),
+        Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {x:?}"),
     }
 }
 
@@ -118,7 +118,7 @@ fn test_get_mut_poison() {
     assert!(m.is_poisoned());
     match Arc::try_unwrap(m).unwrap().get_mut() {
         Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
-        Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x),
+        Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {x:?}"),
     }
 }
 
index fa950331e644af8bec01870381864bf667cea67e..07a90da449c9d17ff23763545aadbce02151e4aa 100644 (file)
@@ -73,7 +73,7 @@ pub struct Guard {
 ///     Ok(_) => unreachable!(),
 ///     Err(p_err) => {
 ///         let data = p_err.get_ref();
-///         println!("recovered: {}", data);
+///         println!("recovered: {data}");
 ///     }
 /// };
 /// ```
index e9b74fb3ecc866dd0f50c94fdf38b242a517d4e5..53aa2b1e38a91cbd8b8b93c891bcb1d04ab8e6a7 100644 (file)
@@ -218,7 +218,7 @@ fn test_into_inner_poison() {
     assert!(m.is_poisoned());
     match Arc::try_unwrap(m).unwrap().into_inner() {
         Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
-        Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x),
+        Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {x:?}"),
     }
 }
 
@@ -242,6 +242,6 @@ fn test_get_mut_poison() {
     assert!(m.is_poisoned());
     match Arc::try_unwrap(m).unwrap().get_mut() {
         Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
-        Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x),
+        Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {x:?}"),
     }
 }
index 5df08a4ff593ce3e42b56d8a28e116185775c161..9508c38741551c8a975c89e87aea20eb0b5d1520 100644 (file)
@@ -95,7 +95,7 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64
 pub(super) fn exit_with_code(code: isize) -> ! {
     if code != 0 {
         if let Some(mut out) = panic::SgxPanicOutput::new() {
-            let _ = write!(out, "Exited with status code {}", code);
+            let _ = write!(out, "Exited with status code {code}");
         }
     }
     usercalls::exit(code != 0);
index a6a659df291fc5b4b26d78ba813743392360ee00..4030355f13518fb7f56a33487f983f1d35138f31 100644 (file)
@@ -83,7 +83,7 @@ pub fn close(fd: Fd) {
 
 fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
     String::from_utf8(buf.copy_user_buffer())
-        .unwrap_or_else(|_| rtabort!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
+        .unwrap_or_else(|_| rtabort!("Usercall {usercall}: expected {arg} to be valid UTF-8"))
 }
 
 /// Usercall `bind_stream`. See the ABI documentation for more information.
@@ -287,7 +287,7 @@ fn check_os_error(err: Result) -> i32 {
     {
         err
     } else {
-        rtabort!("Usercall: returned invalid error value {}", err)
+        rtabort!("Usercall: returned invalid error value {err}")
     }
 }
 
index b0e6a6aaed7b9c4b1cb9279bb3d2817443f10af3..4267b96ccd504474fc049c73aa80aff9aa511211 100644 (file)
@@ -132,7 +132,7 @@ fn into_register(self) -> Register {
 
 impl ReturnValue for ! {
     fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self {
-        rtabort!("Usercall {}: did not expect to be re-entered", call);
+        rtabort!("Usercall {call}: did not expect to be re-entered");
     }
 }
 
index d14990c6877af6384dfc4385d2bd2c4702523109..feb0b62dcd1f71ec1d3a56d3942df075b508d065 100644 (file)
@@ -501,7 +501,7 @@ impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
     type Error = io::Error;
 
     fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
-        LookupHost::new(format!("{}:{}", host, port))
+        LookupHost::new(format!("{host}:{port}"))
     }
 }
 
index 5f8b8def7c6709522f54bbc7b6b03f9c2bd33e38..5da0257f35de5cfd46a656c1f6815bf1d48f2c14 100644 (file)
@@ -22,7 +22,7 @@ pub fn error_string(errno: i32) -> String {
     if errno == RESULT_SUCCESS {
         "operation successful".into()
     } else if ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&errno) {
-        format!("user-specified error {:08x}", errno)
+        format!("user-specified error {errno:08x}")
     } else {
         decode_error_kind(errno).as_str().into()
     }
index 8ccf043b5b57f00cbb64df58a6ac85833e5e2230..2e680e740fde3a48a632232e914f28985d50198b 100644 (file)
@@ -83,6 +83,6 @@ pub fn panic_output() -> Option<impl io::Write> {
     }
     let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) };
     if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
-        eprint!("{}", s);
+        eprint!("{s}");
     }
 }
index 2082c9401535e8d1f4dd67a535f03eda626286bf..049460755d65ad8fefaeccc7140f74968f78a738 100644 (file)
@@ -87,7 +87,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
     unsafe {
         let mut out = crate::mem::MaybeUninit::<[u64; 2]>::uninit();
         let result = abi::SOLID_RNG_SampleRandomBytes(out.as_mut_ptr() as *mut u8, 16);
-        assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {}", result);
+        assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {result}");
         let [x1, x2] = out.assume_init();
         (x1, x2)
     }
index a43407bd0f8652a767cef42a221a33c83d26fd13..faeda5a854d9f3981a0f1bd85272db8d89c10057 100644 (file)
@@ -157,7 +157,7 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> {
         };
         Err(io::Error::new(
             io::ErrorKind::Uncategorized,
-            &format!("failed to lookup address information: {}", msg)[..],
+            &format!("failed to lookup address information: {msg}")[..],
         ))
     }
 }
index 22239e1fa8ebc1944be2e0ae43e8f13b92b90a34..127cca3accad9d341ca0518758e16b4f1d1bd466 100644 (file)
@@ -26,7 +26,7 @@ pub fn errno() -> i32 {
 }
 
 pub fn error_string(errno: i32) -> String {
-    if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{}", errno) }
+    if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{errno}") }
 }
 
 pub fn getcwd() -> io::Result<PathBuf> {
index 0851f512fd01b6644b1e3e98e960c9003a4a8948..a3e6b081936b67bb6f824b85b401edf3cf896c91 100644 (file)
@@ -228,23 +228,54 @@ pub struct ReadDir {
 unsafe impl Send for Dir {}
 unsafe impl Sync for Dir {}
 
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "fuchsia",
+    target_os = "redox"
+))]
 pub struct DirEntry {
-    entry: dirent64,
     dir: Arc<InnerReadDir>,
+    entry: dirent64_min,
     // We need to store an owned copy of the entry name on platforms that use
     // readdir() (not readdir_r()), because a) struct dirent may use a flexible
     // array to store the name, b) it lives only until the next readdir() call.
-    #[cfg(any(
-        target_os = "android",
-        target_os = "linux",
-        target_os = "solaris",
-        target_os = "illumos",
-        target_os = "fuchsia",
-        target_os = "redox"
-    ))]
     name: CString,
 }
 
+// Define a minimal subset of fields we need from `dirent64`, especially since
+// we're not using the immediate `d_name` on these targets. Keeping this as an
+// `entry` field in `DirEntry` helps reduce the `cfg` boilerplate elsewhere.
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "fuchsia",
+    target_os = "redox"
+))]
+struct dirent64_min {
+    d_ino: u64,
+    #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+    d_type: u8,
+}
+
+#[cfg(not(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "fuchsia",
+    target_os = "redox"
+)))]
+pub struct DirEntry {
+    dir: Arc<InnerReadDir>,
+    // The full entry includes a fixed-length `d_name`.
+    entry: dirent64,
+}
+
 #[derive(Clone, Debug)]
 pub struct OpenOptions {
     // generic
@@ -491,11 +522,21 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
 
                 // Only d_reclen bytes of *entry_ptr are valid, so we can't just copy the
                 // whole thing (#93384).  Instead, copy everything except the name.
+                let mut copy: dirent64 = mem::zeroed();
+                // Can't dereference entry_ptr, so use the local entry to get
+                // offsetof(struct dirent, d_name)
+                let copy_bytes = &mut copy as *mut _ as *mut u8;
+                let copy_name = &mut copy.d_name as *mut _ as *mut u8;
+                let name_offset = copy_name.offset_from(copy_bytes) as usize;
                 let entry_bytes = entry_ptr as *const u8;
-                let entry_name = ptr::addr_of!((*entry_ptr).d_name) as *const u8;
-                let name_offset = entry_name.offset_from(entry_bytes) as usize;
-                let mut entry: dirent64 = mem::zeroed();
-                ptr::copy_nonoverlapping(entry_bytes, &mut entry as *mut _ as *mut u8, name_offset);
+                let entry_name = entry_bytes.add(name_offset);
+                ptr::copy_nonoverlapping(entry_bytes, copy_bytes, name_offset);
+
+                let entry = dirent64_min {
+                    d_ino: copy.d_ino as u64,
+                    #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+                    d_type: copy.d_type as u8,
+                };
 
                 let ret = DirEntry {
                     entry,
@@ -1600,17 +1641,15 @@ fn is_dir(ent: &DirEntry) -> Option<bool> {
         }
     }
 
-    fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()> {
-        let pcstr = cstr(p)?;
-
+    fn remove_dir_all_recursive(parent_fd: Option<RawFd>, path: &CStr) -> io::Result<()> {
         // try opening as directory
-        let fd = match openat_nofollow_dironly(parent_fd, &pcstr) {
+        let fd = match openat_nofollow_dironly(parent_fd, &path) {
             Err(err) if err.raw_os_error() == Some(libc::ENOTDIR) => {
                 // not a directory - don't traverse further
                 return match parent_fd {
                     // unlink...
                     Some(parent_fd) => {
-                        cvt(unsafe { unlinkat(parent_fd, pcstr.as_ptr(), 0) }).map(drop)
+                        cvt(unsafe { unlinkat(parent_fd, path.as_ptr(), 0) }).map(drop)
                     }
                     // ...unless this was supposed to be the deletion root directory
                     None => Err(err),
@@ -1623,26 +1662,27 @@ fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()
         let (dir, fd) = fdreaddir(fd)?;
         for child in dir {
             let child = child?;
+            let child_name = child.name_cstr();
             match is_dir(&child) {
                 Some(true) => {
-                    remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+                    remove_dir_all_recursive(Some(fd), child_name)?;
                 }
                 Some(false) => {
-                    cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) })?;
+                    cvt(unsafe { unlinkat(fd, child_name.as_ptr(), 0) })?;
                 }
                 None => {
                     // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed
                     // if the process has the appropriate privileges. This however can causing orphaned
                     // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing
                     // into it first instead of trying to unlink() it.
-                    remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+                    remove_dir_all_recursive(Some(fd), child_name)?;
                 }
             }
         }
 
         // unlink the directory after removing its contents
         cvt(unsafe {
-            unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), pcstr.as_ptr(), libc::AT_REMOVEDIR)
+            unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), path.as_ptr(), libc::AT_REMOVEDIR)
         })?;
         Ok(())
     }
@@ -1655,7 +1695,7 @@ fn remove_dir_all_modern(p: &Path) -> io::Result<()> {
         if attr.file_type().is_symlink() {
             crate::fs::remove_file(p)
         } else {
-            remove_dir_all_recursive(None, p)
+            remove_dir_all_recursive(None, &cstr(p)?)
         }
     }
 
index 61c15ecd85de3ce0a80355126d86fa899671cdb3..e6fd9a0c827e2302957837b5a3311634be1a4472 100644 (file)
@@ -54,7 +54,7 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> {
 
     Err(io::Error::new(
         io::ErrorKind::Uncategorized,
-        &format!("failed to lookup address information: {}", detail)[..],
+        &format!("failed to lookup address information: {detail}")[..],
     ))
 }
 
index 379673781557389d37828b7431b05a080a12a954..213277f01f2a6bec51d8302b965c7277e5675c8f 100644 (file)
@@ -4,7 +4,7 @@
 fn slice_debug_output() {
     let input = Slice::from_u8_slice(b"\xF0hello,\tworld");
     let expected = r#""\xF0hello,\tworld""#;
-    let output = format!("{:?}", input);
+    let output = format!("{input:?}");
 
     assert_eq!(output, expected);
 }
index 09bfd9680f5b2c50841d9ee9b9267c1a62e6e7a7..e3347ab12a7309e8bca82bd9a6b67a197cf5cda6 100644 (file)
@@ -211,7 +211,7 @@ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
                     return Ok(None);
                 }
                 _ => {
-                    panic!("Failed to wait on process handle: {}", status);
+                    panic!("Failed to wait on process handle: {status}");
                 }
             }
             zx_cvt(zx_object_get_info(
index 07a0339c066bc9b23207be9d50e9bc4a73ba9dd2..9c477e5addc44a167e5ccbfcbd99865775f05cc8 100644 (file)
@@ -120,7 +120,7 @@ pub fn spawn(
                 Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
                 Err(e) => {
                     assert!(p.wait().is_ok(), "wait() should either return Ok or panic");
-                    panic!("the CLOEXEC pipe failed: {:?}", e)
+                    panic!("the CLOEXEC pipe failed: {e:?}")
                 }
                 Ok(..) => {
                     // pipe I/O up to PIPE_BUF bytes should be atomic
@@ -682,15 +682,15 @@ fn from(a: c_int) -> ExitStatus {
 impl fmt::Display for ExitStatus {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if let Some(code) = self.code() {
-            write!(f, "exit status: {}", code)
+            write!(f, "exit status: {code}")
         } else if let Some(signal) = self.signal() {
             if self.core_dumped() {
-                write!(f, "signal: {} (core dumped)", signal)
+                write!(f, "signal: {signal} (core dumped)")
             } else {
-                write!(f, "signal: {}", signal)
+                write!(f, "signal: {signal}")
             }
         } else if let Some(signal) = self.stopped_signal() {
-            write!(f, "stopped (not terminated) by signal: {}", signal)
+            write!(f, "stopped (not terminated) by signal: {signal}")
         } else if self.continued() {
             write!(f, "continued (WIFCONTINUED)")
         } else {
index 56ed6cfeb6a6b891101b10cdf3677ded11257b64..016bc20ec0a47dcbd13c8f30612bfef338dcc8ea 100644 (file)
@@ -239,10 +239,10 @@ fn from(a: c_int) -> ExitStatus {
 impl fmt::Display for ExitStatus {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if let Some(code) = self.code() {
-            write!(f, "exit code: {}", code)
+            write!(f, "exit code: {code}")
         } else {
             let signal = self.signal().unwrap();
-            write!(f, "signal: {}", signal)
+            write!(f, "signal: {signal}")
         }
     }
 }
index 7a3f6b0d95a09aace1cdba7529287315eeb6655a..17e8efbe097ce52c15a5296d108f4ef45b8b7dc1 100644 (file)
@@ -82,7 +82,7 @@ fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
                 } else if err == libc::EAGAIN {
                     return false;
                 } else {
-                    panic!("unexpected getrandom error: {}", err);
+                    panic!("unexpected getrandom error: {err}");
                 }
             } else {
                 read += result as usize;
index b1faf12c2261452e1b191c8a91f3b2810ae0a3ff..1318c5b8e3a6104d98607672b91339d62e223924 100644 (file)
@@ -48,9 +48,9 @@ pub unsafe fn read(&self) {
             }
             panic!("rwlock read lock would result in deadlock");
         } else {
-            // According to POSIX, for a properly initialized rwlock this can only
-            // return EAGAIN or EDEADLK or 0. We rely on that.
-            debug_assert_eq!(r, 0);
+            // POSIX does not make guarantees about all the errors that may be returned.
+            // See issue #94705 for more details.
+            assert_eq!(r, 0, "unexpected error during rwlock read lock: {:?}", r);
             self.num_readers.fetch_add(1, Ordering::Relaxed);
         }
     }
index dc288176346bcb4dfe4413836e031478060b6f30..6097e628768479b44c86b31d45d047cc390c8be2 100644 (file)
@@ -224,8 +224,14 @@ fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T>
             } as usize;
             if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
                 n *= 2;
-            } else if k >= n {
+            } else if k > n {
                 n = k;
+            } else if k == n {
+                // It is impossible to reach this point.
+                // On success, k is the returned string length excluding the null.
+                // On failure, k is the required buffer length including the null.
+                // Therefore k never equals n.
+                unreachable!();
             } else {
                 return Ok(f2(&buf[..k]));
             }
index 5f8556c3bc37618a1fef44596aaa0d6dc7f6496c..450bceae0008125d5142a5e2ecfdca52e94ad26f 100644 (file)
@@ -64,7 +64,7 @@ pub fn error_string(mut errnum: i32) -> String {
         if res == 0 {
             // Sometimes FormatMessageW can fail e.g., system doesn't like langId,
             let fm_err = errno();
-            return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
+            return format!("OS Error {errnum} (FormatMessageW() returned error {fm_err})");
         }
 
         match String::from_utf16(&buf[..res]) {
index d18c3d855bcce0e5ae1ccec17380cbbd9bd3995e..d8c9beb0c19750249d3c36c55b89798a7125bf68 100644 (file)
@@ -121,9 +121,7 @@ fn windows_env_unicode_case() {
             assert_eq!(
                 env::var(key).ok(),
                 value.map(|s| s.to_string_lossy().into_owned()),
-                "command environment mismatch: {} {}",
-                a,
-                b
+                "command environment mismatch: {a} {b}",
             );
         }
     }
index 5a8011a95880814497c589257df29f11c8c5195e..5888ee8e34bfb386d076e37004d52eb3e3f9d9f9 100644 (file)
@@ -230,7 +230,7 @@ fn keyed_event_handle() -> c::HANDLE {
                     0,
                 ) {
                     c::STATUS_SUCCESS => {}
-                    r => panic!("Unable to create keyed event handle: error {}", r),
+                    r => panic!("Unable to create keyed event handle: error {r}"),
                 }
             }
             match HANDLE.compare_exchange(INVALID, handle as usize, Relaxed, Relaxed) {
index b0b55592f6f3719995c531b4a0225bacf345cb20..31164afdc7b54ace44c47f57f322cdb129c89d3b 100644 (file)
@@ -174,7 +174,7 @@ pub fn output_filename(
         if let Some(cwd) = cwd {
             if let Ok(stripped) = file.strip_prefix(&cwd) {
                 if let Some(s) = stripped.to_str() {
-                    return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
+                    return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR);
                 }
             }
         }
index 7d45621e09ae470ec12b7f3785a6e34fa7f06d64..ac75d9ebfc85509f1a9b9894de8ec65a1c4c9021 100644 (file)
@@ -6,7 +6,7 @@ fn no_lookup_host_duplicates() {
     let mut addrs = HashMap::new();
     let lh = match LookupHost::try_from(("localhost", 0)) {
         Ok(lh) => lh,
-        Err(e) => panic!("couldn't resolve `localhost': {}", e),
+        Err(e) => panic!("couldn't resolve `localhost': {e}"),
     };
     for sa in lh {
         *addrs.entry(sa).or_insert(0) += 1;
index d99e901bb5f83988bb3c55e3d1c442b3edb9286b..ffb61200e15f9b523ffaa0710edef8837d424467 100644 (file)
@@ -84,7 +84,7 @@ pub unsafe fn park_timeout(&self, dur: Duration) {
         match self.state.swap(EMPTY, SeqCst) {
             NOTIFIED => {} // got a notification, hurray!
             PARKED => {}   // no notification, alas
-            n => panic!("inconsistent park_timeout state: {}", n),
+            n => panic!("inconsistent park_timeout state: {n}"),
         }
     }
 
index 7a6e6246357d1d726162237e59db7faf05a079f5..10ef6662115c1f300297b308ab832ccccc6b9b6d 100644 (file)
@@ -830,7 +830,7 @@ pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 {
 #[inline(never)]
 pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! {
     assert!(begin <= end);
-    panic!("index {} and/or {} in `{:?}` do not lie on character boundary", begin, end, s);
+    panic!("index {begin} and/or {end} in `{s:?}` do not lie on character boundary");
 }
 
 /// Iterator for the code points of a WTF-8 string.
index 1bafbaa69392222d97666bf7b0ff5973ea350543..931996791fbe55b5d2131ae9b376c9b1be780c33 100644 (file)
@@ -266,7 +266,7 @@ fn c(value: &u32) -> CodePoint {
 fn wtf8buf_show() {
     let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r");
     string.push(CodePoint::from_u32(0xD800).unwrap());
-    assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\"");
+    assert_eq!(format!("{string:?}"), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\"");
 }
 
 #[test]
@@ -278,7 +278,7 @@ fn wtf8buf_as_slice() {
 fn wtf8buf_show_str() {
     let text = "a\té 💩\r";
     let string = Wtf8Buf::from_str(text);
-    assert_eq!(format!("{:?}", text), format!("{:?}", string));
+    assert_eq!(format!("{text:?}"), format!("{string:?}"));
 }
 
 #[test]
index 5ffc86b4560fc9221a2111dfb530ed26fe1f7549..ae292caaed9945f844d5bccb77149e613c0d3aae 100644 (file)
@@ -613,7 +613,7 @@ unsafe fn spawn_unchecked_<'a, 'scope, F, T>(
 ///
 /// let receiver = thread::spawn(move || {
 ///     let value = rx.recv().expect("Unable to receive from channel");
-///     println!("{}", value);
+///     println!("{value}");
 /// });
 ///
 /// sender.join().expect("The sender thread has panicked");
@@ -633,7 +633,7 @@ unsafe fn spawn_unchecked_<'a, 'scope, F, T>(
 /// });
 ///
 /// let result = computation.join().unwrap();
-/// println!("{}", result);
+/// println!("{result}");
 /// ```
 ///
 /// [`channels`]: crate::sync::mpsc
@@ -979,7 +979,7 @@ pub fn park_timeout_ms(ms: u32) {
 ///     if elapsed >= timeout {
 ///         break;
 ///     }
-///     println!("restarting park_timeout after {:?}", elapsed);
+///     println!("restarting park_timeout after {elapsed:?}");
 ///     timeout_remaining = timeout - elapsed;
 /// }
 /// ```
@@ -1287,12 +1287,31 @@ unsafe impl<'scope, T: Sync> Sync for Packet<'scope, T> {}
 
 impl<'scope, T> Drop for Packet<'scope, T> {
     fn drop(&mut self) {
+        // If this packet was for a thread that ran in a scope, the thread
+        // panicked, and nobody consumed the panic payload, we make sure
+        // the scope function will panic.
+        let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
+        // Drop the result without causing unwinding.
+        // This is only relevant for threads that aren't join()ed, as
+        // join() will take the `result` and set it to None, such that
+        // there is nothing left to drop here.
+        // If this panics, we should handle that, because we're outside the
+        // outermost `catch_unwind` of our thread.
+        // We just abort in that case, since there's nothing else we can do.
+        // (And even if we tried to handle it somehow, we'd also need to handle
+        // the case where the panic payload we get out of it also panics on
+        // drop, and so on. See issue #86027.)
+        if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+            *self.result.get_mut() = None;
+        })) {
+            rtabort!("thread result panicked on drop");
+        }
         // Book-keeping so the scope knows when it's done.
         if let Some(scope) = self.scope {
-            // If this packet was for a thread that ran in a scope, the thread
-            // panicked, and nobody consumed the panic payload, we make sure
-            // the scope function will panic.
-            let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
+            // Now that there will be no more user code running on this thread
+            // that can use 'scope, mark the thread as 'finished'.
+            // It's important we only do this after the `result` has been dropped,
+            // since dropping it might still use things it borrowed from 'scope.
             scope.decrement_num_running_threads(unhandled_panic);
         }
     }
index ea9623be63bc7c578523fd702c8d6af8ce96f7bf..07e113f3b622299546a1912ffe7e7ba1f1580b9d 100644 (file)
@@ -9,23 +9,24 @@
 /// A scope to spawn scoped threads in.
 ///
 /// See [`scope`] for details.
-pub struct Scope<'env> {
+pub struct Scope<'scope, 'env: 'scope> {
     data: ScopeData,
-    /// Invariance over 'env, to make sure 'env cannot shrink,
+    /// Invariance over 'scope, to make sure 'scope cannot shrink,
     /// which is necessary for soundness.
     ///
     /// Without invariance, this would compile fine but be unsound:
     ///
-    /// ```compile_fail
+    /// ```compile_fail,E0373
     /// #![feature(scoped_threads)]
     ///
     /// std::thread::scope(|s| {
-    ///     s.spawn(|s| {
+    ///     s.spawn(|| {
     ///         let a = String::from("abcd");
-    ///         s.spawn(|_| println!("{:?}", a)); // might run after `a` is dropped
+    ///         s.spawn(|| println!("{a:?}")); // might run after `a` is dropped
     ///     });
     /// });
     /// ```
+    scope: PhantomData<&'scope mut &'scope ()>,
     env: PhantomData<&'env mut &'env ()>,
 }
 
@@ -88,12 +89,12 @@ pub(super) fn decrement_num_running_threads(&self, panic: bool) {
 /// let mut x = 0;
 ///
 /// thread::scope(|s| {
-///     s.spawn(|_| {
+///     s.spawn(|| {
 ///         println!("hello from the first scoped thread");
 ///         // We can borrow `a` here.
 ///         dbg!(&a);
 ///     });
-///     s.spawn(|_| {
+///     s.spawn(|| {
 ///         println!("hello from the second scoped thread");
 ///         // We can even mutably borrow `x` here,
 ///         // because no other threads are using it.
@@ -106,10 +107,28 @@ pub(super) fn decrement_num_running_threads(&self, panic: bool) {
 /// a.push(4);
 /// assert_eq!(x, a.len());
 /// ```
+///
+/// # Lifetimes
+///
+/// Scoped threads involve two lifetimes: `'scope` and `'env`.
+///
+/// The `'scope` lifetime represents the lifetime of the scope itself.
+/// That is: the time during which new scoped threads may be spawned,
+/// and also the time during which they might still be running.
+/// Once this lifetime ends, all scoped threads are joined.
+/// This lifetime starts within the `scope` function, before `f` (the argument to `scope`) starts.
+/// It ends after `f` returns and all scoped threads have been joined, but before `scope` returns.
+///
+/// The `'env` lifetime represents the lifetime of whatever is borrowed by the scoped threads.
+/// This lifetime must outlast the call to `scope`, and thus cannot be smaller than `'scope`.
+/// It can be as small as the call to `scope`, meaning that anything that outlives this call,
+/// such as local variables defined right before the scope, can be borrowed by the scoped threads.
+///
+/// The `'env: 'scope` bound is part of the definition of the `Scope` type.
 #[track_caller]
 pub fn scope<'env, F, T>(f: F) -> T
 where
-    F: FnOnce(&Scope<'env>) -> T,
+    F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T,
 {
     let scope = Scope {
         data: ScopeData {
@@ -118,6 +137,7 @@ pub fn scope<'env, F, T>(f: F) -> T
             a_thread_panicked: AtomicBool::new(false),
         },
         env: PhantomData,
+        scope: PhantomData,
     };
 
     // Run `f`, but catch panics so we can make sure to wait for all the threads to join.
@@ -138,7 +158,7 @@ pub fn scope<'env, F, T>(f: F) -> T
     }
 }
 
-impl<'env> Scope<'env> {
+impl<'scope, 'env> Scope<'scope, 'env> {
     /// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it.
     ///
     /// Unlike non-scoped threads, threads spawned with this function may
@@ -163,10 +183,10 @@ impl<'env> Scope<'env> {
     /// to recover from such errors.
     ///
     /// [`join`]: ScopedJoinHandle::join
-    pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
+    pub fn spawn<F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
     where
-        F: FnOnce(&Scope<'env>) -> T + Send + 'env,
-        T: Send + 'env,
+        F: FnOnce() -> T + Send + 'scope,
+        T: Send + 'scope,
     {
         Builder::new().spawn_scoped(self, f).expect("failed to spawn thread")
     }
@@ -196,7 +216,7 @@ impl Builder {
     /// thread::scope(|s| {
     ///     thread::Builder::new()
     ///         .name("first".to_string())
-    ///         .spawn_scoped(s, |_|
+    ///         .spawn_scoped(s, ||
     ///     {
     ///         println!("hello from the {:?} scoped thread", thread::current().name());
     ///         // We can borrow `a` here.
@@ -205,7 +225,7 @@ impl Builder {
     ///     .unwrap();
     ///     thread::Builder::new()
     ///         .name("second".to_string())
-    ///         .spawn_scoped(s, |_|
+    ///         .spawn_scoped(s, ||
     ///     {
     ///         println!("hello from the {:?} scoped thread", thread::current().name());
     ///         // We can even mutably borrow `x` here,
@@ -222,14 +242,14 @@ impl Builder {
     /// ```
     pub fn spawn_scoped<'scope, 'env, F, T>(
         self,
-        scope: &'scope Scope<'env>,
+        scope: &'scope Scope<'scope, 'env>,
         f: F,
     ) -> io::Result<ScopedJoinHandle<'scope, T>>
     where
-        F: FnOnce(&Scope<'env>) -> T + Send + 'env,
-        T: Send + 'env,
+        F: FnOnce() -> T + Send + 'scope,
+        T: Send + 'scope,
     {
-        Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(|| f(scope), Some(&scope.data)) }?))
+        Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(&scope.data)) }?))
     }
 }
 
@@ -244,7 +264,7 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> {
     /// use std::thread;
     ///
     /// thread::scope(|s| {
-    ///     let t = s.spawn(|_| {
+    ///     let t = s.spawn(|| {
     ///         println!("hello");
     ///     });
     ///     println!("thread id: {:?}", t.thread().id());
@@ -277,7 +297,7 @@ pub fn thread(&self) -> &Thread {
     /// use std::thread;
     ///
     /// thread::scope(|s| {
-    ///     let t = s.spawn(|_| {
+    ///     let t = s.spawn(|| {
     ///         panic!("oh no");
     ///     });
     ///     assert!(t.join().is_err());
@@ -302,7 +322,7 @@ pub fn is_finished(&self) -> bool {
     }
 }
 
-impl<'env> fmt::Debug for Scope<'env> {
+impl fmt::Debug for Scope<'_, '_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("Scope")
             .field("num_running_threads", &self.data.num_running_threads.load(Ordering::Relaxed))
index 3323ba36bf31091798f939babdc64cb2ae932a6b..7386fe1c442abd6a268a08b79fdc0383c76c6fb8 100644 (file)
@@ -4,10 +4,11 @@
 use crate::panic::panic_any;
 use crate::result;
 use crate::sync::{
+    atomic::{AtomicBool, Ordering},
     mpsc::{channel, Sender},
     Arc, Barrier,
 };
-use crate::thread::{self, ThreadId};
+use crate::thread::{self, Scope, ThreadId};
 use crate::time::Duration;
 use crate::time::Instant;
 
@@ -293,5 +294,25 @@ fn test_thread_id_not_equal() {
     assert!(thread::current().id() != spawned_id);
 }
 
-// NOTE: the corresponding test for stderr is in ui/thread-stderr, due
-// to the test harness apparently interfering with stderr configuration.
+#[test]
+fn test_scoped_threads_drop_result_before_join() {
+    let actually_finished = &AtomicBool::new(false);
+    struct X<'scope, 'env>(&'scope Scope<'scope, 'env>, &'env AtomicBool);
+    impl Drop for X<'_, '_> {
+        fn drop(&mut self) {
+            thread::sleep(Duration::from_millis(20));
+            let actually_finished = self.1;
+            self.0.spawn(move || {
+                thread::sleep(Duration::from_millis(20));
+                actually_finished.store(true, Ordering::Relaxed);
+            });
+        }
+    }
+    thread::scope(|s| {
+        s.spawn(move || {
+            thread::sleep(Duration::from_millis(20));
+            X(s, actually_finished)
+        });
+    });
+    assert!(actually_finished.load(Ordering::Relaxed));
+}
index df8a726e64ecb380f13bea12112dc0f03a564336..2f8eb557b4f74718c98a2bba8d8504d1a608a277 100644 (file)
 ///        }
 ///        Err(e) => {
 ///            // an error occurred!
-///            println!("Error: {:?}", e);
+///            println!("Error: {e:?}");
 ///        }
 ///    }
 /// }
@@ -513,7 +513,7 @@ pub fn now() -> SystemTime {
     /// let new_sys_time = SystemTime::now();
     /// let difference = new_sys_time.duration_since(sys_time)
     ///     .expect("Clock may have gone backwards");
-    /// println!("{:?}", difference);
+    /// println!("{difference:?}");
     /// ```
     #[stable(feature = "time2", since = "1.8.0")]
     pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> {
index d1a69ff8697c654422b31191a0b5e878fcc828fb..d710a574465ce019ef9d0006453c987ed274be12 100644 (file)
@@ -55,10 +55,10 @@ fn instant_elapsed() {
 fn instant_math() {
     let a = Instant::now();
     let b = Instant::now();
-    println!("a: {:?}", a);
-    println!("b: {:?}", b);
+    println!("a: {a:?}");
+    println!("b: {b:?}");
     let dur = b.duration_since(a);
-    println!("dur: {:?}", dur);
+    println!("dur: {dur:?}");
     assert_almost_eq!(b - dur, a);
     assert_almost_eq!(a + dur, b);
 
index b39701a3d428828bf0cb7453553bdbdee6d9fec8..000f5fa3f5860842463b8ca38afa0630879c3696 100644 (file)
@@ -149,7 +149,7 @@ fn optgroups() -> getopts::Options {
 }
 
 fn usage(binary: &str, options: &getopts::Options) {
-    let message = format!("Usage: {} [OPTIONS] [FILTERS...]", binary);
+    let message = format!("Usage: {binary} [OPTIONS] [FILTERS...]");
     println!(
         r#"{usage}
 
@@ -360,7 +360,7 @@ fn get_shuffle_seed(matches: &getopts::Matches, allow_unstable: bool) -> OptPart
         shuffle_seed = match env::var("RUST_TEST_SHUFFLE_SEED") {
             Ok(val) => match val.parse::<u64>() {
                 Ok(n) => Some(n),
-                Err(_) => panic!("RUST_TEST_SHUFFLE_SEED is `{}`, should be a number.", val),
+                Err(_) => panic!("RUST_TEST_SHUFFLE_SEED is `{val}`, should be a number."),
             },
             Err(_) => None,
         };
index 22fcd77dccc52a5f32a5a1d51a09fd2cfa3995e6..c7e8507113e0c178bd9e418e74519a3bad0b1f6f 100644 (file)
@@ -114,11 +114,11 @@ pub fn write_log_result(
                 match *result {
                     TestResult::TrOk => "ok".to_owned(),
                     TestResult::TrFailed => "failed".to_owned(),
-                    TestResult::TrFailedMsg(ref msg) => format!("failed: {}", msg),
+                    TestResult::TrFailedMsg(ref msg) => format!("failed: {msg}"),
                     TestResult::TrIgnored => {
                         #[cfg(not(bootstrap))]
                         if let Some(msg) = ignore_message {
-                            format!("ignored, {}", msg)
+                            format!("ignored, {msg}")
                         } else {
                             "ignored".to_owned()
                         }
@@ -132,7 +132,7 @@ pub fn write_log_result(
             )
         })?;
         if let Some(exec_time) = exec_time {
-            self.write_log(|| format!(" <{}>", exec_time))?;
+            self.write_log(|| format!(" <{exec_time}>"))?;
         }
         self.write_log(|| "\n")
     }
@@ -171,14 +171,14 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Res
             }
         };
 
-        writeln!(output, "{}: {}", name, fntype)?;
-        st.write_log(|| format!("{} {}\n", fntype, name))?;
+        writeln!(output, "{name}: {fntype}")?;
+        st.write_log(|| format!("{fntype} {name}\n"))?;
     }
 
     fn plural(count: u32, s: &str) -> String {
         match count {
-            1 => format!("{} {}", 1, s),
-            n => format!("{} {}s", n, s),
+            1 => format!("1 {s}"),
+            n => format!("{n} {s}s"),
         }
     }
 
@@ -218,7 +218,7 @@ fn handle_test_result(st: &mut ConsoleTestState, completed_test: CompletedTest)
         TestResult::TrFailedMsg(msg) => {
             st.failed += 1;
             let mut stdout = stdout;
-            stdout.extend_from_slice(format!("note: {}", msg).as_bytes());
+            stdout.extend_from_slice(format!("note: {msg}").as_bytes());
             st.failures.push((test, stdout));
         }
         TestResult::TrTimedFail => {
index 54e9860ab548779173d623709d5a33fe4c98eb9e..e6fb4f5707b35b17ef0c913d9880b2bee839ee9a 100644 (file)
@@ -97,7 +97,7 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
                         test_name,
                         duration.as_secs_f64()
                     ))?;
-                    self.write_message(&*format!("<failure message=\"{}\" type=\"assert\"/>", m))?;
+                    self.write_message(&*format!("<failure message=\"{m}\" type=\"assert\"/>"))?;
                     self.write_message("</testcase>")?;
                 }
 
index 041df5216d7b307c5385a30f25b9963ca3290fb5..f55d390aa562130d4da2eb674d4c32a6937f2cb6 100644 (file)
@@ -96,7 +96,7 @@ fn write_time(
         exec_time: Option<&time::TestExecTime>,
     ) -> io::Result<()> {
         if let (Some(opts), Some(time)) = (self.time_options, exec_time) {
-            let time_str = format!(" <{}>", time);
+            let time_str = format!(" <{time}>");
 
             let color = if self.use_color {
                 if opts.is_critical(desc, time) {
@@ -124,7 +124,7 @@ fn write_results(
         inputs: &Vec<(TestDesc, Vec<u8>)>,
         results_type: &str,
     ) -> io::Result<()> {
-        let results_out_str = format!("\n{}:\n", results_type);
+        let results_out_str = format!("\n{results_type}:\n");
 
         self.write_plain(&results_out_str)?;
 
@@ -147,7 +147,7 @@ fn write_results(
         self.write_plain(&results_out_str)?;
         results.sort();
         for name in &results {
-            self.write_plain(&format!("    {}\n", name))?;
+            self.write_plain(&format!("    {name}\n"))?;
         }
         Ok(())
     }
@@ -167,9 +167,9 @@ pub fn write_time_failures(&mut self, state: &ConsoleTestState) -> io::Result<()
     fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
         let name = desc.padded_name(self.max_name_len, desc.name.padding());
         if let Some(test_mode) = desc.test_mode() {
-            self.write_plain(&format!("test {} - {} ... ", name, test_mode))?;
+            self.write_plain(&format!("test {name} - {test_mode} ... "))?;
         } else {
-            self.write_plain(&format!("test {} ... ", name))?;
+            self.write_plain(&format!("test {name} ... "))?;
         }
 
         Ok(())
@@ -180,11 +180,11 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> {
     fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> {
         let noun = if test_count != 1 { "tests" } else { "test" };
         let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed {
-            format!(" (shuffle seed: {})", shuffle_seed)
+            format!(" (shuffle seed: {shuffle_seed})")
         } else {
             String::new()
         };
-        self.write_plain(&format!("\nrunning {} {}{}\n", test_count, noun, shuffle_seed_msg))
+        self.write_plain(&format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
     }
 
     fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
@@ -266,7 +266,7 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
         self.write_plain(&s)?;
 
         if let Some(ref exec_time) = state.exec_time {
-            let time_str = format!("; finished in {}", exec_time);
+            let time_str = format!("; finished in {exec_time}");
             self.write_plain(&time_str)?;
         }
 
index 12aca7cd9a42dd7af12b5cea216bd1e164a751a4..fb40f86b42e19ebfdcec4c15e288c171be262f9f 100644 (file)
@@ -122,7 +122,7 @@ pub fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         self.write_plain("\nsuccesses:\n")?;
         successes.sort();
         for name in &successes {
-            self.write_plain(&format!("    {}\n", name))?;
+            self.write_plain(&format!("    {name}\n"))?;
         }
         Ok(())
     }
@@ -148,7 +148,7 @@ pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         self.write_plain("\nfailures:\n")?;
         failures.sort();
         for name in &failures {
-            self.write_plain(&format!("    {}\n", name))?;
+            self.write_plain(&format!("    {name}\n"))?;
         }
         Ok(())
     }
@@ -156,9 +156,9 @@ pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
     fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
         let name = desc.padded_name(self.max_name_len, desc.name.padding());
         if let Some(test_mode) = desc.test_mode() {
-            self.write_plain(&format!("test {} - {} ... ", name, test_mode))?;
+            self.write_plain(&format!("test {name} - {test_mode} ... "))?;
         } else {
-            self.write_plain(&format!("test {} ... ", name))?;
+            self.write_plain(&format!("test {name} ... "))?;
         }
 
         Ok(())
@@ -170,11 +170,11 @@ fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> i
         self.total_test_count = test_count;
         let noun = if test_count != 1 { "tests" } else { "test" };
         let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed {
-            format!(" (shuffle seed: {})", shuffle_seed)
+            format!(" (shuffle seed: {shuffle_seed})")
         } else {
             String::new()
         };
-        self.write_plain(&format!("\nrunning {} {}{}\n", test_count, noun, shuffle_seed_msg))
+        self.write_plain(&format!("\nrunning {test_count} {noun}{shuffle_seed_msg}\n"))
     }
 
     fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
@@ -247,7 +247,7 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
         self.write_plain(&s)?;
 
         if let Some(ref exec_time) = state.exec_time {
-            let time_str = format!("; finished in {}", exec_time);
+            let time_str = format!("; finished in {exec_time}");
             self.write_plain(&time_str)?;
         }
 
index e25f524ec05667f52fa58a7c06d0c5ff99b11cdc..eb211157371b55b532c5888c9b93fc9856b1f9fb 100644 (file)
@@ -6,7 +6,7 @@ pub fn get_concurrency() -> usize {
     if let Ok(value) = env::var("RUST_TEST_THREADS") {
         match value.parse::<NonZeroUsize>().ok() {
             Some(n) => n.get(),
-            _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", value),
+            _ => panic!("RUST_TEST_THREADS is `{value}`, should be a positive integer."),
         }
     } else {
         thread::available_parallelism().map(|n| n.get()).unwrap_or(1)
index 50bb260762a7066649a60e1ed39c393ed2db29f8..f762f88819da530c8206c92736bb0bc7304c7bc8 100644 (file)
@@ -13,7 +13,7 @@ pub fn get_exit_code(status: ExitStatus) -> Result<i32, String> {
     match status.code() {
         Some(code) => Ok(code),
         None => match status.signal() {
-            Some(signal) => Err(format!("child process exited with signal {}", signal)),
+            Some(signal) => Err(format!("child process exited with signal {signal}")),
             None => Err("child process exited with unknown signal".into()),
         },
     }
index 8fc2b4ed748c28fe01b7f310f5b96cb9a1d3ef04..088e3a23ea4d9f5af235472b09164de7f920b814 100644 (file)
@@ -99,7 +99,7 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
     let mut opts = match cli::parse_opts(args) {
         Some(Ok(o)) => o,
         Some(Err(msg)) => {
-            eprintln!("error: {}", msg);
+            eprintln!("error: {msg}");
             process::exit(ERROR_EXIT_CODE);
         }
         None => return,
@@ -109,7 +109,7 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
     }
     if opts.list {
         if let Err(e) = console::list_tests_console(&opts, tests) {
-            eprintln!("error: io error when listing tests: {:?}", e);
+            eprintln!("error: io error when listing tests: {e:?}");
             process::exit(ERROR_EXIT_CODE);
         }
     } else {
@@ -117,7 +117,7 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
             Ok(true) => {}
             Ok(false) => process::exit(ERROR_EXIT_CODE),
             Err(e) => {
-                eprintln!("error: io error when listing tests: {:?}", e);
+                eprintln!("error: io error when listing tests: {e:?}");
                 process::exit(ERROR_EXIT_CODE);
             }
         }
@@ -153,7 +153,7 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) {
             .filter(|test| test.desc.name.as_slice() == name)
             .map(make_owned_test)
             .next()
-            .unwrap_or_else(|| panic!("couldn't find a test with the provided name '{}'", name));
+            .unwrap_or_else(|| panic!("couldn't find a test with the provided name '{name}'"));
         let TestDescAndFn { desc, testfn } = test;
         let testfn = match testfn {
             StaticTestFn(f) => f,
@@ -524,7 +524,7 @@ fn run_test_inner(
                     Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()();
                     None
                 }
-                Err(e) => panic!("failed to spawn thread to run test: {}", e),
+                Err(e) => panic!("failed to spawn thread to run test: {e}"),
             }
         } else {
             runtest();
@@ -678,7 +678,7 @@ fn run_test_in_spawned_subprocess(desc: TestDesc, testfn: Box<dyn FnOnce() + Sen
         // We don't support serializing TrFailedMsg, so just
         // print the message out to stderr.
         if let TrFailedMsg(msg) = &test_result {
-            eprintln!("{}", msg);
+            eprintln!("{msg}");
         }
 
         if let Some(info) = panic_info {
index 0d37eb7359d85cd50963a5e4e2dee17b700db786..0756c8374aa670d614c1d0c9b632af403e1fb22d 100644 (file)
@@ -268,7 +268,7 @@ pub(crate) fn expand(
                     },
                     'e' => state = SeekIfEnd(0),
                     ';' => (),
-                    _ => return Err(format!("unrecognized format option {}", cur)),
+                    _ => return Err(format!("unrecognized format option {cur}")),
                 }
             }
             PushParam => {
index 256d1aaf446d96f962e0d29f0285d75ef2b5f9c5..c738f3ba04fce1108973c6beef4ddcd7838457a8 100644 (file)
@@ -78,15 +78,15 @@ fn test_push_bad_param() {
 fn test_comparison_ops() {
     let v = [('<', [1u8, 0u8, 0u8]), ('=', [0u8, 1u8, 0u8]), ('>', [0u8, 0u8, 1u8])];
     for &(op, bs) in v.iter() {
-        let s = format!("%{{1}}%{{2}}%{}%d", op);
+        let s = format!("%{{1}}%{{2}}%{op}%d");
         let res = expand(s.as_bytes(), &[], &mut Variables::new());
         assert!(res.is_ok(), "{}", res.unwrap_err());
         assert_eq!(res.unwrap(), vec![b'0' + bs[0]]);
-        let s = format!("%{{1}}%{{1}}%{}%d", op);
+        let s = format!("%{{1}}%{{1}}%{op}%d");
         let res = expand(s.as_bytes(), &[], &mut Variables::new());
         assert!(res.is_ok(), "{}", res.unwrap_err());
         assert_eq!(res.unwrap(), vec![b'0' + bs[1]]);
-        let s = format!("%{{2}}%{{1}}%{}%d", op);
+        let s = format!("%{{2}}%{{1}}%{op}%d");
         let res = expand(s.as_bytes(), &[], &mut Variables::new());
         assert!(res.is_ok(), "{}", res.unwrap_err());
         assert_eq!(res.unwrap(), vec![b'0' + bs[2]]);
index b24f3f8b05e708cd9bb606d8f1de07f3a485c3ca..5d40b7988b52dad0cecd70a227e62f1d8f971916 100644 (file)
@@ -198,7 +198,7 @@ macro_rules! t( ($e:expr) => (
     let extended = match magic {
         0o0432 => false,
         0o01036 => true,
-        _ => return Err(format!("invalid magic number, found {:o}", magic)),
+        _ => return Err(format!("invalid magic number, found {magic:o}")),
     };
 
     // According to the spec, these fields must be >= -1 where -1 means that the feature is not
index 8c216a1e0e70e2d40206073610ac6b7be29a1cf1..7f44d6e3d0f122dff5157cd0d2914f2e2f097499 100644 (file)
@@ -89,7 +89,7 @@ pub fn get_result_from_exit_code(
     let result = match code {
         TR_OK => TestResult::TrOk,
         TR_FAILED => TestResult::TrFailed,
-        _ => TestResult::TrFailedMsg(format!("got unexpected return code {}", code)),
+        _ => TestResult::TrFailedMsg(format!("got unexpected return code {code}")),
     };
 
     // If test is already failed (or allowed to fail), do not change the result.
index c8c5528b104ebeb24e6e76592f3d0137ec9cda96..432628613f586e0480d06dc45a7aa3397cfa36a5 100644 (file)
@@ -249,6 +249,10 @@ pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
     extern "C-unwind" {
         pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
     }
+    #[cfg_attr(
+        all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
+        link(name = "unwind", kind = "static", modifiers = "-bundle")
+    )]
     extern "C" {
         pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
                                  trace_argument: *mut c_void)
index fe9d6a727ed1eceb86674ae0684c09b54f0218ed..4c32547f0590b6178241808a0cd70440fab63598 100644 (file)
@@ -3,6 +3,7 @@ name = "bootstrap"
 version = "0.0.0"
 edition = "2021"
 build = "build.rs"
+default-run = "bootstrap"
 
 [lib]
 path = "lib.rs"
index 6c1128b393fed9207bb2662cdc5beeffa0f69260..71b8f3c4553bce5140bc6df271b2b181fd58c661 100644 (file)
@@ -1233,16 +1233,18 @@ def bootstrap(help_triggered):
     build.verbose = args.verbose
     build.clean = args.clean
 
-    # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then fallback to `config.toml` (if it
-    # exists).
+    # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`,
+    # then `config.toml` in the root directory.
     toml_path = args.config or os.getenv('RUST_BOOTSTRAP_CONFIG')
-    if not toml_path and os.path.exists('config.toml'):
+    using_default_path = toml_path is None
+    if using_default_path:
         toml_path = 'config.toml'
-
-    if toml_path:
         if not os.path.exists(toml_path):
             toml_path = os.path.join(build.rust_root, toml_path)
 
+    # Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
+    # but not if `config.toml` hasn't been created.
+    if not using_default_path or os.path.exists(toml_path):
         with open(toml_path) as config:
             build.config_toml = config.read()
 
@@ -1267,7 +1269,7 @@ def bootstrap(help_triggered):
     build.check_vendored_status()
 
     build_dir = build.get_toml('build-dir', 'build') or 'build'
-    build.build_dir = os.path.abspath(build_dir.replace("$ROOT", build.rust_root))
+    build.build_dir = os.path.abspath(build_dir)
 
     with open(os.path.join(build.rust_root, "src", "stage0.json")) as f:
         data = json.load(f)
@@ -1302,10 +1304,7 @@ def bootstrap(help_triggered):
     env = os.environ.copy()
     env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
     env["BOOTSTRAP_PYTHON"] = sys.executable
-    env["BUILD_DIR"] = build.build_dir
     env["RUSTC_BOOTSTRAP"] = '1'
-    if toml_path:
-        env["BOOTSTRAP_CONFIG"] = toml_path
     if build.rustc_commit is not None:
         env["BOOTSTRAP_DOWNLOAD_RUSTC"] = '1'
     run(args, env=env, verbose=build.verbose, is_bootstrap=True)
index fc55c8626d99fe28ae72b851dc7cf9c83ca166df..1903f0baef1fae4d71a8f0ce3210e3a7e334965b 100644 (file)
@@ -883,7 +883,7 @@ pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
     }
 
     pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
-        let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc"));
+        let mut cmd = Command::new(&self.bootstrap_out.join("rustdoc"));
         cmd.env("RUSTC_STAGE", compiler.stage.to_string())
             .env("RUSTC_SYSROOT", self.sysroot(compiler))
             // Note that this is *not* the sysroot_libdir because rustdoc must be linked
@@ -1249,7 +1249,7 @@ pub fn cargo(
             .env("RUSTC_STAGE", stage.to_string())
             .env("RUSTC_SYSROOT", &sysroot)
             .env("RUSTC_LIBDIR", &libdir)
-            .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
+            .env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
             .env(
                 "RUSTDOC_REAL",
                 if cmd == "doc" || cmd == "rustdoc" || (cmd == "test" && want_rustdoc) {
@@ -1263,7 +1263,7 @@ pub fn cargo(
         // Clippy support is a hack and uses the default `cargo-clippy` in path.
         // Don't override RUSTC so that the `cargo-clippy` in path will be run.
         if cmd != "clippy" {
-            cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc"));
+            cargo.env("RUSTC", self.bootstrap_out.join("rustc"));
         }
 
         // Dealing with rpath here is a little special, so let's go into some
index bc71034496968ff3fad5a502309b39e65ae72408..b76bb569852cdb9806b1f8664b619a258cf5c28f 100644 (file)
@@ -8,10 +8,10 @@ fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
     config.save_toolstates = None;
     config.dry_run = true;
     config.ninja_in_file = false;
-    // try to avoid spurious failures in dist where we create/delete each others file
     config.out = PathBuf::from(env::var_os("BOOTSTRAP_OUTPUT_DIRECTORY").unwrap());
     config.initial_rustc = PathBuf::from(env::var_os("RUSTC").unwrap());
     config.initial_cargo = PathBuf::from(env::var_os("BOOTSTRAP_INITIAL_CARGO").unwrap());
+    // try to avoid spurious failures in dist where we create/delete each others file
     let dir = config
         .out
         .join("tmp-rustbuild-tests")
index b17b94f2893953a2cfa69ac79437ce7178e05fab..0c0a4733231d22e07bbbcc910eb1bda673a01f0d 100644 (file)
@@ -6,7 +6,6 @@
 use std::cmp;
 use std::collections::{HashMap, HashSet};
 use std::env;
-use std::ffi::OsString;
 use std::fmt;
 use std::fs;
 use std::path::{Path, PathBuf};
@@ -392,7 +391,6 @@ struct Build {
         build: Option<String>,
         host: Option<Vec<String>>,
         target: Option<Vec<String>>,
-        // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable
         build_dir: Option<String>,
         cargo: Option<String>,
         rustc: Option<String>,
@@ -588,18 +586,6 @@ struct TomlTarget {
 }
 
 impl Config {
-    fn path_from_python(var_key: &str) -> PathBuf {
-        match env::var_os(var_key) {
-            Some(var_val) => Self::normalize_python_path(var_val),
-            _ => panic!("expected '{}' to be set", var_key),
-        }
-    }
-
-    /// Normalizes paths from Python slightly. We don't trust paths from Python (#49785).
-    fn normalize_python_path(path: OsString) -> PathBuf {
-        Path::new(&path).components().collect()
-    }
-
     pub fn default_opts() -> Config {
         let mut config = Config::default();
         config.llvm_optimize = true;
@@ -625,7 +611,7 @@ pub fn default_opts() -> Config {
         let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
         // Undo `src/bootstrap`
         config.src = manifest_dir.parent().unwrap().parent().unwrap().to_owned();
-        config.out = Config::path_from_python("BUILD_DIR");
+        config.out = PathBuf::from("build");
 
         config.initial_cargo = PathBuf::from(env!("CARGO"));
         config.initial_rustc = PathBuf::from(env!("RUSTC"));
@@ -655,19 +641,14 @@ pub fn parse(args: &[String]) -> Config {
         config.llvm_profile_use = flags.llvm_profile_use;
         config.llvm_profile_generate = flags.llvm_profile_generate;
 
-        if config.dry_run {
-            let dir = config.out.join("tmp-dry-run");
-            t!(fs::create_dir_all(&dir));
-            config.out = dir;
-        }
-
         #[cfg(test)]
         let get_toml = |_| TomlConfig::default();
         #[cfg(not(test))]
         let get_toml = |file: &Path| {
             use std::process;
 
-            let contents = t!(fs::read_to_string(file), "`include` config not found");
+            let contents =
+                t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
             match toml::from_str(&contents) {
                 Ok(table) => table,
                 Err(err) => {
@@ -677,7 +658,25 @@ pub fn parse(args: &[String]) -> Config {
             }
         };
 
-        let mut toml = flags.config.as_deref().map(get_toml).unwrap_or_else(TomlConfig::default);
+        // Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, then `config.toml` in the root directory.
+        let toml_path = flags
+            .config
+            .clone()
+            .or_else(|| env::var_os("RUST_BOOTSTRAP_CONFIG").map(PathBuf::from));
+        let using_default_path = toml_path.is_none();
+        let mut toml_path = toml_path.unwrap_or_else(|| PathBuf::from("config.toml"));
+        if using_default_path && !toml_path.exists() {
+            toml_path = config.src.join(toml_path);
+        }
+
+        // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
+        // but not if `config.toml` hasn't been created.
+        let mut toml = if !using_default_path || toml_path.exists() {
+            get_toml(&toml_path)
+        } else {
+            TomlConfig::default()
+        };
+
         if let Some(include) = &toml.profile {
             let mut include_path = config.src.clone();
             include_path.push("src");
@@ -689,12 +688,25 @@ pub fn parse(args: &[String]) -> Config {
         }
 
         config.changelog_seen = toml.changelog_seen;
-        if let Some(cfg) = flags.config {
-            config.config = cfg;
-        }
+        config.config = toml_path;
 
         let build = toml.build.unwrap_or_default();
 
+        set(&mut config.initial_rustc, build.rustc.map(PathBuf::from));
+        set(&mut config.out, build.build_dir.map(PathBuf::from));
+        // NOTE: Bootstrap spawns various commands with different working directories.
+        // To avoid writing to random places on the file system, `config.out` needs to be an absolute path.
+        if !config.out.is_absolute() {
+            // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead.
+            config.out = crate::util::absolute(&config.out);
+        }
+
+        if config.dry_run {
+            let dir = config.out.join("tmp-dry-run");
+            t!(fs::create_dir_all(&dir));
+            config.out = dir;
+        }
+
         config.hosts = if let Some(arg_host) = flags.host {
             arg_host
         } else if let Some(file_host) = build.host {
index 94424cb4548fa5d0f5d8ef21ed4ef9291ef90550..87a130a09827dfbf2c988b8aa53a41983337e369 100755 (executable)
@@ -279,6 +279,10 @@ def build():
 
 
 def set(key, value):
+    if isinstance(value, list):
+        # Remove empty values, which value.split(',') tends to generate.
+        value = [v for v in value if v]
+
     s = "{:20} := {}".format(key, value)
     if len(s) < 70:
         p(s)
index e34b40a93ff47c577e092cbdf1a95ecc2cbf2ee4..1a4e6a9688803b544295aa7d1c7ba0d5d2d9c2d0 100644 (file)
@@ -3,7 +3,6 @@
 //! This module implements the command-line parsing of the build system which
 //! has various flags to configure how it's run.
 
-use std::env;
 use std::path::PathBuf;
 use std::process;
 
@@ -541,7 +540,6 @@ pub fn parse(args: &[String]) -> Flags {
         // Get any optional paths which occur after the subcommand
         let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
 
-        let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
         let verbose = matches.opt_present("verbose");
 
         // User passed in -h/--help?
@@ -671,7 +669,7 @@ pub fn parse(args: &[String]) -> Flags {
             } else {
                 None
             },
-            config: cfg_file,
+            config: matches.opt_str("config").map(PathBuf::from),
             jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")),
             cmd,
             incremental: matches.opt_present("incremental"),
index ccc8516a89abf8014e888c3b6d43e1f3446a865b..2ee67d623eec90f191eacf17ee075116553620c2 100644 (file)
@@ -193,7 +193,6 @@ pub unsafe fn setup(_build: &mut crate::Build) {}
     (None, "bootstrap", None),
     (Some(Mode::Rustc), "parallel_compiler", None),
     (Some(Mode::ToolRustc), "parallel_compiler", None),
-    (Some(Mode::Std), "miri", None),
     (Some(Mode::Std), "stdarch_intel_sde", None),
     (Some(Mode::Std), "no_fp_fmt_parse", None),
     (Some(Mode::Std), "no_global_oom_handling", None),
@@ -261,6 +260,7 @@ pub struct Build {
     // Properties derived from the above configuration
     src: PathBuf,
     out: PathBuf,
+    bootstrap_out: PathBuf,
     rust_info: channel::GitInfo,
     cargo_info: channel::GitInfo,
     rls_info: channel::GitInfo,
@@ -435,6 +435,20 @@ pub fn new(config: Config) -> Build {
             .expect("failed to read src/version");
         let version = version.trim();
 
+        let bootstrap_out = if std::env::var("BOOTSTRAP_PYTHON").is_ok() {
+            out.join("bootstrap").join("debug")
+        } else {
+            let workspace_target_dir = std::env::var("CARGO_TARGET_DIR")
+                .map(PathBuf::from)
+                .unwrap_or_else(|_| src.join("target"));
+            let bootstrap_out = workspace_target_dir.join("debug");
+            if !bootstrap_out.join("rustc").exists() {
+                // this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented
+                panic!("run `cargo build --bins` before `cargo run`")
+            }
+            bootstrap_out
+        };
+
         let mut build = Build {
             initial_rustc: config.initial_rustc.clone(),
             initial_cargo: config.initial_cargo.clone(),
@@ -453,6 +467,7 @@ pub fn new(config: Config) -> Build {
             version: version.to_string(),
             src,
             out,
+            bootstrap_out,
 
             rust_info,
             cargo_info,
@@ -629,7 +644,7 @@ pub fn build(&mut self) {
         }
 
         if let Subcommand::Setup { profile } = &self.config.cmd {
-            return setup::setup(&self.config.src, *profile);
+            return setup::setup(&self.config, *profile);
         }
 
         {
index f00c5ce5aa6f03fff9885a022260c1d4df076014..0fe39defae85dee45bd886b7ef28fc602aa579ba 100644 (file)
@@ -259,18 +259,6 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
         }
 
-        // For distribution we want the LLVM tools to be *statically* linked to libstdc++.
-        // We also do this if the user explicitly requested static libstdc++.
-        if builder.config.llvm_tools_enabled || builder.config.llvm_static_stdcpp {
-            if !target.contains("msvc") && !target.contains("netbsd") {
-                if target.contains("apple") {
-                    ldflags.push_all("-static-libstdc++");
-                } else {
-                    ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++");
-                }
-            }
-        }
-
         if target.starts_with("riscv") && !target.contains("freebsd") {
             // RISC-V GCC erroneously requires linking against
             // `libatomic` when using 1-byte and 2-byte C++
@@ -576,6 +564,18 @@ fn configure_cmake(
         ldflags.push_all(&flags);
     }
 
+    // For distribution we want the LLVM tools to be *statically* linked to libstdc++.
+    // We also do this if the user explicitly requested static libstdc++.
+    if builder.config.llvm_tools_enabled || builder.config.llvm_static_stdcpp {
+        if !target.contains("msvc") && !target.contains("netbsd") {
+            if target.contains("apple") {
+                ldflags.push_all("-static-libstdc++");
+            } else {
+                ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++");
+            }
+        }
+    }
+
     cfg.define("CMAKE_SHARED_LINKER_FLAGS", &ldflags.shared);
     cfg.define("CMAKE_MODULE_LINKER_FLAGS", &ldflags.module);
     cfg.define("CMAKE_EXE_LINKER_FLAGS", &ldflags.exe);
index 9a9ef0b76955d503127bc64bd7b6be057b575be7..e1235829b3aeff524b6997bf24ebd5f66312b050 100644 (file)
@@ -1,5 +1,5 @@
-use crate::TargetSelection;
 use crate::{t, VERSION};
+use crate::{Config, TargetSelection};
 use std::env::consts::EXE_SUFFIX;
 use std::fmt::Write as _;
 use std::fs::File;
@@ -81,24 +81,22 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-pub fn setup(src_path: &Path, profile: Profile) {
-    let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
+pub fn setup(config: &Config, profile: Profile) {
+    let path = &config.config;
 
-    if cfg_file.as_ref().map_or(false, |f| f.exists()) {
-        let file = cfg_file.unwrap();
+    if path.exists() {
         println!(
             "error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
-            file.display()
+            path.display()
         );
-        println!("help: try adding `profile = \"{}\"` at the top of {}", profile, file.display());
+        println!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display());
         println!(
             "note: this will use the configuration in {}",
-            profile.include_path(src_path).display()
+            profile.include_path(&config.src).display()
         );
         std::process::exit(1);
     }
 
-    let path = cfg_file.unwrap_or_else(|| "config.toml".into());
     let settings = format!(
         "# Includes one of the default files in src/bootstrap/defaults\n\
     profile = \"{}\"\n\
@@ -107,7 +105,7 @@ pub fn setup(src_path: &Path, profile: Profile) {
     );
     t!(fs::write(path, settings));
 
-    let include_path = profile.include_path(src_path);
+    let include_path = profile.include_path(&config.src);
     println!("`x.py` will now use the configuration at {}", include_path.display());
 
     let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
@@ -138,7 +136,7 @@ pub fn setup(src_path: &Path, profile: Profile) {
 
     println!();
 
-    t!(install_git_hook_maybe(src_path));
+    t!(install_git_hook_maybe(&config.src));
 
     println!();
 
index e4fcb287f1228545d44301e6d5f993a7b0571763..58b73ebed5000118365eb8cbab5ce2ae3ff8f425 100644 (file)
@@ -730,7 +730,7 @@ fn make_run(run: RunConfig<'_>) {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let rustdoc = builder.out.join("bootstrap/debug/rustdoc");
+        let rustdoc = builder.bootstrap_out.join("rustdoc");
         let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
         cmd.arg(rustdoc.to_str().unwrap())
             .arg(builder.src.join("src/librustdoc/html/static/css/themes").to_str().unwrap())
@@ -2346,6 +2346,8 @@ fn run(self, builder: &Builder<'_>) {
             .current_dir(builder.src.join("src/bootstrap"))
             .env("RUSTFLAGS", "-Cdebuginfo=2")
             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
+            // HACK: bootstrap's tests want to know the output directory, but there's no way to set
+            // it except through config.toml. Set it through an env variable instead.
             .env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out)
             .env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo)
             .env("RUSTC_BOOTSTRAP", "1")
index 8e770d4d57fa6efeedeceaa9392b020c483a9f2e..30d9665dd0f4ad98f2974c4796bf877b33db18fd 100644 (file)
@@ -440,3 +440,112 @@ fn fail(s: &str) -> ! {
     println!("\n\n{}\n\n", s);
     std::process::exit(1);
 }
+
+/// Copied from `std::path::absolute` until it stabilizes.
+///
+/// FIXME: this shouldn't exist.
+pub(crate) fn absolute(path: &Path) -> PathBuf {
+    if path.as_os_str().is_empty() {
+        panic!("can't make empty path absolute");
+    }
+    #[cfg(unix)]
+    {
+        t!(absolute_unix(path), format!("could not make path absolute: {}", path.display()))
+    }
+    #[cfg(windows)]
+    {
+        t!(absolute_windows(path), format!("could not make path absolute: {}", path.display()))
+    }
+    #[cfg(not(any(unix, windows)))]
+    {
+        println!("warning: bootstrap is not supported on non-unix platforms");
+        t!(std::fs::canonicalize(t!(std::env::current_dir()))).join(path)
+    }
+}
+
+#[cfg(unix)]
+/// Make a POSIX path absolute without changing its semantics.
+fn absolute_unix(path: &Path) -> io::Result<PathBuf> {
+    // This is mostly a wrapper around collecting `Path::components`, with
+    // exceptions made where this conflicts with the POSIX specification.
+    // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
+    // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+
+    use std::os::unix::prelude::OsStrExt;
+    let mut components = path.components();
+    let path_os = path.as_os_str().as_bytes();
+
+    let mut normalized = if path.is_absolute() {
+        // "If a pathname begins with two successive <slash> characters, the
+        // first component following the leading <slash> characters may be
+        // interpreted in an implementation-defined manner, although more than
+        // two leading <slash> characters shall be treated as a single <slash>
+        // character."
+        if path_os.starts_with(b"//") && !path_os.starts_with(b"///") {
+            components.next();
+            PathBuf::from("//")
+        } else {
+            PathBuf::new()
+        }
+    } else {
+        env::current_dir()?
+    };
+    normalized.extend(components);
+
+    // "Interfaces using pathname resolution may specify additional constraints
+    // when a pathname that does not name an existing directory contains at
+    // least one non- <slash> character and contains one or more trailing
+    // <slash> characters".
+    // A trailing <slash> is also meaningful if "a symbolic link is
+    // encountered during pathname resolution".
+
+    if path_os.ends_with(b"/") {
+        normalized.push("");
+    }
+
+    Ok(normalized)
+}
+
+#[cfg(windows)]
+fn absolute_windows(path: &std::path::Path) -> std::io::Result<std::path::PathBuf> {
+    use std::ffi::OsString;
+    use std::io::Error;
+    use std::os::windows::ffi::{OsStrExt, OsStringExt};
+    use std::ptr::null_mut;
+    #[link(name = "kernel32")]
+    extern "system" {
+        fn GetFullPathNameW(
+            lpFileName: *const u16,
+            nBufferLength: u32,
+            lpBuffer: *mut u16,
+            lpFilePart: *mut *const u16,
+        ) -> u32;
+    }
+
+    unsafe {
+        // encode the path as UTF-16
+        let path: Vec<u16> = path.as_os_str().encode_wide().chain([0]).collect();
+        let mut buffer = Vec::new();
+        // Loop until either success or failure.
+        loop {
+            // Try to get the absolute path
+            let len = GetFullPathNameW(
+                path.as_ptr(),
+                buffer.len().try_into().unwrap(),
+                buffer.as_mut_ptr(),
+                null_mut(),
+            );
+            match len as usize {
+                // Failure
+                0 => return Err(Error::last_os_error()),
+                // Buffer is too small, resize.
+                len if len > buffer.len() => buffer.resize(len, 0),
+                // Success!
+                len => {
+                    buffer.truncate(len);
+                    return Ok(OsString::from_wide(&buffer).into());
+                }
+            }
+        }
+    }
+}
index f1c42b248f4bd236d5781b6ba969d407abbfa2ca..9b92bed1f02b3f729b394293170ddaec87471c2d 100644 (file)
@@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
 # https://github.com/puppeteer/puppeteer/issues/375
 #
 # We also specify the version in case we need to update it to go around cache limitations.
-RUN npm install -g browser-ui-test@0.7.2 --unsafe-perm=true
+RUN npm install -g browser-ui-test@0.8.0 --unsafe-perm=true
 
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
index 97e08416d7686bc6d937e02189420fe2092460db..45405a11765cc761aab576fee0bb37982a96a612 100644 (file)
@@ -4,3 +4,7 @@ title = "The rustdoc book"
 
 [output.html]
 git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustdoc"
+
+[output.html.redirect]
+"/the-doc-attribute.html" = "write-documentation/the-doc-attribute.html"
+"/documentation-tests.html" = "write-documentation/documentation-tests.html"
index eb18185945387cbaf5de34a8cfc6335ccfc89c9d..d627f5b0389f39594ba815a731e9203edab60344 100644 (file)
@@ -1,16 +1,15 @@
 # The Rustdoc Book
 
 - [What is rustdoc?](what-is-rustdoc.md)
+- [Command-line arguments](command-line-arguments.md)
 - [How to read rustdoc output](how-to-read-rustdoc.md)
 - [How to write documentation](how-to-write-documentation.md)
-- [What to include (and exclude)](what-to-include.md)
-- [Command-line arguments](command-line-arguments.md)
-- [The `#[doc]` attribute](the-doc-attribute.md)
-- [Documentation tests](documentation-tests.md)
-- [Linking to items by name](linking-to-items-by-name.md)
-- [Lints](lints.md)
+    - [What to include (and exclude)](write-documentation/what-to-include.md)
+    - [The `#[doc]` attribute](write-documentation/the-doc-attribute.md)
+    - [Linking to items by name](write-documentation/linking-to-items-by-name.md)
+    - [Documentation tests](write-documentation/documentation-tests.md)
+- [Rustdoc-specific lints](lints.md)
 - [Advanced features](advanced-features.md)
 - [Unstable features](unstable-features.md)
-- [Website features](website-features.md)
-- [Passes](passes.md)
+- [Deprecated features](deprecated-features.md)
 - [References](references.md)
index 6147bd0a97a968e7234517d271405a290243ee60..dbf0baec04c03193629feca752c201437a875de1 100644 (file)
@@ -88,3 +88,25 @@ You can add multiple aliases at the same time by using a list:
 #[doc(alias("x", "big"))]
 pub struct BigX;
 ```
+
+## Custom search engines
+
+If you find yourself often referencing online Rust docs you might enjoy using a custom search
+engine. This allows you to use the navigation bar directly to search a `rustdoc` website.
+Most browsers support this feature by letting you define a URL template containing `%s`
+which will be substituted for the search term. As an example, for the standard library you could use
+this template:
+
+```text
+https://doc.rust-lang.org/stable/std/?search=%s
+```
+
+Note that this will take you to a results page listing all matches. If you want to navigate to the first
+result right away (which is often the best match) use the following instead:
+
+```text
+https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
+```
+
+This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
+to automatically go to the first result.
index 3ce57f88938f76d39f495db068a6a01b94893b41..2a2e51b2f6331085224ecb9c661c334cf32e7416 100644 (file)
@@ -177,7 +177,7 @@ $ rustdoc src/lib.rs --test
 ```
 
 This flag will run your code examples as tests. For more, see [the chapter
-on documentation tests](documentation-tests.md).
+on documentation tests](write-documentation/documentation-tests.md).
 
 See also `--test-args`.
 
@@ -190,7 +190,7 @@ $ rustdoc src/lib.rs --test --test-args ignored
 ```
 
 This flag will pass options to the test runner when running documentation tests.
-For more, see [the chapter on documentation tests](documentation-tests.md).
+For more, see [the chapter on documentation tests](write-documentation/documentation-tests.md).
 
 See also `--test`.
 
@@ -336,7 +336,7 @@ $ rustdoc src/lib.rs --sysroot /path/to/sysroot
 Similar to `rustc --sysroot`, this lets you change the sysroot `rustdoc` uses
 when compiling your code.
 
-### `--edition`: control the edition of docs and doctests
+## `--edition`: control the edition of docs and doctests
 
 Using this flag looks like this:
 
@@ -403,12 +403,12 @@ encoded as UTF-8.
 ## `--passes`: add more rustdoc passes
 
 This flag is **deprecated**.
-For more details on passes, see [the chapter on them](passes.md).
+For more details on passes, see [the chapter on them](deprecated-features.md#passes).
 
 ## `--no-defaults`: don't run default passes
 
 This flag is **deprecated**.
-For more details on passes, see [the chapter on them](passes.md).
+For more details on passes, see [the chapter on them](deprecated-features.md#passes).
 
 ## `-r`/`--input-format`: input format
 
@@ -417,23 +417,3 @@ This flag is **deprecated** and **has no effect**.
 Rustdoc only supports Rust source code and Markdown input formats. If the
 file ends in `.md` or `.markdown`, `rustdoc` treats it as a Markdown file.
 Otherwise, it assumes that the input file is Rust.
-
-# Unstable command line arguments
-
-## `--nocapture`
-
-When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be
-captured by rustdoc. Instead, the output will be directed to your terminal,
-as if you had run the test executable manually. This is especially useful
-for debugging your tests!
-
-## `--check`
-
-When this flag is supplied, rustdoc will type check and lint your code, but will not generate any
-documentation or run your doctests.
-
-Using this flag looks like:
-
-```bash
-rustdoc -Z unstable-options --check src/lib.rs
-```
diff --git a/src/doc/rustdoc/src/deprecated-features.md b/src/doc/rustdoc/src/deprecated-features.md
new file mode 100644 (file)
index 0000000..2bc6e8f
--- /dev/null
@@ -0,0 +1,13 @@
+# Deprecated features
+
+## Passes
+
+Rustdoc has a concept called "passes". These are transformations that
+`rustdoc` runs on your documentation before producing its final output.
+
+Customizing passes is **deprecated**. The available passes are not considered stable and may
+change in any release.
+
+In the past the most common use case for customizing passes was to omit the `strip-private` pass.
+You can do this more easily, and without risk of the pass being changed, by passing
+[`--document-private-items`](./unstable-features.md#--document-private-items).
diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md
deleted file mode 100644 (file)
index 534fd19..0000000
+++ /dev/null
@@ -1,445 +0,0 @@
-# Documentation tests
-
-`rustdoc` supports executing your documentation examples as tests. This makes sure
-that examples within your documentation are up to date and working.
-
-The basic idea is this:
-
-```rust,no_run
-/// # Examples
-///
-/// ```
-/// let x = 5;
-/// ```
-# fn f() {}
-```
-
-The triple backticks start and end code blocks. If this were in a file named `foo.rs`,
-running `rustdoc --test foo.rs` will extract this example, and then run it as a test.
-
-Please note that by default, if no language is set for the block code, rustdoc
-assumes it is Rust code. So the following:
-
-``````markdown
-```rust
-let x = 5;
-```
-``````
-
-is strictly equivalent to:
-
-``````markdown
-```
-let x = 5;
-```
-``````
-
-There's some subtlety though! Read on for more details.
-
-## Passing or failing a doctest
-
-Like regular unit tests, regular doctests are considered to "pass"
-if they compile and run without panicking.
-So if you want to demonstrate that some computation gives a certain result,
-the `assert!` family of macros works the same as other Rust code:
-
-```rust
-let foo = "foo";
-assert_eq!(foo, "foo");
-```
-
-This way, if the computation ever returns something different,
-the code panics and the doctest fails.
-
-## Pre-processing examples
-
-In the example above, you'll note something strange: there's no `main`
-function! Forcing you to write `main` for every example, no matter how small,
-adds friction and clutters the output. So `rustdoc` processes your examples
-slightly before running them. Here's the full algorithm `rustdoc` uses to
-preprocess examples:
-
-1. Some common `allow` attributes are inserted, including
-   `unused_variables`, `unused_assignments`, `unused_mut`,
-   `unused_attributes`, and `dead_code`. Small examples often trigger
-   these lints.
-2. Any attributes specified with `#![doc(test(attr(...)))]` are added.
-3. Any leading `#![foo]` attributes are left intact as crate attributes.
-4. If the example does not contain `extern crate`, and
-   `#![doc(test(no_crate_inject))]` was not specified, then `extern crate
-   <mycrate>;` is inserted (note the lack of `#[macro_use]`).
-5. Finally, if the example does not contain `fn main`, the remainder of the
-   text is wrapped in `fn main() { your_code }`.
-
-For more about that caveat in rule 4, see "Documenting Macros" below.
-
-## Hiding portions of the example
-
-Sometimes, you need some setup code, or other things that would distract
-from your example, but are important to make the tests work. Consider
-an example block that looks like this:
-
-```rust,no_run
-/// ```
-/// /// Some documentation.
-/// # fn foo() {} // this function will be hidden
-/// println!("Hello, World!");
-/// ```
-# fn f() {}
-```
-
-It will render like this:
-
-```rust
-/// Some documentation.
-# fn foo() {}
-println!("Hello, World!");
-```
-
-Yes, that's right: you can add lines that start with `# `, and they will
-be hidden from the output, but will be used when compiling your code. You
-can use this to your advantage. In this case, documentation comments need
-to apply to some kind of function, so if I want to show you just a
-documentation comment, I need to add a little function definition below
-it. At the same time, it's only there to satisfy the compiler, so hiding
-it makes the example more clear. You can use this technique to explain
-longer examples in detail, while still preserving the testability of your
-documentation.
-
-For example, imagine that we wanted to document this code:
-
-```rust
-let x = 5;
-let y = 6;
-println!("{}", x + y);
-```
-
-We might want the documentation to end up looking like this:
-
-> First, we set `x` to five:
->
-> ```rust
-> let x = 5;
-> # let y = 6;
-> # println!("{}", x + y);
-> ```
->
-> Next, we set `y` to six:
->
-> ```rust
-> # let x = 5;
-> let y = 6;
-> # println!("{}", x + y);
-> ```
->
-> Finally, we print the sum of `x` and `y`:
->
-> ```rust
-> # let x = 5;
-> # let y = 6;
-> println!("{}", x + y);
-> ```
-
-To keep each code block testable, we want the whole program in each block, but
-we don't want the reader to see every line every time.  Here's what we put in
-our source code:
-
-``````markdown
-First, we set `x` to five:
-
-```
-let x = 5;
-# let y = 6;
-# println!("{}", x + y);
-```
-
-Next, we set `y` to six:
-
-```
-# let x = 5;
-let y = 6;
-# println!("{}", x + y);
-```
-
-Finally, we print the sum of `x` and `y`:
-
-```
-# let x = 5;
-# let y = 6;
-println!("{}", x + y);
-```
-``````
-
-By repeating all parts of the example, you can ensure that your example still
-compiles, while only showing the parts that are relevant to that part of your
-explanation.
-
-The `#`-hiding of lines can be prevented by using two consecutive hashes
-`##`. This only needs to be done with the first `#` which would've
-otherwise caused hiding. If we have a string literal like the following,
-which has a line that starts with a `#`:
-
-```rust
-let s = "foo
-## bar # baz";
-```
-
-We can document it by escaping the initial `#`:
-
-```text
-/// let s = "foo
-/// ## bar # baz";
-```
-
-
-## Using `?` in doc tests
-
-When writing an example, it is rarely useful to include a complete error
-handling, as it would add significant amounts of boilerplate code. Instead, you
-may want the following:
-
-```rust,no_run
-/// ```
-/// use std::io;
-/// let mut input = String::new();
-/// io::stdin().read_line(&mut input)?;
-/// ```
-# fn f() {}
-```
-
-The problem is that `?` returns a `Result<T, E>` and test functions don't
-return anything, so this will give a mismatched types error.
-
-You can get around this limitation by manually adding a `main` that returns
-`Result<T, E>`, because `Result<T, E>` implements the `Termination` trait:
-
-```rust,no_run
-/// A doc test using ?
-///
-/// ```
-/// use std::io;
-///
-/// fn main() -> io::Result<()> {
-///     let mut input = String::new();
-///     io::stdin().read_line(&mut input)?;
-///     Ok(())
-/// }
-/// ```
-# fn f() {}
-```
-
-Together with the `# ` from the section above, you arrive at a solution that
-appears to the reader as the initial idea but works with doc tests:
-
-```rust,no_run
-/// ```
-/// use std::io;
-/// # fn main() -> io::Result<()> {
-/// let mut input = String::new();
-/// io::stdin().read_line(&mut input)?;
-/// # Ok(())
-/// # }
-/// ```
-# fn f() {}
-```
-
-As of version 1.34.0, one can also omit the `fn main()`, but you will have to
-disambiguate the error type:
-
-```rust,no_run
-/// ```
-/// use std::io;
-/// let mut input = String::new();
-/// io::stdin().read_line(&mut input)?;
-/// # Ok::<(), io::Error>(())
-/// ```
-# fn f() {}
-```
-
-This is an unfortunate consequence of the `?` operator adding an implicit
-conversion, so type inference fails because the type is not unique. Please note
-that you must write the `(())` in one sequence without intermediate whitespace
-so that `rustdoc` understands you want an implicit `Result`-returning function.
-
-## Showing warnings in doctests
-
-You can show warnings in doctests by running `rustdoc --test --test-args=--show-output`
-(or, if you're using cargo, `cargo test --doc -- --show-output`).
-By default, this will still hide `unused` warnings, since so many examples use private functions;
-you can add `#![warn(unused)]` to the top of your example if you want to see unused variables or dead code warnings.
-You can also use [`#![doc(test(attr(warn(unused))))]`][test-attr] in the crate root to enable warnings globally.
-
-[test-attr]: ./the-doc-attribute.md#testattr
-
-## Documenting macros
-
-Here’s an example of documenting a macro:
-
-```rust
-/// Panic with a given message unless an expression evaluates to true.
-///
-/// # Examples
-///
-/// ```
-/// # #[macro_use] extern crate foo;
-/// # fn main() {
-/// panic_unless!(1 + 1 == 2, “Math is broken.”);
-/// # }
-/// ```
-///
-/// ```should_panic
-/// # #[macro_use] extern crate foo;
-/// # fn main() {
-/// panic_unless!(true == false, “I’m broken.”);
-/// # }
-/// ```
-#[macro_export]
-macro_rules! panic_unless {
-    ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } });
-}
-# fn main() {}
-```
-
-You’ll note three things: we need to add our own `extern crate` line, so that
-we can add the `#[macro_use]` attribute. Second, we’ll need to add our own
-`main()` as well (for reasons discussed above). Finally, a judicious use of
-`#` to comment out those two things, so they don’t show up in the output.
-
-## Attributes
-
-Code blocks can be annotated with attributes that help `rustdoc` do the right
-thing when testing your code:
-
-The `ignore` attribute tells Rust to ignore your code. This is almost never
-what you want as it's the most generic. Instead, consider annotating it
-with `text` if it's not code or using `#`s to get a working example that
-only shows the part you care about.
-
-```rust
-/// ```ignore
-/// fn foo() {
-/// ```
-# fn foo() {}
-```
-
-`should_panic` tells `rustdoc` that the code should compile correctly but
-panic during execution. If the code doesn't panic, the test will fail.
-
-```rust
-/// ```should_panic
-/// assert!(false);
-/// ```
-# fn foo() {}
-```
-
-The `no_run` attribute will compile your code but not run it. This is
-important for examples such as "Here's how to retrieve a web page,"
-which you would want to ensure compiles, but might be run in a test
-environment that has no network access. This attribute can also be
-used to demonstrate code snippets that can cause Undefined Behavior.
-
-```rust
-/// ```no_run
-/// loop {
-///     println!("Hello, world");
-/// }
-/// ```
-# fn foo() {}
-```
-
-`compile_fail` tells `rustdoc` that the compilation should fail. If it
-compiles, then the test will fail. However, please note that code failing
-with the current Rust release may work in a future release, as new features
-are added.
-
-```rust
-/// ```compile_fail
-/// let x = 5;
-/// x += 2; // shouldn't compile!
-/// ```
-# fn foo() {}
-```
-
-`edition2015`, `edition2018` and `edition2021` tell `rustdoc`
-that the code sample should be compiled using the respective edition of Rust.
-
-```rust
-/// Only runs on the 2018 edition.
-///
-/// ```edition2018
-/// let result: Result<i32, ParseIntError> = try {
-///     "1".parse::<i32>()?
-///         + "2".parse::<i32>()?
-///         + "3".parse::<i32>()?
-/// };
-/// ```
-# fn foo() {}
-```
-
-## Syntax reference
-
-The *exact* syntax for code blocks, including the edge cases, can be found
-in the [Fenced Code Blocks](https://spec.commonmark.org/0.29/#fenced-code-blocks)
-section of the CommonMark specification.
-
-Rustdoc also accepts *indented* code blocks as an alternative to fenced
-code blocks: instead of surrounding your code with three backticks, you
-can indent each line by four or more spaces.
-
-``````markdown
-    let foo = "foo";
-    assert_eq!(foo, "foo");
-``````
-
-These, too, are documented in the CommonMark specification, in the
-[Indented Code Blocks](https://spec.commonmark.org/0.29/#indented-code-blocks)
-section.
-
-However, it's preferable to use fenced code blocks over indented code blocks.
-Not only are fenced code blocks considered more idiomatic for Rust code,
-but there is no way to use attributes such as `ignore` or `should_panic` with
-indented code blocks.
-
-### Include items only when collecting doctests
-
-Rustdoc's documentation tests can do some things that regular unit tests can't, so it can
-sometimes be useful to extend your doctests with samples that wouldn't otherwise need to be in
-documentation. To this end, Rustdoc allows you to have certain items only appear when it's
-collecting doctests, so you can utilize doctest functionality without forcing the test to appear in
-docs, or to find an arbitrary private item to include it on.
-
-When compiling a crate for use in doctests (with `--test` option), `rustdoc` will set `#[cfg(doctest)]`.
-Note that they will still link against only the public items of your crate; if you need to test
-private items, you need to write a unit test.
-
-In this example, we're adding doctests that we know won't compile, to verify that our struct can
-only take in valid data:
-
-```rust
-/// We have a struct here. Remember it doesn't accept negative numbers!
-pub struct MyStruct(pub usize);
-
-/// ```compile_fail
-/// let x = my_crate::MyStruct(-5);
-/// ```
-#[cfg(doctest)]
-pub struct MyStructOnlyTakesUsize;
-```
-
-Note that the struct `MyStructOnlyTakesUsize` here isn't actually part of your public crate
-API. The use of `#[cfg(doctest)]` makes sure that this struct only exists while `rustdoc` is
-collecting doctests. This means that its doctest is executed when `--test` is passed to rustdoc,
-but is hidden from the public documentation.
-
-Another possible use of `#[cfg(doctest)]` is to test doctests that are included in your README file
-without including it in your main documentation. For example, you could write this into your
-`lib.rs` to test your README as part of your doctests:
-
-```rust,no_run
-#[doc = include_str!("../README.md")]
-#[cfg(doctest)]
-pub struct ReadmeDoctests;
-```
-
-This will include your README as documentation on the hidden struct `ReadmeDoctests`, which will
-then be tested alongside the rest of your doctests.
index 99724d859ee75b81ca1a27a4d48cca446974e272..098bc1879b56f6c9a3f3f6006ba6d176e534681d 100644 (file)
@@ -26,7 +26,7 @@ At the top is some at-a-glance info and controls:
 - a button to collapse or expand the top-level documentation for that item
   (`[+]` or `[-]`),
 - a link to the source code (`[src]`),
-  if [configured](the-doc-attribute.html#html_no_source),
+  if [configured](write-documentation/the-doc-attribute.html#html_no_source),
   and present (the source may not be available if
   the documentation was created with `cargo doc --no-deps`),
 - and the version in which the item became stable,
@@ -52,7 +52,7 @@ For example, when looking at documentation for the crate root,
 it shows all the crates documented in the documentation bundle,
 and quick links to the modules, structs, traits, functions, and macros available
 from the current crate.
-At the top, it displays a [configurable logo](the-doc-attribute.html#html_logo_url)
+At the top, it displays a [configurable logo](write-documentation/the-doc-attribute.html#html_logo_url)
 alongside the current crate's name and version,
 or the current item whose documentation is being displayed.
 
index f89495cca3a31c4b43f849291abbfd2a2577de87..38fd1db5c21e8d5a19461967726e01482b0fec3e 100644 (file)
@@ -126,7 +126,7 @@ use std::env;
 
 // Prints each argument on a separate line
 for argument in env::args() {
-    println!("{}", argument);
+    println!("{argument}");
 }
 ```
 
diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md
deleted file mode 100644 (file)
index 6ca1d11..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-# Linking to items by name
-
-Rustdoc is capable of directly linking to other rustdoc pages using the path of
-the item as a link. This is referred to as an 'intra-doc link'.
-
-For example, in the following code all of the links will link to the rustdoc page for `Bar`:
-
-```rust
-/// This struct is not [Bar]
-pub struct Foo1;
-
-/// This struct is also not [bar](Bar)
-pub struct Foo2;
-
-/// This struct is also not [bar][b]
-///
-/// [b]: Bar
-pub struct Foo3;
-
-/// This struct is also not [`Bar`]
-pub struct Foo4;
-
-/// This struct *is* [`Bar`]!
-pub struct Bar;
-```
-
-Unlike normal Markdown, `[bar][Bar]` syntax is also supported without needing a
-`[Bar]: ...` reference link.
-
-Backticks around the link will be stripped, so ``[`Option`]`` will correctly
-link to `Option`.
-
-## Valid links
-
-You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and
-`crate`. Associated items (functions, types, and constants) are supported, but [not for blanket
-trait implementations][#79682]. Rustdoc also supports linking to all primitives listed in
-[the standard library documentation](../std/index.html#primitives).
-
-[#79682]: https://github.com/rust-lang/rust/pull/79682
-
-You can also refer to items with generic parameters like `Vec<T>`. The link will
-resolve as if you had written ``[`Vec<T>`](Vec)``. Fully-qualified syntax (for example,
-`<Vec as IntoIterator>::into_iter()`) is [not yet supported][fqs-issue], however.
-
-[fqs-issue]: https://github.com/rust-lang/rust/issues/74563
-
-```rust,edition2018
-use std::sync::mpsc::Receiver;
-
-/// This is a version of [`Receiver<T>`] with support for [`std::future`].
-///
-/// You can obtain a [`std::future::Future`] by calling [`Self::recv()`].
-pub struct AsyncReceiver<T> {
-    sender: Receiver<T>
-}
-
-impl<T> AsyncReceiver<T> {
-    pub async fn recv() -> T {
-        unimplemented!()
-    }
-}
-```
-
-Rustdoc allows using URL fragment specifiers, just like a normal link:
-
-```rust
-/// This is a special implementation of [positional parameters].
-///
-/// [positional parameters]: std::fmt#formatting-parameters
-struct MySpecialFormatter;
-```
-
-## Namespaces and Disambiguators
-
-Paths in Rust have three namespaces: type, value, and macro. Item names must be unique within
-their namespace, but can overlap with items in other namespaces. In case of ambiguity,
-rustdoc will warn about the ambiguity and suggest a disambiguator.
-
-```rust
-/// See also: [`Foo`](struct@Foo)
-struct Bar;
-
-/// This is different from [`Foo`](fn@Foo)
-struct Foo {}
-
-fn Foo() {}
-```
-
-These prefixes will be stripped when displayed in the documentation, so `[struct@Foo]` will be
-rendered as `Foo`.
-
-You can also disambiguate for functions by adding `()` after the function name,
-or for macros by adding `!` after the macro name:
-
-```rust
-/// This is different from [`foo!`]
-fn foo() {}
-
-/// This is different from [`foo()`]
-macro_rules! foo {
-  () => {}
-}
-```
-
-## Warnings, re-exports, and scoping
-
-Links are resolved in the scope of the module where the item is defined, even
-when the item is re-exported. If a link from another crate fails to resolve, no
-warning is given.
-
-```rust,edition2018
-mod inner {
-    /// Link to [f()]
-    pub struct S;
-    pub fn f() {}
-}
-pub use inner::S; // the link to `f` will still resolve correctly
-```
-
-When re-exporting an item, rustdoc allows adding additional documentation to it.
-That additional documentation will be resolved in the scope of the re-export, not
-the original, allowing you to link to items in the new crate. The new links
-will still give a warning if they fail to resolve.
-
-```rust
-/// See also [foo()]
-pub use std::process::Command;
-
-pub fn foo() {}
-```
-
-This is especially useful for proc-macros, which must always be defined in their own dedicated crate.
-
-Note: Because of how `macro_rules!` macros are scoped in Rust, the intra-doc links of a
-`macro_rules!` macro will be resolved [relative to the crate root][#72243], as opposed to the
-module it is defined in.
-
-If links do not look 'sufficiently like' an intra-doc link, they will be ignored and no warning
-will be given, even if the link fails to resolve. For example, any link containing `/` or `[]`
-characters will be ignored.
-
-[#72243]: https://github.com/rust-lang/rust/issues/72243
index 1773c15464a94680714452c2d32115ab492f98db..bff01d7cb7c14ef5a0544ff0089e30de545133a4 100644 (file)
@@ -13,11 +13,11 @@ Note that, except for `missing_docs`, these lints are only available when runnin
 
 Here is the list of the lints provided by `rustdoc`:
 
-## broken_intra_doc_links
+## `broken_intra_doc_links`
 
 This lint **warns by default**. This lint detects when an [intra-doc link] fails to be resolved. For example:
 
-[intra-doc link]: linking-to-items-by-name.md
+[intra-doc link]: write-documentation/linking-to-items-by-name.md
 
 ```rust
 /// I want to link to [`Nonexistent`] but it doesn't exist!
@@ -64,7 +64,7 @@ help: to link to the function, add parentheses
 
 ```
 
-## private_intra_doc_links
+## `private_intra_doc_links`
 
 This lint **warns by default**. This lint detects when [intra-doc links] from public to private items.
 For example:
@@ -104,9 +104,9 @@ warning: public documentation for `public` links to private item `private`
   = note: this link resolves only because you passed `--document-private-items`, but will break without
 ```
 
-[intra-doc links]: linking-to-items-by-name.html
+[intra-doc links]: write-documentation/linking-to-items-by-name.md
 
-## missing_docs
+## `missing_docs`
 
 This lint is **allowed by default**. It detects items missing documentation.
 For example:
@@ -130,7 +130,7 @@ warning: missing documentation for a function
 
 Note that unlike other rustdoc lints, this lint is also available from `rustc` directly.
 
-## missing_crate_level_docs
+## `missing_crate_level_docs`
 
 This lint is **allowed by default**. It detects if there is no documentation
 at the crate root. For example:
@@ -154,7 +154,7 @@ warning in the future. This is intended as a means to introduce new users on
 get started, without providing overwhelming warnings like `missing_docs`
 might.
 
-## missing_doc_code_examples
+## `missing_doc_code_examples`
 
 This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block
 is missing a code example. For example:
@@ -190,7 +190,7 @@ To fix the lint, you need to add a code example into the documentation block:
 pub fn no_code_example() {}
 ```
 
-## private_doc_tests
+## `private_doc_tests`
 
 This lint is **allowed by default**. It detects documentation tests when they
 are on a private item. For example:
@@ -223,7 +223,7 @@ warning: Documentation test in private item
    | |___________^
 ```
 
-## invalid_codeblock_attributes
+## `invalid_codeblock_attributes`
 
 This lint **warns by default**. It detects code block attributes in
 documentation examples that have potentially mis-typed values. For example:
@@ -259,7 +259,7 @@ warning: unknown attribute `should-panic`. Did you mean `should_panic`?
 In the example above, the correct form is `should_panic`. This helps detect
 typo mistakes for some common attributes.
 
-## invalid_html_tags
+## `invalid_html_tags`
 
 This lint is **allowed by default** and is **nightly-only**. It detects unclosed
 or invalid HTML tags. For example:
@@ -298,7 +298,7 @@ warning: unclosed HTML tag `h1`
 warning: 2 warnings emitted
 ```
 
-## invalid_rust_codeblocks
+## `invalid_rust_codeblocks`
 
 This lint **warns by default**. It detects Rust code blocks in documentation
 examples that are invalid (e.g. empty, not parsable as Rust). For example:
@@ -342,7 +342,7 @@ warning: could not parse code block as Rust code
    = note: error from rustc: unterminated character literal
 ```
 
-## bare_urls
+## `bare_urls`
 
 This lint is **warn-by-default**. It detects URLs which are not links.
 For example:
diff --git a/src/doc/rustdoc/src/passes.md b/src/doc/rustdoc/src/passes.md
deleted file mode 100644 (file)
index c3c3fd3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# Passes
-
-Rustdoc has a concept called "passes". These are transformations that
-`rustdoc` runs on your documentation before producing its final output.
-
-Customizing passes is **deprecated**. The available passes are not considered stable and may
-change in any release.
-
-In the past the most common use case for customizing passes was to omit the `strip-private` pass.
-You can do this more easily, and without risk of the pass being changed, by passing
-[`--document-private-items`](./unstable-features.md#--document-private-items).
diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md
deleted file mode 100644 (file)
index c5cc840..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-# The `#[doc]` attribute
-
-The `#[doc]` attribute lets you control various aspects of how `rustdoc` does
-its job.
-
-The most basic function of `#[doc]` is to handle the actual documentation
-text. That is, `///` is syntax sugar for `#[doc]`. This means that these two
-are the same:
-
-```rust,no_run
-/// This is a doc comment.
-#[doc = " This is a doc comment."]
-# fn f() {}
-```
-
-(Note the leading space in the attribute version.)
-
-In most cases, `///` is easier to use than `#[doc]`. One case where the latter is easier is
-when generating documentation in macros; the `collapse-docs` pass will combine multiple
-`#[doc]` attributes into a single doc comment, letting you generate code like this:
-
-```rust,no_run
-#[doc = "This is"]
-#[doc = " a "]
-#[doc = "doc comment"]
-# fn f() {}
-```
-
-Which can feel more flexible. Note that this would generate this:
-
-```rust,no_run
-#[doc = "This is\n a \ndoc comment"]
-# fn f() {}
-```
-
-but given that docs are rendered via Markdown, it will remove these newlines.
-
-Another use case is for including external files as documentation:
-
-```rust,no_run
-#[doc = include_str!("../README.md")]
-# fn f() {}
-```
-
-The `doc` attribute has more options though! These don't involve the text of
-the output, but instead, various aspects of the presentation of the output.
-We've split them into two kinds below: attributes that are useful at the
-crate level, and ones that are useful at the item level.
-
-## At the crate level
-
-These options control how the docs look at a crate level.
-
-### `html_favicon_url`
-
-This form of the `doc` attribute lets you control the favicon of your docs.
-
-```rust,no_run
-#![doc(html_favicon_url = "https://example.com/favicon.ico")]
-```
-
-This will put `<link rel="icon" href="{}">` into your docs, where
-the string for the attribute goes into the `{}`.
-
-If you don't use this attribute, there will be no favicon.
-
-### `html_logo_url`
-
-This form of the `doc` attribute lets you control the logo in the upper
-left hand side of the docs.
-
-```rust,no_run
-#![doc(html_logo_url = "https://example.com/logo.jpg")]
-```
-
-This will put `<a href='index.html'><img src='{}' alt='logo' width='100'></a>` into
-your docs, where the string for the attribute goes into the `{}`.
-
-If you don't use this attribute, there will be no logo.
-
-### `html_playground_url`
-
-This form of the `doc` attribute lets you control where the "run" buttons
-on your documentation examples make requests to.
-
-```rust,no_run
-#![doc(html_playground_url = "https://playground.example.com/")]
-```
-
-Now, when you press "run", the button will make a request to this domain.
-
-If you don't use this attribute, there will be no run buttons.
-
-### `issue_tracker_base_url`
-
-This form of the `doc` attribute is mostly only useful for the standard library;
-When a feature is unstable, an issue number for tracking the feature must be
-given. `rustdoc` uses this number, plus the base URL given here, to link to
-the tracking issue.
-
-```rust,no_run
-#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
-```
-
-### `html_root_url`
-
-The `#[doc(html_root_url = "…")]` attribute value indicates the URL for
-generating links to external crates. When rustdoc needs to generate a link to
-an item in an external crate, it will first check if the extern crate has been
-documented locally on-disk, and if so link directly to it. Failing that, it
-will use the URL given by the `--extern-html-root-url` command-line flag if
-available. If that is not available, then it will use the `html_root_url`
-value in the extern crate if it is available. If that is not available, then
-the extern items will not be linked.
-
-```rust,no_run
-#![doc(html_root_url = "https://docs.rs/serde/1.0")]
-```
-
-### `html_no_source`
-
-By default, `rustdoc` will include the source code of your program, with links
-to it in the docs. But if you include this:
-
-```rust,no_run
-#![doc(html_no_source)]
-```
-
-it will not.
-
-### `test(no_crate_inject)`
-
-By default, `rustdoc` will automatically add a line with `extern crate my_crate;` into each doctest.
-But if you include this:
-
-```rust,no_run
-#![doc(test(no_crate_inject))]
-```
-
-it will not.
-
-### `test(attr(...))`
-
-This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For
-example, if you want your doctests to fail if they produce any warnings, you could add this:
-
-```rust,no_run
-#![doc(test(attr(deny(warnings))))]
-```
-
-## At the item level
-
-These forms of the `#[doc]` attribute are used on individual items, to control how
-they are documented.
-
-### `inline` and `no_inline`
-
-<span id="docno_inlinedocinline"></span>
-
-These attributes are used on `use` statements, and control where the documentation shows
-up. For example, consider this Rust code:
-
-```rust,no_run
-pub use bar::Bar;
-
-/// bar docs
-pub mod bar {
-    /// the docs for Bar
-    pub struct Bar;
-}
-# fn main() {}
-```
-
-The documentation will generate a "Re-exports" section, and say `pub use bar::Bar;`, where
-`Bar` is a link to its page.
-
-If we change the `use` line like this:
-
-```rust,no_run
-#[doc(inline)]
-pub use bar::Bar;
-# pub mod bar { pub struct Bar; }
-# fn main() {}
-```
-
-Instead, `Bar` will appear in a `Structs` section, just like `Bar` was defined at the
-top level, rather than `pub use`'d.
-
-Let's change our original example, by making `bar` private:
-
-```rust,no_run
-pub use bar::Bar;
-
-/// bar docs
-mod bar {
-    /// the docs for Bar
-    pub struct Bar;
-}
-# fn main() {}
-```
-
-Here, because `bar` is not public, `Bar` wouldn't have its own page, so there's nowhere
-to link to. `rustdoc` will inline these definitions, and so we end up in the same case
-as the `#[doc(inline)]` above; `Bar` is in a `Structs` section, as if it were defined at
-the top level. If we add the `no_inline` form of the attribute:
-
-```rust,no_run
-#[doc(no_inline)]
-pub use bar::Bar;
-
-/// bar docs
-mod bar {
-    /// the docs for Bar
-    pub struct Bar;
-}
-# fn main() {}
-```
-
-Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere.
-
-One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will
-not eagerly inline it as a module unless you add `#[doc(inline)]`.
-
-### `hidden`
-
-<span id="dochidden"></span>
-
-Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless
-the `strip-hidden` pass is removed.
-
-### `alias`
-
-This attribute adds an alias in the search index.
-
-Let's take an example:
-
-```rust,no_run
-#[doc(alias = "TheAlias")]
-pub struct SomeType;
-```
-
-So now, if you enter "TheAlias" in the search, it'll display `SomeType`.
-Of course, if you enter `SomeType` it'll return `SomeType` as expected!
-
-#### FFI example
-
-This doc attribute is especially useful when writing bindings for a C library.
-For example, let's say we have a C function that looks like this:
-
-```c
-int lib_name_do_something(Obj *obj);
-```
-
-It takes a pointer to an `Obj` type and returns an integer. In Rust, it might
-be written like this:
-
-```ignore (using non-existing ffi types)
-pub struct Obj {
-    inner: *mut ffi::Obj,
-}
-
-impl Obj {
-    pub fn do_something(&mut self) -> i32 {
-        unsafe { ffi::lib_name_do_something(self.inner) }
-    }
-}
-```
-
-The function has been turned into a method to make it more convenient to use.
-However, if you want to look for the Rust equivalent of `lib_name_do_something`,
-you have no way to do so.
-
-To get around this limitation, we just add `#[doc(alias = "lib_name_do_something")]`
-on the `do_something` method and then it's all good!
-Users can now look for `lib_name_do_something` in our crate directly and find
-`Obj::do_something`.
index 141d5d2d2b2d0fec9a8802eedaee1cf7d5cf3919..537ab48bbfc12a457dc3e49afb879e203cdb6754 100644 (file)
@@ -22,7 +22,7 @@ As detailed in [the chapter on documentation tests][doctest-attributes], you can
 nightly, you can optionally add an error number to state that a doctest should emit a specific error
 number:
 
-[doctest-attributes]: documentation-tests.html#attributes
+[doctest-attributes]: write-documentation/documentation-tests.html#attributes
 
 ``````markdown
 ```compile_fail,E0044
@@ -45,6 +45,8 @@ and enabled with a `#![feature(...)]` attribute in your crate.
 
 ### `#[doc(cfg)]`: Recording what platforms or features are required for code to be present
 
+ * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781)
+
 You can use `#[doc(cfg(...))]` to tell Rustdoc exactly which platform items appear on.
 This has two effects:
 
@@ -86,6 +88,8 @@ Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg].
 
 ### `doc_auto_cfg`: Automatically generate `#[doc(cfg)]`
 
+ * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781)
+
 `doc_auto_cfg` is an extension to the `#[doc(cfg)]` feature. With it, you don't need to add
 `#[doc(cfg(...)]` anymore unless you want to override the default behaviour. So if we take the
 previous source code:
@@ -123,6 +127,8 @@ And `doc` won't show up anymore!
 
 ### Adding your trait to the "Notable traits" dialog
 
+ * Tracking issue: [#45040](https://github.com/rust-lang/rust/issues/45040)
+
 Rustdoc keeps a list of a few traits that are believed to be "fundamental" to
 types that implement them. These traits are intended to be the primary interface
 for their implementers, and are often most of the API available to be documented
@@ -146,6 +152,8 @@ and [its tracking issue][issue-notable_trait].
 
 ### Exclude certain dependencies from documentation
 
+ * Tracking issue: [#44027](https://github.com/rust-lang/rust/issues/44027)
+
 The standard library uses several dependencies which, in turn, use several types and traits from the
 standard library. In addition, there are several compiler-internal crates that are not considered to
 be part of the official standard library, and thus would be a distraction to include in
@@ -164,8 +172,7 @@ Book][unstable-masked] and [its tracking issue][issue-masked].
 [unstable-masked]: ../unstable-book/language-features/doc-masked.html
 [issue-masked]: https://github.com/rust-lang/rust/issues/44027
 
-
-## Document primitives
+### Document primitives
 
 This is for Rust compiler internal use only.
 
@@ -174,7 +181,7 @@ attributes. The `#[doc(primitive)]` attribute is used by the standard library to
 to generate documentation for primitive types, and requires `#![feature(rustdoc_internals)]` to
 enable.
 
-## Document keywords
+### Document keywords
 
 This is for Rust compiler internal use only.
 
@@ -199,6 +206,8 @@ the flag in question to Rustdoc on the command-line. To do this from Cargo, you
 
 ### `--markdown-before-content`: include rendered Markdown before the content
 
+ * Tracking issue: [#44027](https://github.com/rust-lang/rust/issues/44027)
+
 Using this flag looks like this:
 
 ```bash
@@ -241,7 +250,7 @@ attribute][doc-playground]. Please be aware that the official Rust Playground at
 https://play.rust-lang.org does not have every crate available, so if your examples require your
 crate, make sure the playground you provide has your crate available.
 
-[doc-playground]: the-doc-attribute.html#html_playground_url
+[doc-playground]: write-documentation/the-doc-attribute.html#html_playground_url
 
 If both `--playground-url` and `--markdown-playground-url` are present when rendering a standalone
 Markdown file, the URL given to `--markdown-playground-url` will take precedence. If both
@@ -279,6 +288,8 @@ between compilations.
 
 ### `--resource-suffix`: modifying the name of CSS/JavaScript in crate docs
 
+ * Tracking issue: [#54765](https://github.com/rust-lang/rust/issues/54765)
+
 Using this flag looks like this:
 
 ```bash
@@ -331,6 +342,24 @@ Using `index-page` option enables `enable-index-page` option as well.
 
 This feature allows the generation of a default index-page which lists the generated crates.
 
+### `--nocapture`: disable output capture for test
+
+When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be
+captured by rustdoc. Instead, the output will be directed to your terminal,
+as if you had run the test executable manually. This is especially useful
+for debugging your tests!
+
+### `--check`: only checks the documentation
+
+When this flag is supplied, rustdoc will type check and lint your code, but will not generate any
+documentation or run your doctests.
+
+Using this flag looks like:
+
+```bash
+rustdoc -Z unstable-options --check src/lib.rs
+```
+
 ### `--static-root-path`: control how static files are loaded in HTML output
 
 Using this flag looks like this:
@@ -348,6 +377,8 @@ renamed with `--resource-suffix` will load from the given path.
 
 ### `--persist-doctests`: persist doctest executables after running
 
+ * Tracking issue: [#56925](https://github.com/rust-lang/rust/issues/56925)
+
 Using this flag looks like this:
 
 ```bash
@@ -360,6 +391,8 @@ with this option, you can keep those binaries around for farther testing.
 
 ### `--show-coverage`: calculate the percentage of items with documentation
 
+ * Tracking issue: [#58154](https://github.com/rust-lang/rust/issues/58154)
+
 Using this flag looks like this:
 
 ```bash
@@ -438,6 +471,8 @@ information.
 
 ### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests
 
+ * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)
+
 Using this flag looks like this:
 
 ```bash
@@ -471,6 +506,8 @@ override `ignore`.
 
 ### `--runtool`, `--runtool-arg`: program to run tests with; args to pass to it
 
+ * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)
+
 Using these options looks like this:
 
 ```bash
@@ -488,6 +525,8 @@ Another use case would be to run a test inside an emulator, or through a Virtual
 
 ### `--with-examples`: include examples of uses of items as documentation
 
+ * Tracking issue: [#88791](https://github.com/rust-lang/rust/issues/88791)
+
 This option, combined with `--scrape-examples-target-crate` and
 `--scrape-examples-output-path`, is used to implement the functionality in [RFC
 #3123](https://github.com/rust-lang/rfcs/pull/3123). Uses of an item (currently
@@ -515,6 +554,8 @@ add the `--scrape-tests` flag.
 
 ### `--check-cfg`: check configuration flags
 
+ * Tracking issue: [#82450](https://github.com/rust-lang/rust/issues/82450)
+
 This flag accepts the same values as `rustc --check-cfg`, and uses it to check configuration flags.
 
 Using this flag looks like this:
diff --git a/src/doc/rustdoc/src/website-features.md b/src/doc/rustdoc/src/website-features.md
deleted file mode 100644 (file)
index 5fade4e..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# Website features
-
-These features are about using the website generated by `rustdoc`.
-
-## Custom search engines
-
-If you find yourself often referencing online Rust docs you might enjoy using a custom search
-engine. This allows you to use the navigation bar directly to search a `rustdoc` website.
-Most browsers support this feature by letting you define a URL template containing `%s`
-which will be substituted for the search term. As an example, for the standard library you could use
-this template:
-
-```text
-https://doc.rust-lang.org/stable/std/?search=%s
-```
-
-Note that this will take you to a results page listing all matches. If you want to navigate to the first
-result right away (which is often the best match) use the following instead:
-
-```text
-https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
-```
-
-This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
-to automatically go to the first result.
diff --git a/src/doc/rustdoc/src/what-to-include.md b/src/doc/rustdoc/src/what-to-include.md
deleted file mode 100644 (file)
index 2a6b62e..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-# What to include (and exclude)
-
-It is easy to say everything must be documented in a project and often times
-that is correct, but how can we get there, and are there things that don't
-belong?
-
-At the top of the `src/lib.rs` or `main.rs` file in your binary project, include
-the following attribute:
-
-```rust
-#![warn(missing_docs)]
-```
-
-Now run `cargo doc` and examine the output.  Here's a sample:
-
-```text
- Documenting docdemo v0.1.0 (/Users/username/docdemo)
-warning: missing documentation for the crate
- --> src/main.rs:1:1
-  |
-1 | / #![warn(missing_docs)]
-2 | |
-3 | | fn main() {
-4 | |     println!("Hello, world!");
-5 | | }
-  | |_^
-  |
-note: the lint level is defined here
- --> src/main.rs:1:9
-  |
-1 | #![warn(missing_docs)]
-  |         ^^^^^^^^^^^^
-
-warning: 1 warning emitted
-
-    Finished dev [unoptimized + debuginfo] target(s) in 2.96s
-```
-
-As a library author, adding the lint `#![deny(missing_docs)]` is a great way to
-ensure the project does not drift away from being documented well, and
-`#![warn(missing_docs)]` is a good way to move towards comprehensive
-documentation.  In addition to docs, `#![deny(missing_doc_code_examples)]`
-ensures each function contains a usage example.  In our example above, the
-warning is resolved by adding crate level documentation.
-
-There are more lints in the upcoming chapter [Lints][rustdoc-lints].
-
-## Examples
-
-Of course this is contrived to be simple, but part of the power of documentation
-is showing code that is easy to follow, rather than being realistic.  Docs often
-take shortcuts with error handling because examples can become complicated to
-follow with all the necessary set up required for a simple example.
-
-`Async` is a good example of this.  In order to execute an `async` example, an
-executor needs to be available.  Examples will often shortcut this, and leave
-users to figure out how to put the `async` code into their own runtime.
-
-It is preferred that `unwrap()` not be used inside an example, and some of the
-error handling components be hidden if they make the example too difficult to
-follow.
-
-``````text
-/// Example
-/// ```rust
-/// let fourtytwo = "42".parse::<u32>()?;
-/// println!("{} + 10 = {}", fourtytwo, fourtytwo+10);
-/// ```
-``````
-
-When rustdoc wraps that in a main function, it will fail to compile because the
-`ParseIntError` trait is not implemented.  In order to help both your audience
-and your test suite, this example needs some additional code:
-
-``````text
-/// Example
-/// ```rust
-/// # main() -> Result<(), std::num::ParseIntError> {
-/// let fortytwo = "42".parse::<u32>()?;
-/// println!("{} + 10 = {}", fortytwo, fortytwo+10);
-/// #     Ok(())
-/// # }
-/// ```
-``````
-
-The example is the same on the doc page, but has that extra information
-available to anyone trying to use your crate.  More about tests in the
-upcoming [Documentation tests] chapter.
-
-## What to Exclude
-
-Certain parts of your public interface may be included by default in the output
-of rustdoc.  The attribute `#[doc(hidden)]` can hide implementation details
-to encourage idiomatic use of the crate.
-
-For example, an internal `macro!` that makes the crate easier to implement can
-become a footgun for users when it appears in the public documentation.  An
-internal `Error` type may exist, and `impl` details should be hidden, as
-detailed in the [API Guidelines].
-
-## Customizing the output
-
-It is possible to pass a custom css file to `rustdoc` and style the
-documentation.
-
-```bash
-rustdoc --extend-css custom.css src/lib.rs
-```
-
-A good example of using this feature to create a dark theme is documented [on
-this blog].  Just remember, dark theme is already included in the rustdoc output
-by clicking on the paintbrush.  Adding additional options to the themes are
-as easy as creating a custom theme `.css` file and using the following syntax:
-
-```bash
-rustdoc --theme awesome.css src/lib.rs
-```
-
-Here is an example of a new theme, [Ayu].
-
-[Ayu]: https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/static/css/themes/ayu.css
-[API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html#rustdoc-does-not-show-unhelpful-implementation-details-c-hidden
-[Documentation tests]: documentation-tests.md
-[on this blog]: https://blog.guillaume-gomez.fr/articles/2016-09-16+Generating+doc+with+rustdoc+and+a+custom+theme
-[rustdoc-lints]: lints.md
diff --git a/src/doc/rustdoc/src/write-documentation/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
new file mode 100644 (file)
index 0000000..1cb5b04
--- /dev/null
@@ -0,0 +1,445 @@
+# Documentation tests
+
+`rustdoc` supports executing your documentation examples as tests. This makes sure
+that examples within your documentation are up to date and working.
+
+The basic idea is this:
+
+```rust,no_run
+/// # Examples
+///
+/// ```
+/// let x = 5;
+/// ```
+# fn f() {}
+```
+
+The triple backticks start and end code blocks. If this were in a file named `foo.rs`,
+running `rustdoc --test foo.rs` will extract this example, and then run it as a test.
+
+Please note that by default, if no language is set for the block code, rustdoc
+assumes it is Rust code. So the following:
+
+``````markdown
+```rust
+let x = 5;
+```
+``````
+
+is strictly equivalent to:
+
+``````markdown
+```
+let x = 5;
+```
+``````
+
+There's some subtlety though! Read on for more details.
+
+## Passing or failing a doctest
+
+Like regular unit tests, regular doctests are considered to "pass"
+if they compile and run without panicking.
+So if you want to demonstrate that some computation gives a certain result,
+the `assert!` family of macros works the same as other Rust code:
+
+```rust
+let foo = "foo";
+assert_eq!(foo, "foo");
+```
+
+This way, if the computation ever returns something different,
+the code panics and the doctest fails.
+
+## Pre-processing examples
+
+In the example above, you'll note something strange: there's no `main`
+function! Forcing you to write `main` for every example, no matter how small,
+adds friction and clutters the output. So `rustdoc` processes your examples
+slightly before running them. Here's the full algorithm `rustdoc` uses to
+preprocess examples:
+
+1. Some common `allow` attributes are inserted, including
+   `unused_variables`, `unused_assignments`, `unused_mut`,
+   `unused_attributes`, and `dead_code`. Small examples often trigger
+   these lints.
+2. Any attributes specified with `#![doc(test(attr(...)))]` are added.
+3. Any leading `#![foo]` attributes are left intact as crate attributes.
+4. If the example does not contain `extern crate`, and
+   `#![doc(test(no_crate_inject))]` was not specified, then `extern crate
+   <mycrate>;` is inserted (note the lack of `#[macro_use]`).
+5. Finally, if the example does not contain `fn main`, the remainder of the
+   text is wrapped in `fn main() { your_code }`.
+
+For more about that caveat in rule 4, see "Documenting Macros" below.
+
+## Hiding portions of the example
+
+Sometimes, you need some setup code, or other things that would distract
+from your example, but are important to make the tests work. Consider
+an example block that looks like this:
+
+```rust,no_run
+/// ```
+/// /// Some documentation.
+/// # fn foo() {} // this function will be hidden
+/// println!("Hello, World!");
+/// ```
+# fn f() {}
+```
+
+It will render like this:
+
+```rust
+/// Some documentation.
+# fn foo() {}
+println!("Hello, World!");
+```
+
+Yes, that's right: you can add lines that start with `# `, and they will
+be hidden from the output, but will be used when compiling your code. You
+can use this to your advantage. In this case, documentation comments need
+to apply to some kind of function, so if I want to show you just a
+documentation comment, I need to add a little function definition below
+it. At the same time, it's only there to satisfy the compiler, so hiding
+it makes the example more clear. You can use this technique to explain
+longer examples in detail, while still preserving the testability of your
+documentation.
+
+For example, imagine that we wanted to document this code:
+
+```rust
+let x = 5;
+let y = 6;
+println!("{}", x + y);
+```
+
+We might want the documentation to end up looking like this:
+
+> First, we set `x` to five:
+>
+> ```rust
+> let x = 5;
+> # let y = 6;
+> # println!("{}", x + y);
+> ```
+>
+> Next, we set `y` to six:
+>
+> ```rust
+> # let x = 5;
+> let y = 6;
+> # println!("{}", x + y);
+> ```
+>
+> Finally, we print the sum of `x` and `y`:
+>
+> ```rust
+> # let x = 5;
+> # let y = 6;
+> println!("{}", x + y);
+> ```
+
+To keep each code block testable, we want the whole program in each block, but
+we don't want the reader to see every line every time.  Here's what we put in
+our source code:
+
+``````markdown
+First, we set `x` to five:
+
+```
+let x = 5;
+# let y = 6;
+# println!("{}", x + y);
+```
+
+Next, we set `y` to six:
+
+```
+# let x = 5;
+let y = 6;
+# println!("{}", x + y);
+```
+
+Finally, we print the sum of `x` and `y`:
+
+```
+# let x = 5;
+# let y = 6;
+println!("{}", x + y);
+```
+``````
+
+By repeating all parts of the example, you can ensure that your example still
+compiles, while only showing the parts that are relevant to that part of your
+explanation.
+
+The `#`-hiding of lines can be prevented by using two consecutive hashes
+`##`. This only needs to be done with the first `#` which would've
+otherwise caused hiding. If we have a string literal like the following,
+which has a line that starts with a `#`:
+
+```rust
+let s = "foo
+## bar # baz";
+```
+
+We can document it by escaping the initial `#`:
+
+```text
+/// let s = "foo
+/// ## bar # baz";
+```
+
+
+## Using `?` in doc tests
+
+When writing an example, it is rarely useful to include a complete error
+handling, as it would add significant amounts of boilerplate code. Instead, you
+may want the following:
+
+```rust,no_run
+/// ```
+/// use std::io;
+/// let mut input = String::new();
+/// io::stdin().read_line(&mut input)?;
+/// ```
+# fn f() {}
+```
+
+The problem is that `?` returns a `Result<T, E>` and test functions don't
+return anything, so this will give a mismatched types error.
+
+You can get around this limitation by manually adding a `main` that returns
+`Result<T, E>`, because `Result<T, E>` implements the `Termination` trait:
+
+```rust,no_run
+/// A doc test using ?
+///
+/// ```
+/// use std::io;
+///
+/// fn main() -> io::Result<()> {
+///     let mut input = String::new();
+///     io::stdin().read_line(&mut input)?;
+///     Ok(())
+/// }
+/// ```
+# fn f() {}
+```
+
+Together with the `# ` from the section above, you arrive at a solution that
+appears to the reader as the initial idea but works with doc tests:
+
+```rust,no_run
+/// ```
+/// use std::io;
+/// # fn main() -> io::Result<()> {
+/// let mut input = String::new();
+/// io::stdin().read_line(&mut input)?;
+/// # Ok(())
+/// # }
+/// ```
+# fn f() {}
+```
+
+As of version 1.34.0, one can also omit the `fn main()`, but you will have to
+disambiguate the error type:
+
+```rust,no_run
+/// ```
+/// use std::io;
+/// let mut input = String::new();
+/// io::stdin().read_line(&mut input)?;
+/// # Ok::<(), io::Error>(())
+/// ```
+# fn f() {}
+```
+
+This is an unfortunate consequence of the `?` operator adding an implicit
+conversion, so type inference fails because the type is not unique. Please note
+that you must write the `(())` in one sequence without intermediate whitespace
+so that `rustdoc` understands you want an implicit `Result`-returning function.
+
+## Showing warnings in doctests
+
+You can show warnings in doctests by running `rustdoc --test --test-args=--show-output`
+(or, if you're using cargo, `cargo test --doc -- --show-output`).
+By default, this will still hide `unused` warnings, since so many examples use private functions;
+you can add `#![warn(unused)]` to the top of your example if you want to see unused variables or dead code warnings.
+You can also use [`#![doc(test(attr(warn(unused))))]`][test-attr] in the crate root to enable warnings globally.
+
+[test-attr]: the-doc-attribute.md#testattr
+
+## Documenting macros
+
+Here’s an example of documenting a macro:
+
+```rust
+/// Panic with a given message unless an expression evaluates to true.
+///
+/// # Examples
+///
+/// ```
+/// # #[macro_use] extern crate foo;
+/// # fn main() {
+/// panic_unless!(1 + 1 == 2, “Math is broken.”);
+/// # }
+/// ```
+///
+/// ```should_panic
+/// # #[macro_use] extern crate foo;
+/// # fn main() {
+/// panic_unless!(true == false, “I’m broken.”);
+/// # }
+/// ```
+#[macro_export]
+macro_rules! panic_unless {
+    ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } });
+}
+# fn main() {}
+```
+
+You’ll note three things: we need to add our own `extern crate` line, so that
+we can add the `#[macro_use]` attribute. Second, we’ll need to add our own
+`main()` as well (for reasons discussed above). Finally, a judicious use of
+`#` to comment out those two things, so they don’t show up in the output.
+
+## Attributes
+
+Code blocks can be annotated with attributes that help `rustdoc` do the right
+thing when testing your code:
+
+The `ignore` attribute tells Rust to ignore your code. This is almost never
+what you want as it's the most generic. Instead, consider annotating it
+with `text` if it's not code or using `#`s to get a working example that
+only shows the part you care about.
+
+```rust
+/// ```ignore
+/// fn foo() {
+/// ```
+# fn foo() {}
+```
+
+`should_panic` tells `rustdoc` that the code should compile correctly but
+panic during execution. If the code doesn't panic, the test will fail.
+
+```rust
+/// ```should_panic
+/// assert!(false);
+/// ```
+# fn foo() {}
+```
+
+The `no_run` attribute will compile your code but not run it. This is
+important for examples such as "Here's how to retrieve a web page,"
+which you would want to ensure compiles, but might be run in a test
+environment that has no network access. This attribute can also be
+used to demonstrate code snippets that can cause Undefined Behavior.
+
+```rust
+/// ```no_run
+/// loop {
+///     println!("Hello, world");
+/// }
+/// ```
+# fn foo() {}
+```
+
+`compile_fail` tells `rustdoc` that the compilation should fail. If it
+compiles, then the test will fail. However, please note that code failing
+with the current Rust release may work in a future release, as new features
+are added.
+
+```rust
+/// ```compile_fail
+/// let x = 5;
+/// x += 2; // shouldn't compile!
+/// ```
+# fn foo() {}
+```
+
+`edition2015`, `edition2018` and `edition2021` tell `rustdoc`
+that the code sample should be compiled using the respective edition of Rust.
+
+```rust
+/// Only runs on the 2018 edition.
+///
+/// ```edition2018
+/// let result: Result<i32, ParseIntError> = try {
+///     "1".parse::<i32>()?
+///         + "2".parse::<i32>()?
+///         + "3".parse::<i32>()?
+/// };
+/// ```
+# fn foo() {}
+```
+
+## Syntax reference
+
+The *exact* syntax for code blocks, including the edge cases, can be found
+in the [Fenced Code Blocks](https://spec.commonmark.org/0.29/#fenced-code-blocks)
+section of the CommonMark specification.
+
+Rustdoc also accepts *indented* code blocks as an alternative to fenced
+code blocks: instead of surrounding your code with three backticks, you
+can indent each line by four or more spaces.
+
+``````markdown
+    let foo = "foo";
+    assert_eq!(foo, "foo");
+``````
+
+These, too, are documented in the CommonMark specification, in the
+[Indented Code Blocks](https://spec.commonmark.org/0.29/#indented-code-blocks)
+section.
+
+However, it's preferable to use fenced code blocks over indented code blocks.
+Not only are fenced code blocks considered more idiomatic for Rust code,
+but there is no way to use attributes such as `ignore` or `should_panic` with
+indented code blocks.
+
+### Include items only when collecting doctests
+
+Rustdoc's documentation tests can do some things that regular unit tests can't, so it can
+sometimes be useful to extend your doctests with samples that wouldn't otherwise need to be in
+documentation. To this end, Rustdoc allows you to have certain items only appear when it's
+collecting doctests, so you can utilize doctest functionality without forcing the test to appear in
+docs, or to find an arbitrary private item to include it on.
+
+When compiling a crate for use in doctests (with `--test` option), `rustdoc` will set `#[cfg(doctest)]`.
+Note that they will still link against only the public items of your crate; if you need to test
+private items, you need to write a unit test.
+
+In this example, we're adding doctests that we know won't compile, to verify that our struct can
+only take in valid data:
+
+```rust
+/// We have a struct here. Remember it doesn't accept negative numbers!
+pub struct MyStruct(pub usize);
+
+/// ```compile_fail
+/// let x = my_crate::MyStruct(-5);
+/// ```
+#[cfg(doctest)]
+pub struct MyStructOnlyTakesUsize;
+```
+
+Note that the struct `MyStructOnlyTakesUsize` here isn't actually part of your public crate
+API. The use of `#[cfg(doctest)]` makes sure that this struct only exists while `rustdoc` is
+collecting doctests. This means that its doctest is executed when `--test` is passed to rustdoc,
+but is hidden from the public documentation.
+
+Another possible use of `#[cfg(doctest)]` is to test doctests that are included in your README file
+without including it in your main documentation. For example, you could write this into your
+`lib.rs` to test your README as part of your doctests:
+
+```rust,no_run
+#[doc = include_str!("../README.md")]
+#[cfg(doctest)]
+pub struct ReadmeDoctests;
+```
+
+This will include your README as documentation on the hidden struct `ReadmeDoctests`, which will
+then be tested alongside the rest of your doctests.
diff --git a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md
new file mode 100644 (file)
index 0000000..36bc312
--- /dev/null
@@ -0,0 +1,143 @@
+# Linking to items by name
+
+Rustdoc is capable of directly linking to other rustdoc pages using the path of
+the item as a link. This is referred to as an 'intra-doc link'.
+
+For example, in the following code all of the links will link to the rustdoc page for `Bar`:
+
+```rust
+/// This struct is not [Bar]
+pub struct Foo1;
+
+/// This struct is also not [bar](Bar)
+pub struct Foo2;
+
+/// This struct is also not [bar][b]
+///
+/// [b]: Bar
+pub struct Foo3;
+
+/// This struct is also not [`Bar`]
+pub struct Foo4;
+
+/// This struct *is* [`Bar`]!
+pub struct Bar;
+```
+
+Unlike normal Markdown, `[bar][Bar]` syntax is also supported without needing a
+`[Bar]: ...` reference link.
+
+Backticks around the link will be stripped, so ``[`Option`]`` will correctly
+link to `Option`.
+
+## Valid links
+
+You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and
+`crate`. Associated items (functions, types, and constants) are supported, but [not for blanket
+trait implementations][#79682]. Rustdoc also supports linking to all primitives listed in
+[the standard library documentation](../../std/index.html#primitives).
+
+[#79682]: https://github.com/rust-lang/rust/pull/79682
+
+You can also refer to items with generic parameters like `Vec<T>`. The link will
+resolve as if you had written ``[`Vec<T>`](Vec)``. Fully-qualified syntax (for example,
+`<Vec as IntoIterator>::into_iter()`) is [not yet supported][fqs-issue], however.
+
+[fqs-issue]: https://github.com/rust-lang/rust/issues/74563
+
+```rust,edition2018
+use std::sync::mpsc::Receiver;
+
+/// This is a version of [`Receiver<T>`] with support for [`std::future`].
+///
+/// You can obtain a [`std::future::Future`] by calling [`Self::recv()`].
+pub struct AsyncReceiver<T> {
+    sender: Receiver<T>
+}
+
+impl<T> AsyncReceiver<T> {
+    pub async fn recv() -> T {
+        unimplemented!()
+    }
+}
+```
+
+Rustdoc allows using URL fragment specifiers, just like a normal link:
+
+```rust
+/// This is a special implementation of [positional parameters].
+///
+/// [positional parameters]: std::fmt#formatting-parameters
+struct MySpecialFormatter;
+```
+
+## Namespaces and Disambiguators
+
+Paths in Rust have three namespaces: type, value, and macro. Item names must be unique within
+their namespace, but can overlap with items in other namespaces. In case of ambiguity,
+rustdoc will warn about the ambiguity and suggest a disambiguator.
+
+```rust
+/// See also: [`Foo`](struct@Foo)
+struct Bar;
+
+/// This is different from [`Foo`](fn@Foo)
+struct Foo {}
+
+fn Foo() {}
+```
+
+These prefixes will be stripped when displayed in the documentation, so `[struct@Foo]` will be
+rendered as `Foo`.
+
+You can also disambiguate for functions by adding `()` after the function name,
+or for macros by adding `!` after the macro name:
+
+```rust
+/// This is different from [`foo!`]
+fn foo() {}
+
+/// This is different from [`foo()`]
+macro_rules! foo {
+  () => {}
+}
+```
+
+## Warnings, re-exports, and scoping
+
+Links are resolved in the scope of the module where the item is defined, even
+when the item is re-exported. If a link from another crate fails to resolve, no
+warning is given.
+
+```rust,edition2018
+mod inner {
+    /// Link to [f()]
+    pub struct S;
+    pub fn f() {}
+}
+pub use inner::S; // the link to `f` will still resolve correctly
+```
+
+When re-exporting an item, rustdoc allows adding additional documentation to it.
+That additional documentation will be resolved in the scope of the re-export, not
+the original, allowing you to link to items in the new crate. The new links
+will still give a warning if they fail to resolve.
+
+```rust
+/// See also [foo()]
+pub use std::process::Command;
+
+pub fn foo() {}
+```
+
+This is especially useful for proc-macros, which must always be defined in their own dedicated crate.
+
+Note: Because of how `macro_rules!` macros are scoped in Rust, the intra-doc links of a
+`macro_rules!` macro will be resolved [relative to the crate root][#72243], as opposed to the
+module it is defined in.
+
+If links do not look 'sufficiently like' an intra-doc link, they will be ignored and no warning
+will be given, even if the link fails to resolve. For example, any link containing `/` or `[]`
+characters will be ignored.
+
+[#72243]: https://github.com/rust-lang/rust/issues/72243
diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md
new file mode 100644 (file)
index 0000000..25ef8b5
--- /dev/null
@@ -0,0 +1,276 @@
+# The `#[doc]` attribute
+
+The `#[doc]` attribute lets you control various aspects of how `rustdoc` does
+its job.
+
+The most basic function of `#[doc]` is to handle the actual documentation
+text. That is, `///` is syntax sugar for `#[doc]`. This means that these two
+are the same:
+
+```rust,no_run
+/// This is a doc comment.
+#[doc = " This is a doc comment."]
+# fn f() {}
+```
+
+(Note the leading space in the attribute version.)
+
+In most cases, `///` is easier to use than `#[doc]`. One case where the latter is easier is
+when generating documentation in macros; the `collapse-docs` pass will combine multiple
+`#[doc]` attributes into a single doc comment, letting you generate code like this:
+
+```rust,no_run
+#[doc = "This is"]
+#[doc = " a "]
+#[doc = "doc comment"]
+# fn f() {}
+```
+
+Which can feel more flexible. Note that this would generate this:
+
+```rust,no_run
+#[doc = "This is\n a \ndoc comment"]
+# fn f() {}
+```
+
+but given that docs are rendered via Markdown, it will remove these newlines.
+
+Another use case is for including external files as documentation:
+
+```rust,no_run
+#[doc = include_str!("../../README.md")]
+# fn f() {}
+```
+
+The `doc` attribute has more options though! These don't involve the text of
+the output, but instead, various aspects of the presentation of the output.
+We've split them into two kinds below: attributes that are useful at the
+crate level, and ones that are useful at the item level.
+
+## At the crate level
+
+These options control how the docs look at a crate level.
+
+### `html_favicon_url`
+
+This form of the `doc` attribute lets you control the favicon of your docs.
+
+```rust,no_run
+#![doc(html_favicon_url = "https://example.com/favicon.ico")]
+```
+
+This will put `<link rel="icon" href="{}">` into your docs, where
+the string for the attribute goes into the `{}`.
+
+If you don't use this attribute, there will be no favicon.
+
+### `html_logo_url`
+
+This form of the `doc` attribute lets you control the logo in the upper
+left hand side of the docs.
+
+```rust,no_run
+#![doc(html_logo_url = "https://example.com/logo.jpg")]
+```
+
+This will put `<a href='../index.html'><img src='{}' alt='logo' width='100'></a>` into
+your docs, where the string for the attribute goes into the `{}`.
+
+If you don't use this attribute, there will be no logo.
+
+### `html_playground_url`
+
+This form of the `doc` attribute lets you control where the "run" buttons
+on your documentation examples make requests to.
+
+```rust,no_run
+#![doc(html_playground_url = "https://playground.example.com/")]
+```
+
+Now, when you press "run", the button will make a request to this domain.
+
+If you don't use this attribute, there will be no run buttons.
+
+### `issue_tracker_base_url`
+
+This form of the `doc` attribute is mostly only useful for the standard library;
+When a feature is unstable, an issue number for tracking the feature must be
+given. `rustdoc` uses this number, plus the base URL given here, to link to
+the tracking issue.
+
+```rust,no_run
+#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
+```
+
+### `html_root_url`
+
+The `#[doc(html_root_url = "…")]` attribute value indicates the URL for
+generating links to external crates. When rustdoc needs to generate a link to
+an item in an external crate, it will first check if the extern crate has been
+documented locally on-disk, and if so link directly to it. Failing that, it
+will use the URL given by the `--extern-html-root-url` command-line flag if
+available. If that is not available, then it will use the `html_root_url`
+value in the extern crate if it is available. If that is not available, then
+the extern items will not be linked.
+
+```rust,no_run
+#![doc(html_root_url = "https://docs.rs/serde/1.0")]
+```
+
+### `html_no_source`
+
+By default, `rustdoc` will include the source code of your program, with links
+to it in the docs. But if you include this:
+
+```rust,no_run
+#![doc(html_no_source)]
+```
+
+it will not.
+
+### `test(no_crate_inject)`
+
+By default, `rustdoc` will automatically add a line with `extern crate my_crate;` into each doctest.
+But if you include this:
+
+```rust,no_run
+#![doc(test(no_crate_inject))]
+```
+
+it will not.
+
+### `test(attr(...))`
+
+This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For
+example, if you want your doctests to fail if they produce any warnings, you could add this:
+
+```rust,no_run
+#![doc(test(attr(deny(warnings))))]
+```
+
+## At the item level
+
+These forms of the `#[doc]` attribute are used on individual items, to control how
+they are documented.
+
+### `inline` and `no_inline`
+
+<span id="docno_inlinedocinline"></span>
+
+These attributes are used on `use` statements, and control where the documentation shows
+up. For example, consider this Rust code:
+
+```rust,no_run
+pub use bar::Bar;
+
+/// bar docs
+pub mod bar {
+    /// the docs for Bar
+    pub struct Bar;
+}
+# fn main() {}
+```
+
+The documentation will generate a "Re-exports" section, and say `pub use bar::Bar;`, where
+`Bar` is a link to its page.
+
+If we change the `use` line like this:
+
+```rust,no_run
+#[doc(inline)]
+pub use bar::Bar;
+# pub mod bar { pub struct Bar; }
+# fn main() {}
+```
+
+Instead, `Bar` will appear in a `Structs` section, just like `Bar` was defined at the
+top level, rather than `pub use`'d.
+
+Let's change our original example, by making `bar` private:
+
+```rust,no_run
+pub use bar::Bar;
+
+/// bar docs
+mod bar {
+    /// the docs for Bar
+    pub struct Bar;
+}
+# fn main() {}
+```
+
+Here, because `bar` is not public, `Bar` wouldn't have its own page, so there's nowhere
+to link to. `rustdoc` will inline these definitions, and so we end up in the same case
+as the `#[doc(inline)]` above; `Bar` is in a `Structs` section, as if it were defined at
+the top level. If we add the `no_inline` form of the attribute:
+
+```rust,no_run
+#[doc(no_inline)]
+pub use bar::Bar;
+
+/// bar docs
+mod bar {
+    /// the docs for Bar
+    pub struct Bar;
+}
+# fn main() {}
+```
+
+Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere.
+
+One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will
+not eagerly inline it as a module unless you add `#[doc(inline)]`.
+
+### `hidden`
+
+<span id="dochidden"></span>
+
+Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless
+the `strip-hidden` pass is removed.
+
+### `alias`
+
+This attribute adds an alias in the search index.
+
+Let's take an example:
+
+```rust,no_run
+#[doc(alias = "TheAlias")]
+pub struct SomeType;
+```
+
+So now, if you enter "TheAlias" in the search, it'll display `SomeType`.
+Of course, if you enter `SomeType` it'll return `SomeType` as expected!
+
+#### FFI example
+
+This doc attribute is especially useful when writing bindings for a C library.
+For example, let's say we have a C function that looks like this:
+
+```c
+int lib_name_do_something(Obj *obj);
+```
+
+It takes a pointer to an `Obj` type and returns an integer. In Rust, it might
+be written like this:
+
+```ignore (using non-existing ffi types)
+pub struct Obj {
+    inner: *mut ffi::Obj,
+}
+
+impl Obj {
+    pub fn do_something(&mut self) -> i32 {
+        unsafe { ffi::lib_name_do_something(self.inner) }
+    }
+}
+```
+
+The function has been turned into a method to make it more convenient to use.
+However, if you want to look for the Rust equivalent of `lib_name_do_something`,
+you have no way to do so.
+
+To get around this limitation, we just add `#[doc(alias = "lib_name_do_something")]`
+on the `do_something` method and then it's all good!
+Users can now look for `lib_name_do_something` in our crate directly and find
+`Obj::do_something`.
diff --git a/src/doc/rustdoc/src/write-documentation/what-to-include.md b/src/doc/rustdoc/src/write-documentation/what-to-include.md
new file mode 100644 (file)
index 0000000..35e6ccb
--- /dev/null
@@ -0,0 +1,125 @@
+# What to include (and exclude)
+
+It is easy to say everything must be documented in a project and often times
+that is correct, but how can we get there, and are there things that don't
+belong?
+
+At the top of the `src/lib.rs` or `main.rs` file in your binary project, include
+the following attribute:
+
+```rust
+#![warn(missing_docs)]
+```
+
+Now run `cargo doc` and examine the output.  Here's a sample:
+
+```text
+ Documenting docdemo v0.1.0 (/Users/username/docdemo)
+warning: missing documentation for the crate
+ --> src/main.rs:1:1
+  |
+1 | / #![warn(missing_docs)]
+2 | |
+3 | | fn main() {
+4 | |     println!("Hello, world!");
+5 | | }
+  | |_^
+  |
+note: the lint level is defined here
+ --> src/main.rs:1:9
+  |
+1 | #![warn(missing_docs)]
+  |         ^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
+    Finished dev [unoptimized + debuginfo] target(s) in 2.96s
+```
+
+As a library author, adding the lint `#![deny(missing_docs)]` is a great way to
+ensure the project does not drift away from being documented well, and
+`#![warn(missing_docs)]` is a good way to move towards comprehensive
+documentation.  In addition to docs, `#![deny(missing_doc_code_examples)]`
+ensures each function contains a usage example.  In our example above, the
+warning is resolved by adding crate level documentation.
+
+There are more lints in the upcoming chapter [Lints][rustdoc-lints].
+
+## Examples
+
+Of course this is contrived to be simple, but part of the power of documentation
+is showing code that is easy to follow, rather than being realistic.  Docs often
+take shortcuts with error handling because examples can become complicated to
+follow with all the necessary set up required for a simple example.
+
+`Async` is a good example of this.  In order to execute an `async` example, an
+executor needs to be available.  Examples will often shortcut this, and leave
+users to figure out how to put the `async` code into their own runtime.
+
+It is preferred that `unwrap()` not be used inside an example, and some of the
+error handling components be hidden if they make the example too difficult to
+follow.
+
+``````text
+/// Example
+/// ```rust
+/// let fourtytwo = "42".parse::<u32>()?;
+/// println!("{} + 10 = {}", fourtytwo, fourtytwo+10);
+/// ```
+``````
+
+When rustdoc wraps that in a main function, it will fail to compile because the
+`ParseIntError` trait is not implemented.  In order to help both your audience
+and your test suite, this example needs some additional code:
+
+``````text
+/// Example
+/// ```rust
+/// # main() -> Result<(), std::num::ParseIntError> {
+/// let fortytwo = "42".parse::<u32>()?;
+/// println!("{} + 10 = {}", fortytwo, fortytwo+10);
+/// #     Ok(())
+/// # }
+/// ```
+``````
+
+The example is the same on the doc page, but has that extra information
+available to anyone trying to use your crate.  More about tests in the
+upcoming [Documentation tests] chapter.
+
+## What to Exclude
+
+Certain parts of your public interface may be included by default in the output
+of rustdoc.  The attribute `#[doc(hidden)]` can hide implementation details
+to encourage idiomatic use of the crate.
+
+For example, an internal `macro!` that makes the crate easier to implement can
+become a footgun for users when it appears in the public documentation.  An
+internal `Error` type may exist, and `impl` details should be hidden, as
+detailed in the [API Guidelines].
+
+## Customizing the output
+
+It is possible to pass a custom css file to `rustdoc` and style the
+documentation.
+
+```bash
+rustdoc --extend-css custom.css src/lib.rs
+```
+
+A good example of using this feature to create a dark theme is documented [on
+this blog].  Just remember, dark theme is already included in the rustdoc output
+by clicking on the paintbrush.  Adding additional options to the themes are
+as easy as creating a custom theme `.css` file and using the following syntax:
+
+```bash
+rustdoc --theme awesome.css src/lib.rs
+```
+
+Here is an example of a new theme, [Ayu].
+
+[Ayu]: https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/static/css/themes/ayu.css
+[API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html#rustdoc-does-not-show-unhelpful-implementation-details-c-hidden
+[Documentation tests]: documentation-tests.md
+[on this blog]: https://blog.guillaume-gomez.fr/articles/2016-09-16+Generating+doc+with+rustdoc+and+a+custom+theme
+[rustdoc-lints]: ../lints.md
index 457851b0cc7a42945fd4b6d28224297c6d25ad4f..735521e667c91e78980d37af9c0dc909fc5c97c9 100644 (file)
@@ -240,7 +240,7 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
 fn main() {
     let answer = do_twice(add_one, 5);
 
-    println!("The answer is: {}", answer);
+    println!("The answer is: {answer}");
 
     println!("With CFI enabled, you should not see the next answer");
     let f: fn(i32) -> i32 = unsafe {
@@ -250,7 +250,7 @@ fn main() {
     };
     let next_answer = do_twice(f, 5);
 
-    println!("The next answer is: {}", next_answer);
+    println!("The next answer is: {next_answer}");
 }
 ```
 Fig. 1. Modified example from the [Advanced Functions and
@@ -303,14 +303,14 @@ fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
 fn main() {
     let answer = do_twice(add_one, 5);
 
-    println!("The answer is: {}", answer);
+    println!("The answer is: {answer}");
 
     println!("With CFI enabled, you should not see the next answer");
     let f: fn(i32) -> i32 =
         unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
     let next_answer = do_twice(f, 5);
 
-    println!("The next answer is: {}", next_answer);
+    println!("The next answer is: {next_answer}");
 }
 ```
 Fig. 4. Another modified example from the [Advanced Functions and
index bf0819ec920b7f0462ad912fa87ad80124e1c34c..584f4295cba0fa349332261d3e4dcfe56bafd6d9 100644 (file)
@@ -18,10 +18,10 @@ fn main() {
     let b = Some(Box::new(5));
     match b {
         Some(box n) if n < 0 => {
-            println!("Box contains negative number {}", n);
+            println!("Box contains negative number {n}");
         },
         Some(box n) if n >= 0 => {
-            println!("Box contains non-negative number {}", n);
+            println!("Box contains non-negative number {n}");
         },
         None => {
             println!("No box");
index 4371a914b48041c932114de3d477d758ec8ddd9b..cc5c583bea8e25d81dda1b114b6e96a04dffeedf 100644 (file)
@@ -11,13 +11,13 @@ arrayvec = { version = "0.7", default-features = false }
 askama = { version = "0.11", default-features = false, features = ["config"] }
 atty = "0.2"
 pulldown-cmark = { version = "0.9", default-features = false }
-minifier = "0.0.42"
+minifier = "0.0.43"
 rayon = "1.5.1"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 smallvec = "1.6.1"
 tempfile = "3"
-itertools = "0.10"
+itertools = "0.10.1"
 regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }
 tracing = "0.1"
index 0d1482ce47017313c89346a5cbc2d12d0bb96b66..fa0030a936030f12bcf5ad482674795fb0ec483d 100644 (file)
@@ -402,16 +402,7 @@ fn projection_to_path_segment(ty: ty::ProjectionTy<'_>, cx: &mut DocContext<'_>)
     PathSegment {
         name: item.name,
         args: GenericArgs::AngleBracketed {
-            args: ty.substs[generics.parent_count..]
-                .iter()
-                .map(|ty| match ty.unpack() {
-                    ty::subst::GenericArgKind::Lifetime(lt) => {
-                        GenericArg::Lifetime(lt.clean(cx).unwrap())
-                    }
-                    ty::subst::GenericArgKind::Type(ty) => GenericArg::Type(ty.clean(cx)),
-                    ty::subst::GenericArgKind::Const(c) => GenericArg::Const(Box::new(c.clean(cx))),
-                })
-                .collect(),
+            args: substs_to_args(cx, &ty.substs[generics.parent_count..], false),
             bindings: Default::default(),
         },
     }
@@ -451,7 +442,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
                     },
                 )
             }
-            ty::GenericParamDefKind::Const { has_default, .. } => (
+            ty::GenericParamDefKind::Const { has_default } => (
                 self.name,
                 GenericParamDefKind::Const {
                     did: self.def_id,
@@ -838,7 +829,7 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib
                             .values
                             .insert(a as _, Argument { name, type_: *ty, is_const: true });
                     } else {
-                        panic!("unexpected non const in position {}", pos);
+                        panic!("unexpected non const in position {pos}");
                     }
                 }
                 _ => panic!("invalid arg index"),
@@ -1379,11 +1370,7 @@ fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_>
                 });
                 if let Some(lt) = lifetime.cloned() {
                     let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
-                    let cleaned = if !lt.is_elided() {
-                        lt.clean(cx)
-                    } else {
-                        self::types::Lifetime::elided()
-                    };
+                    let cleaned = if !lt.is_elided() { lt.clean(cx) } else { Lifetime::elided() };
                     substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
                 }
                 indices.lifetimes += 1;
index 20eea32560b27fdb5f00c5a0e87d2f7a441f9fc0..7861b915e9627668edd0e9be6f388f4270f229b7 100644 (file)
     Crate { module, primitives, external_traits: cx.external_traits.clone() }
 }
 
-fn external_generic_args(
+crate fn substs_to_args(
     cx: &mut DocContext<'_>,
-    did: DefId,
-    has_self: bool,
-    bindings: Vec<TypeBinding>,
-    substs: SubstsRef<'_>,
-) -> GenericArgs {
-    let mut skip_self = has_self;
-    let mut ty_kind = None;
-    let args: Vec<_> = substs
+    substs: &[ty::subst::GenericArg<'_>],
+    mut skip_first: bool,
+) -> Vec<GenericArg> {
+    substs
         .iter()
         .filter_map(|kind| match kind.unpack() {
             GenericArgKind::Lifetime(lt) => match *lt {
@@ -95,23 +91,32 @@ fn external_generic_args(
                 }
                 _ => lt.clean(cx).map(GenericArg::Lifetime),
             },
-            GenericArgKind::Type(_) if skip_self => {
-                skip_self = false;
+            GenericArgKind::Type(_) if skip_first => {
+                skip_first = false;
                 None
             }
-            GenericArgKind::Type(ty) => {
-                ty_kind = Some(ty.kind());
-                Some(GenericArg::Type(ty.clean(cx)))
-            }
+            GenericArgKind::Type(ty) => Some(GenericArg::Type(ty.clean(cx))),
             GenericArgKind::Const(ct) => Some(GenericArg::Const(Box::new(ct.clean(cx)))),
         })
-        .collect();
+        .collect()
+}
+
+fn external_generic_args(
+    cx: &mut DocContext<'_>,
+    did: DefId,
+    has_self: bool,
+    bindings: Vec<TypeBinding>,
+    substs: SubstsRef<'_>,
+) -> GenericArgs {
+    let args = substs_to_args(cx, &substs, has_self);
 
     if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() {
-        let inputs = match ty_kind.unwrap() {
-            ty::Tuple(tys) => tys.iter().map(|t| t.clean(cx)).collect(),
-            _ => return GenericArgs::AngleBracketed { args, bindings: bindings.into() },
-        };
+        let inputs =
+            // The trait's first substitution is the one after self, if there is one.
+            match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() {
+                ty::Tuple(tys) => tys.iter().map(|t| t.clean(cx)).collect(),
+                _ => return GenericArgs::AngleBracketed { args, bindings: bindings.into() },
+            };
         let output = None;
         // FIXME(#20299) return type comes from a projection now
         // match types[1].kind {
index 63a8e85f7c54044413df3e4c6551f6697fe6b059..e9efeba02997faf8898466a8fe0e6e7b3d97f3c3 100644 (file)
                 .to_string();
             let uext = UnusedExterns { lint_level, unused_extern_names };
             let unused_extern_json = serde_json::to_string(&uext).unwrap();
-            eprintln!("{}", unused_extern_json);
+            eprintln!("{unused_extern_json}");
         }
     }
 
@@ -430,7 +430,7 @@ fn drop(&mut self) {
                 // We used to check if the output contained "error[{}]: " but since we added the
                 // colored output, we can't anymore because of the color escape characters before
                 // the ":".
-                lang_string.error_codes.retain(|err| !out.contains(&format!("error[{}]", err)));
+                lang_string.error_codes.retain(|err| !out.contains(&format!("error[{err}]")));
 
                 if !lang_string.error_codes.is_empty() {
                     return Err(TestFailure::MissingErrorCodes(lang_string.error_codes));
@@ -510,7 +510,7 @@ fn drop(&mut self) {
 
     // Next, any attributes that came from the crate root via #![doc(test(attr(...)))].
     for attr in &opts.attrs {
-        prog.push_str(&format!("#![{}]\n", attr));
+        prog.push_str(&format!("#![{attr}]\n"));
         line_offset += 1;
     }
 
@@ -647,7 +647,7 @@ fn drop(&mut self) {
             // parse the source, but only has false positives, not false
             // negatives.
             if s.contains(crate_name) {
-                prog.push_str(&format!("extern crate r#{};\n", crate_name));
+                prog.push_str(&format!("extern crate r#{crate_name};\n"));
                 line_offset += 1;
             }
         }
@@ -661,7 +661,7 @@ fn drop(&mut self) {
         // Give each doctest main function a unique name.
         // This is for example needed for the tooling around `-C instrument-coverage`.
         let inner_fn_name = if let Some(test_id) = test_id {
-            format!("_doctest_main_{}", test_id)
+            format!("_doctest_main_{test_id}")
         } else {
             "_inner".into()
         };
@@ -669,15 +669,14 @@ fn drop(&mut self) {
         let (main_pre, main_post) = if returns_result {
             (
                 format!(
-                    "fn main() {{ {}fn {}() -> Result<(), impl core::fmt::Debug> {{\n",
-                    inner_attr, inner_fn_name
+                    "fn main() {{ {inner_attr}fn {inner_fn_name}() -> Result<(), impl core::fmt::Debug> {{\n",
                 ),
-                format!("\n}} {}().unwrap() }}", inner_fn_name),
+                format!("\n}} {inner_fn_name}().unwrap() }}"),
             )
         } else if test_id.is_some() {
             (
-                format!("fn main() {{ {}fn {}() {{\n", inner_attr, inner_fn_name),
-                format!("\n}} {}() }}", inner_fn_name),
+                format!("fn main() {{ {inner_attr}fn {inner_fn_name}() {{\n",),
+                format!("\n}} {inner_fn_name}() }}"),
             )
         } else {
             ("fn main() {\n".into(), "\n}".into())
@@ -695,7 +694,7 @@ fn drop(&mut self) {
         prog.extend([&main_pre, everything_else, &main_post].iter().cloned());
     }
 
-    debug!("final doctest:\n{}", prog);
+    debug!("final doctest:\n{prog}");
 
     (prog, line_offset, supports_color)
 }
@@ -763,9 +762,9 @@ enum PartitionState {
         }
     }
 
-    debug!("before:\n{}", before);
-    debug!("crates:\n{}", crates);
-    debug!("after:\n{}", after);
+    debug!("before:\n{before}");
+    debug!("crates:\n{crates}");
+    debug!("after:\n{after}");
 
     (before, after, crates)
 }
@@ -940,7 +939,7 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
             )
         };
 
-        debug!("creating test {}: {}", name, test);
+        debug!("creating test {name}: {test}");
         self.tests.push(test::TestDescAndFn {
             desc: test::TestDesc {
                 name: test::DynTestName(name),
@@ -994,19 +993,19 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
                             eprint!("Some expected error codes were not found: {:?}", codes);
                         }
                         TestFailure::ExecutionError(err) => {
-                            eprint!("Couldn't run the test: {}", err);
+                            eprint!("Couldn't run the test: {err}");
                             if err.kind() == io::ErrorKind::PermissionDenied {
                                 eprint!(" - maybe your tempdir is mounted with noexec?");
                             }
                         }
                         TestFailure::ExecutionFailure(out) => {
                             let reason = if let Some(code) = out.status.code() {
-                                format!("exit code {}", code)
+                                format!("exit code {code}")
                             } else {
                                 String::from("terminated by signal")
                             };
 
-                            eprintln!("Test executable failed ({}).", reason);
+                            eprintln!("Test executable failed ({reason}).");
 
                             // FIXME(#12309): An unfortunate side-effect of capturing the test
                             // executable's output is that the relative ordering between the test's
@@ -1024,11 +1023,11 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
                                 eprintln!();
 
                                 if !stdout.is_empty() {
-                                    eprintln!("stdout:\n{}", stdout);
+                                    eprintln!("stdout:\n{stdout}");
                                 }
 
                                 if !stderr.is_empty() {
-                                    eprintln!("stderr:\n{}", stderr);
+                                    eprintln!("stderr:\n{stderr}");
                                 }
                             }
                         }
index 78965712dfa1843f98f5cc91534b4e04e7a3a92f..5c59609d5b8c600253fb5913c4d1bfe9eea4b646 100644 (file)
@@ -143,11 +143,14 @@ impl Buffer {
     }
 }
 
-fn comma_sep<T: fmt::Display>(items: impl Iterator<Item = T>) -> impl fmt::Display {
+fn comma_sep<T: fmt::Display>(
+    items: impl Iterator<Item = T>,
+    space_after_comma: bool,
+) -> impl fmt::Display {
     display_fn(move |f| {
         for (i, item) in items.enumerate() {
             if i != 0 {
-                write!(f, ", ")?;
+                write!(f, ",{}", if space_after_comma { " " } else { "" })?;
             }
             fmt::Display::fmt(&item, f)?;
         }
@@ -248,9 +251,9 @@ impl clean::Generics {
             }
 
             if f.alternate() {
-                write!(f, "<{:#}>", comma_sep(real_params.map(|g| g.print(cx))))
+                write!(f, "<{:#}>", comma_sep(real_params.map(|g| g.print(cx)), true))
             } else {
-                write!(f, "&lt;{}&gt;", comma_sep(real_params.map(|g| g.print(cx))))
+                write!(f, "&lt;{}&gt;", comma_sep(real_params.map(|g| g.print(cx)), true))
             }
         })
     }
@@ -266,10 +269,80 @@ impl clean::Generics {
     end_newline: bool,
 ) -> impl fmt::Display + 'a + Captures<'tcx> {
     display_fn(move |f| {
-        if gens.where_predicates.is_empty() {
+        let mut where_predicates = gens.where_predicates.iter().filter(|pred| {
+            !matches!(pred, clean::WherePredicate::BoundPredicate { bounds, .. } if bounds.is_empty())
+        }).map(|pred| {
+            display_fn(move |f| {
+                if f.alternate() {
+                    f.write_str(" ")?;
+                } else {
+                    f.write_str("<br>")?;
+                }
+
+                match pred {
+                    clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
+                        let bounds = bounds;
+                        let for_prefix = if bound_params.is_empty() {
+                            String::new()
+                        } else if f.alternate() {
+                            format!(
+                                "for&lt;{:#}&gt; ",
+                                comma_sep(bound_params.iter().map(|lt| lt.print()), true)
+                            )
+                        } else {
+                            format!(
+                                "for&lt;{}&gt; ",
+                                comma_sep(bound_params.iter().map(|lt| lt.print()), true)
+                            )
+                        };
+
+                        if f.alternate() {
+                            write!(
+                                f,
+                                "{}{:#}: {:#}",
+                                for_prefix,
+                                ty.print(cx),
+                                print_generic_bounds(bounds, cx)
+                            )
+                        } else {
+                            write!(
+                                f,
+                                "{}{}: {}",
+                                for_prefix,
+                                ty.print(cx),
+                                print_generic_bounds(bounds, cx)
+                            )
+                        }
+                    }
+                    clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
+                        write!(
+                            f,
+                            "{}: {}",
+                            lifetime.print(),
+                            bounds
+                                .iter()
+                                .map(|b| b.print(cx).to_string())
+                                .collect::<Vec<_>>()
+                                .join(" + ")
+                        )
+                    }
+                    clean::WherePredicate::EqPredicate { lhs, rhs } => {
+                        if f.alternate() {
+                            write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx),)
+                        } else {
+                            write!(f, "{} == {}", lhs.print(cx), rhs.print(cx),)
+                        }
+                    }
+                }
+            })
+        }).peekable();
+
+        if where_predicates.peek().is_none() {
             return Ok(());
         }
+
         let mut clause = String::new();
+
         if f.alternate() {
             clause.push_str(" where");
         } else {
@@ -279,72 +352,11 @@ impl clean::Generics {
                 clause.push_str(" <span class=\"where\">where");
             }
         }
-        for (i, pred) in gens.where_predicates.iter().enumerate() {
-            if f.alternate() {
-                clause.push(' ');
-            } else {
-                clause.push_str("<br>");
-            }
 
-            match pred {
-                clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
-                    let bounds = bounds;
-                    let for_prefix = match bound_params.len() {
-                        0 => String::new(),
-                        _ if f.alternate() => {
-                            format!(
-                                "for&lt;{:#}&gt; ",
-                                comma_sep(bound_params.iter().map(|lt| lt.print()))
-                            )
-                        }
-                        _ => format!(
-                            "for&lt;{}&gt; ",
-                            comma_sep(bound_params.iter().map(|lt| lt.print()))
-                        ),
-                    };
-
-                    if f.alternate() {
-                        clause.push_str(&format!(
-                            "{}{:#}: {:#}",
-                            for_prefix,
-                            ty.print(cx),
-                            print_generic_bounds(bounds, cx)
-                        ));
-                    } else {
-                        clause.push_str(&format!(
-                            "{}{}: {}",
-                            for_prefix,
-                            ty.print(cx),
-                            print_generic_bounds(bounds, cx)
-                        ));
-                    }
-                }
-                clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
-                    clause.push_str(&format!(
-                        "{}: {}",
-                        lifetime.print(),
-                        bounds
-                            .iter()
-                            .map(|b| b.print(cx).to_string())
-                            .collect::<Vec<_>>()
-                            .join(" + ")
-                    ));
-                }
-                clean::WherePredicate::EqPredicate { lhs, rhs } => {
-                    if f.alternate() {
-                        clause.push_str(&format!("{:#} == {:#}", lhs.print(cx), rhs.print(cx),));
-                    } else {
-                        clause.push_str(&format!("{} == {}", lhs.print(cx), rhs.print(cx),));
-                    }
-                }
-            }
-
-            if i < gens.where_predicates.len() - 1 || end_newline {
-                clause.push(',');
-            }
-        }
+        clause.push_str(&comma_sep(where_predicates, false).to_string());
 
         if end_newline {
+            clause.push(',');
             // add a space so stripping <br> tags and breaking spaces still renders properly
             if f.alternate() {
                 clause.push(' ');
@@ -394,13 +406,13 @@ fn print<'a, 'tcx: 'a>(
                     write!(
                         f,
                         "for<{:#}> ",
-                        comma_sep(self.generic_params.iter().map(|g| g.print(cx)))
+                        comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
                     )?;
                 } else {
                     write!(
                         f,
                         "for&lt;{}&gt; ",
-                        comma_sep(self.generic_params.iter().map(|g| g.print(cx)))
+                        comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
                     )?;
                 }
             }
@@ -424,7 +436,8 @@ impl clean::GenericBound {
                 let modifier_str = match modifier {
                     hir::TraitBoundModifier::None => "",
                     hir::TraitBoundModifier::Maybe => "?",
-                    hir::TraitBoundModifier::MaybeConst => "~const",
+                    // ~const is experimental; do not display those bounds in rustdoc
+                    hir::TraitBoundModifier::MaybeConst => "",
                 };
                 if f.alternate() {
                     write!(f, "{}{:#}", modifier_str, ty.print(cx))
@@ -1111,7 +1124,7 @@ fn print_hrtb_with_space<'a, 'tcx: 'a>(
                 write!(
                     f,
                     "for&lt;{}&gt; ",
-                    comma_sep(self.generic_params.iter().map(|g| g.print(cx)))
+                    comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
                 )
             } else {
                 Ok(())
@@ -1172,8 +1185,8 @@ fn inner_full_print(
         cx: &Context<'_>,
     ) -> fmt::Result {
         let amp = if f.alternate() { "&" } else { "&amp;" };
-        let mut args = String::new();
-        let mut args_plain = String::new();
+        let mut args = Buffer::html();
+        let mut args_plain = Buffer::new();
         for (i, input) in self.inputs.values.iter().enumerate() {
             if i == 0 {
                 args.push_str("<br>");
@@ -1186,59 +1199,51 @@ fn inner_full_print(
                         args_plain.push_str("self");
                     }
                     clean::SelfBorrowed(Some(ref lt), mtbl) => {
-                        args.push_str(&format!(
-                            "{}{} {}self",
-                            amp,
-                            lt.print(),
-                            mtbl.print_with_space()
-                        ));
-                        args_plain.push_str(&format!(
-                            "&{} {}self",
-                            lt.print(),
-                            mtbl.print_with_space()
-                        ));
+                        write!(args, "{}{} {}self", amp, lt.print(), mtbl.print_with_space());
+                        write!(args_plain, "&{} {}self", lt.print(), mtbl.print_with_space());
                     }
                     clean::SelfBorrowed(None, mtbl) => {
-                        args.push_str(&format!("{}{}self", amp, mtbl.print_with_space()));
-                        args_plain.push_str(&format!("&{}self", mtbl.print_with_space()));
+                        write!(args, "{}{}self", amp, mtbl.print_with_space());
+                        write!(args_plain, "&{}self", mtbl.print_with_space());
                     }
                     clean::SelfExplicit(ref typ) => {
                         if f.alternate() {
-                            args.push_str(&format!("self: {:#}", typ.print(cx)));
+                            write!(args, "self: {:#}", typ.print(cx));
                         } else {
-                            args.push_str(&format!("self: {}", typ.print(cx)));
+                            write!(args, "self: {}", typ.print(cx));
                         }
-                        args_plain.push_str(&format!("self: {:#}", typ.print(cx)));
+                        write!(args_plain, "self: {:#}", typ.print(cx));
                     }
                 }
             } else {
                 if i > 0 {
                     args.push_str(" <br>");
-                    args_plain.push(' ');
+                    args_plain.push_str(" ");
                 }
                 if input.is_const {
                     args.push_str("const ");
                     args_plain.push_str("const ");
                 }
                 if !input.name.is_empty() {
-                    args.push_str(&format!("{}: ", input.name));
-                    args_plain.push_str(&format!("{}: ", input.name));
+                    write!(args, "{}: ", input.name);
+                    write!(args_plain, "{}: ", input.name);
                 }
 
                 if f.alternate() {
-                    args.push_str(&format!("{:#}", input.type_.print(cx)));
+                    write!(args, "{:#}", input.type_.print(cx));
                 } else {
-                    args.push_str(&input.type_.print(cx).to_string());
+                    write!(args, "{}", input.type_.print(cx));
                 }
-                args_plain.push_str(&format!("{:#}", input.type_.print(cx)));
+                write!(args_plain, "{:#}", input.type_.print(cx));
             }
             if i + 1 < self.inputs.values.len() {
-                args.push(',');
-                args_plain.push(',');
+                args.push_str(",");
+                args_plain.push_str(",");
             }
         }
 
-        let mut args_plain = format!("({})", args_plain);
+        let mut args_plain = format!("({})", args_plain.into_inner());
+        let mut args = args.into_inner();
 
         if self.c_variadic {
             args.push_str(",<br> ...");
index 7061a9674e4fb63be45ec59f5704763dcf47cd36..3a3d61b1e67cca0122973b6eaeb6d224823847e4 100644 (file)
@@ -1314,7 +1314,7 @@ fn markdown_summary_with_limit(
 
     for ev in iter {
         if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 {
-            debug!("found link: {}", dest);
+            debug!("found link: {dest}");
             let span = span_for_link(&dest, ev.1);
             links.borrow_mut().push(MarkdownLink { kind, link: dest.into_string(), range: span });
         }
@@ -1460,6 +1460,7 @@ fn init_id_map() -> FxHashMap<String, usize> {
     map.insert("provided-methods".to_owned(), 1);
     map.insert("implementors".to_owned(), 1);
     map.insert("synthetic-implementors".to_owned(), 1);
+    map.insert("implementations-list".to_owned(), 1);
     map.insert("trait-implementations-list".to_owned(), 1);
     map.insert("synthetic-implementations-list".to_owned(), 1);
     map.insert("blanket-implementations-list".to_owned(), 1);
index 558dbb3b3965a5e6dd4b968e39c7e36f17cb65bd..34d1268a7df61d28dc179605d71b7ff6c2daee5a 100644 (file)
@@ -699,7 +699,13 @@ fn short_item_info(
 
 // Render the list of items inside one of the sections "Trait Implementations",
 // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
-fn render_impls(cx: &Context<'_>, w: &mut Buffer, impls: &[&&Impl], containing_item: &clean::Item) {
+fn render_impls(
+    cx: &Context<'_>,
+    w: &mut Buffer,
+    impls: &[&&Impl],
+    containing_item: &clean::Item,
+    toggle_open_by_default: bool,
+) {
     let tcx = cx.tcx();
     let mut rendered_impls = impls
         .iter()
@@ -722,7 +728,7 @@ fn render_impls(cx: &Context<'_>, w: &mut Buffer, impls: &[&&Impl], containing_i
                     is_on_foreign_type: false,
                     show_default_items: true,
                     show_non_assoc_items: true,
-                    toggle_open_by_default: true,
+                    toggle_open_by_default,
                 },
             );
             buffer.into_inner()
@@ -1065,14 +1071,15 @@ fn render_assoc_items_inner(
     let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
     if !non_trait.is_empty() {
         let mut tmp_buf = Buffer::empty_from(w);
-        let render_mode = match what {
+        let (render_mode, id) = match what {
             AssocItemRender::All => {
                 tmp_buf.write_str(
                     "<h2 id=\"implementations\" class=\"small-section-header\">\
-                         Implementations<a href=\"#implementations\" class=\"anchor\"></a>\
-                    </h2>",
+                         Implementations\
+                         <a href=\"#implementations\" class=\"anchor\"></a>\
+                     </h2>",
                 );
-                RenderMode::Normal
+                (RenderMode::Normal, "implementations-list".to_owned())
             }
             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
                 let id =
@@ -1090,7 +1097,7 @@ fn render_assoc_items_inner(
                     trait_ = trait_.print(cx),
                     type_ = type_.print(cx),
                 );
-                RenderMode::ForDeref { mut_: deref_mut_ }
+                (RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id))
             }
         };
         let mut impls_buf = Buffer::empty_from(w);
@@ -1115,7 +1122,9 @@ fn render_assoc_items_inner(
         }
         if !impls_buf.is_empty() {
             w.push_buffer(tmp_buf);
+            write!(w, "<div id=\"{}\">", id);
             w.push_buffer(impls_buf);
+            w.write_str("</div>");
         }
     }
 
@@ -1140,13 +1149,14 @@ fn render_assoc_items_inner(
             concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
 
         let mut impls = Buffer::empty_from(w);
-        render_impls(cx, &mut impls, &concrete, containing_item);
+        render_impls(cx, &mut impls, &concrete, containing_item, true);
         let impls = impls.into_inner();
         if !impls.is_empty() {
             write!(
                 w,
                 "<h2 id=\"trait-implementations\" class=\"small-section-header\">\
-                     Trait Implementations<a href=\"#trait-implementations\" class=\"anchor\"></a>\
+                     Trait Implementations\
+                     <a href=\"#trait-implementations\" class=\"anchor\"></a>\
                  </h2>\
                  <div id=\"trait-implementations-list\">{}</div>",
                 impls
@@ -1161,7 +1171,7 @@ fn render_assoc_items_inner(
                  </h2>\
                  <div id=\"synthetic-implementations-list\">",
             );
-            render_impls(cx, w, &synthetic, containing_item);
+            render_impls(cx, w, &synthetic, containing_item, false);
             w.write_str("</div>");
         }
 
@@ -1173,7 +1183,7 @@ fn render_assoc_items_inner(
                  </h2>\
                  <div id=\"blanket-implementations-list\">",
             );
-            render_impls(cx, w, &blanket_impl, containing_item);
+            render_impls(cx, w, &blanket_impl, containing_item, false);
             w.write_str("</div>");
         }
     }
index e84dc6c72409f6ee2bc98089a3ad6144a8e77503..68644a017a4004001188eaf3c697e99dd1f9a0ac 100644 (file)
@@ -1710,11 +1710,11 @@ struct update syntax will not work.",
 }
 
 fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
-    fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) {
-        if layout.abi.is_unsized() {
+    fn write_size_of_layout(w: &mut Buffer, layout: Layout<'_>, tag_size: u64) {
+        if layout.abi().is_unsized() {
             write!(w, "(unsized)");
         } else {
-            let bytes = layout.size.bytes() - tag_size;
+            let bytes = layout.size().bytes() - tag_size;
             write!(w, "{size} byte{pl}", size = bytes, pl = if bytes == 1 { "" } else { "s" },);
         }
     }
@@ -1744,7 +1744,7 @@ fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) {
             write_size_of_layout(w, ty_layout.layout, 0);
             writeln!(w, "</p>");
             if let Variants::Multiple { variants, tag, tag_encoding, .. } =
-                &ty_layout.layout.variants
+                &ty_layout.layout.variants()
             {
                 if !variants.is_empty() {
                     w.write_str(
@@ -1767,7 +1767,7 @@ fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) {
                     for (index, layout) in variants.iter_enumerated() {
                         let name = adt.variants[index].name;
                         write!(w, "<li><code>{name}</code>: ", name = name);
-                        write_size_of_layout(w, layout, tag_size);
+                        write_size_of_layout(w, *layout, tag_size);
                         writeln!(w, "</li>");
                     }
                     w.write_str("</ul>");
index bae04f2095a3d079d63a6a09636953c3c592292b..9fba6e911628229f8ed8632581ea9916ba96a56c 100644 (file)
@@ -272,22 +272,16 @@ fn emit_source(
 ) {
     let lines = s.lines().count();
     let mut line_numbers = Buffer::empty_from(buf);
-    let mut cols = 0;
-    let mut tmp = lines;
-    while tmp > 0 {
-        cols += 1;
-        tmp /= 10;
-    }
     line_numbers.write_str("<pre class=\"line-numbers\">");
     match source_context {
         SourceContext::Standalone => {
             for line in 1..=lines {
-                writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", line, cols)
+                writeln!(line_numbers, "<span id=\"{0}\">{0}</span>", line)
             }
         }
         SourceContext::Embedded { offset } => {
             for line in 1..=lines {
-                writeln!(line_numbers, "<span>{0:1$}</span>", line + offset, cols)
+                writeln!(line_numbers, "<span>{0}</span>", line + offset)
             }
         }
     }
index f1e0a89883ab8d2915c862304aa0ed126ee2c3d5..9a4b382a304ff9b899dafbb83719dc5763ea7ba9 100644 (file)
@@ -541,6 +541,9 @@ h2.location a {
        text-decoration: underline;
 }
 
+.line-numbers {
+       text-align: right;
+}
 .rustdoc:not(.source) .example-wrap > pre:not(.line-number) {
        width: 100%;
        overflow-x: auto;
index 8e1919f75d671512149b1efdba9247121f2984ec..90592335d5ddfa83cfa03112873620992a04047f 100644 (file)
@@ -741,7 +741,7 @@ function hideThemeButtonState() {
         } else {
             addClass(innerToggle, "will-expand");
             onEachLazy(document.getElementsByClassName("rustdoc-toggle"), function(e) {
-                if (e.parentNode.id !== MAIN_ID ||
+                if (e.parentNode.id !== "implementations-list" ||
                     (!hasClass(e, "implementors-toggle") &&
                      !hasClass(e, "type-contents-toggle")))
                 {
index 906b8f8a245709656d2e657c573de12397913eba..a1f92afad46a659bf53b511e640555c901fa2f73 100644 (file)
@@ -51,7 +51,7 @@ fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) {
 
     let mut css = String::new();
     for name in &options.markdown_css {
-        let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">\n", name);
+        let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{name}\">\n");
         css.push_str(&s)
     }
 
index e29ac13bc97e26f886c3bfe72f9135e994c3cd0a..c8eccf626fb5bb851b2ade93af8851ca1523807f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e29ac13bc97e26f886c3bfe72f9135e994c3cd0a
+Subproject commit c8eccf626fb5bb851b2ade93af8851ca1523807f
index dd8e6f614df11812bd69f621f24e60fd62239ae8..6a898b2974a65f40fb3eba2dc11cc205c457a5fe 100644 (file)
@@ -13,6 +13,7 @@
 pub trait Sized {}
 #[lang = "copy"]
 pub trait Copy {}
+impl Copy for f32 {}
 
 #[repr(C)]
 pub struct Franta {
index 4c2073678b842a084e6f10fdf444d775d331fc01..18d896e86b215e8bc1e8df05489d0209c6ef8c29 100644 (file)
@@ -23,6 +23,7 @@
 trait Sized {}
 #[lang = "copy"]
 trait Copy {}
+impl Copy for u32 {}
 
 // Use of these requires target features to be enabled
 extern "unadjusted" {
index bb910d573b33818e78a40f35b65cffccb33e27f0..dfc312279083d6fe576440b4e6fa7bb796651ec0 100644 (file)
@@ -13,6 +13,7 @@
 trait Sized {}
 #[lang = "copy"]
 trait Copy {}
+impl Copy for i64 {}
 
 // CHECK: define x86_64_sysvcc i64 @has_sysv64_abi
 #[no_mangle]
index 119004d261d60ed07d4e522cf833844b094248ab..d612f603e4fea0d27e64b0e4f17b914f565a195d 100644 (file)
@@ -13,6 +13,7 @@
 trait Sized {}
 #[lang = "copy"]
 trait Copy {}
+impl Copy for i64 {}
 
 // CHECK: define x86_intrcc i64 @has_x86_interrupt_abi
 #[no_mangle]
index 367591dcb9617843bee42b6884a9507254e0e32c..f7c02d47939fed4314f87dde85ba35526761d7da 100644 (file)
@@ -17,7 +17,7 @@
 trait Sized { }
 #[lang="copy"]
 trait Copy { }
-
+impl Copy for u32 {}
 
 
 // CHECK: define i32 @peach{{.*}}[[PEACH_ATTRS:\#[0-9]+]] {
index ad41badf38169036d03b02a6a1fb599e0f86d583..d3ea1915a8b1967537facedd40c8ab69bc18bea6 100644 (file)
@@ -6,7 +6,7 @@
 
 pub fn f() {
     let a = A;
-    let b = (0i32, 1i32, 2i32, 3i32);
+    let b = (0i32, 1i32, 2i32, 3 as *const i32);
     let c = || {};
 
     a(String::new(), String::new());
@@ -21,7 +21,7 @@ pub fn f() {
 // CHECK-NOT:  inlinehint
 // CHECK-SAME: {{$}}
 
-// CHECK:      ; <(i32, i32, i32, i32) as core::clone::Clone>::clone
+// CHECK:      ; <(i32, i32, i32, *const i{{16|32|64}}) as core::clone::Clone>::clone
 // CHECK-NEXT: ; Function Attrs: inlinehint
 
 // CHECK:      ; inline_hint::f::{closure#0}
index faf81b5ae76057c8028a4b465430367c094c1864..7f0f678062a64b3295343054993a21f47ebe0a2a 100644 (file)
 trait Sized {}
 #[lang = "copy"]
 trait Copy {}
+impl Copy for bool {}
+impl Copy for i8 {}
+impl Copy for u8 {}
+impl Copy for i32 {}
+impl Copy for i64 {}
+impl Copy for u64 {}
+impl Copy for f32 {}
+impl Copy for f64 {}
 
 // CHECK: define void @f_void()
 #[no_mangle]
index 2c19cfd8c220127f54212fd66d6a73534fffbb77..4be77e36e760bdf0a160bd2fb7f7fd6582165220 100644 (file)
@@ -29,7 +29,7 @@ pub unsafe fn apple() -> u32 {
     peach()
 }
 
-// target features same as global (not reflected or overriden in IR)
+// target features same as global
 #[no_mangle]
 pub unsafe fn banana() -> u32 {
 // CHECK-LABEL: @banana()
@@ -43,5 +43,5 @@ pub unsafe fn banana() -> u32 {
 // COMPAT-SAME: "target-features"="+avx2,+avx,+avx"
 // INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx"
 // CHECK: attributes [[BANANAATTRS]]
-// CHECK-NOT: target-features
-// CHECK-SAME: }
+// COMPAT-SAME: "target-features"="+avx2,+avx"
+// INCOMPAT-SAME: "target-features"="-avx2,-avx"
diff --git a/src/test/mir-opt/combine_clone_of_primitives.rs b/src/test/mir-opt/combine_clone_of_primitives.rs
new file mode 100644 (file)
index 0000000..0972d2d
--- /dev/null
@@ -0,0 +1,20 @@
+// compile-flags: -C opt-level=0 -Z inline_mir=no
+// ignore-wasm32 compiled with panic=abort by default
+
+// EMIT_MIR combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
+
+#[derive(Clone)]
+struct MyThing<T> {
+    v: T,
+    i: u64,
+    a: [f32; 3],
+}
+
+fn main() {
+    let x = MyThing::<i16> { v: 2, i: 3, a: [0.0; 3] };
+    let y = x.clone();
+
+    assert_eq!(y.v, 2);
+    assert_eq!(y.i, 3);
+    assert_eq!(y.a, [0.0; 3]);
+}
diff --git a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
new file mode 100644 (file)
index 0000000..62e5da4
--- /dev/null
@@ -0,0 +1,80 @@
+- // MIR for `<impl at $DIR/combine_clone_of_primitives.rs:6:10: 6:15>::clone` before InstCombine
++ // MIR for `<impl at $DIR/combine_clone_of_primitives.rs:6:10: 6:15>::clone` after InstCombine
+  
+  fn <impl at $DIR/combine_clone_of_primitives.rs:6:10: 6:15>::clone(_1: &MyThing<T>) -> MyThing<T> {
+      debug self => _1;                    // in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+      let mut _0: MyThing<T>;              // return place in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+      let _2: &T;                          // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+      let _3: &u64;                        // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      let _4: &[f32; 3];                   // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      let mut _5: T;                       // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+      let mut _6: &T;                      // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+      let _7: &T;                          // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+      let mut _8: u64;                     // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      let mut _9: &u64;                    // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      let _10: &u64;                       // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      let mut _11: [f32; 3];               // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      let mut _12: &[f32; 3];              // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      let _13: &[f32; 3];                  // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      scope 1 {
+          debug __self_0_0 => _2;          // in scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          debug __self_0_1 => _3;          // in scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          debug __self_0_2 => _4;          // in scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      }
+  
+      bb0: {
+          _2 = &((*_1).0: T);              // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          _3 = &((*_1).1: u64);            // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          _4 = &((*_1).2: [f32; 3]);       // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-         _7 = &(*_2);                     // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+-         _6 = &(*_7);                     // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
++         _7 = _2;                         // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
++         _6 = _7;                         // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          _5 = <T as Clone>::clone(move _6) -> bb1; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+                                           // mir::Constant
+                                           // + span: $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+                                           // + literal: Const { ty: for<'r> fn(&'r T) -> T {<T as Clone>::clone}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+-         _10 = &(*_3);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+-         _9 = &(*_10);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+-         _8 = <u64 as Clone>::clone(move _9) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+-                                          // mir::Constant
+-                                          // + span: $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+-                                          // + literal: Const { ty: for<'r> fn(&'r u64) -> u64 {<u64 as Clone>::clone}, val: Value(Scalar(<ZST>)) }
++         _10 = _3;                        // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
++         _9 = _10;                        // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
++         _8 = (*_9);                      // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
++         goto -> bb2;                     // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      }
+  
+      bb2: {
+-         _13 = &(*_4);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-         _12 = &(*_13);                   // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-         _11 = <[f32; 3] as Clone>::clone(move _12) -> [return: bb3, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-                                          // mir::Constant
+-                                          // + span: $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-                                          // + literal: Const { ty: for<'r> fn(&'r [f32; 3]) -> [f32; 3] {<[f32; 3] as Clone>::clone}, val: Value(Scalar(<ZST>)) }
++         _13 = _4;                        // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
++         _12 = _13;                       // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
++         _11 = (*_12);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
++         goto -> bb3;                     // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      }
+  
+      bb3: {
+          (_0.0: T) = move _5;             // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+          (_0.1: u64) = move _8;           // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+          (_0.2: [f32; 3]) = move _11;     // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+          return;                          // scope 0 at $DIR/combine_clone_of_primitives.rs:6:15: 6:15
+      }
+  
+      bb4 (cleanup): {
+          drop(_5) -> bb5;                 // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+      }
+  
+      bb5 (cleanup): {
+          resume;                          // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+      }
+  }
+  
index 1d72b34f83b815809d3b00f83e2d696ff2abe4d6..831d73045dd639d01e4d6802f1ba4d38a260cea6 100644 (file)
 -     bb1: {
 +         discriminant(_4) = 0;            // scope 2 at $DIR/inline-generator.rs:15:5: 15:41
           _3 = &mut _4;                    // scope 0 at $DIR/inline-generator.rs:9:23: 9:31
--         _2 = Pin::<&mut impl Generator<bool>>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:32
+-         _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:32
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-generator.rs:9:14: 9:22
 -                                          // + user_ty: UserType(0)
--                                          // + literal: Const { ty: fn(&mut impl Generator<bool>) -> Pin<&mut impl Generator<bool>> {Pin::<&mut impl Generator<bool>>::new}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn(&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]) -> Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]> {Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new}, val: Value(Scalar(<ZST>)) }
 -     }
 - 
 -     bb2: {
 +         StorageDead(_6);                 // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         StorageDead(_5);                 // scope 4 at $SRC_DIR/core/src/pin.rs:LL:COL
           StorageDead(_3);                 // scope 0 at $DIR/inline-generator.rs:9:31: 9:32
--         _1 = <impl Generator<bool> as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
+-         _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-generator.rs:9:33: 9:39
--                                          // + literal: Const { ty: for<'r> fn(Pin<&'r mut impl Generator<bool>>, bool) -> GeneratorState<<impl Generator<bool> as Generator<bool>>::Yield, <impl Generator<bool> as Generator<bool>>::Return> {<impl Generator<bool> as Generator<bool>>::resume}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> fn(Pin<&'r mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>, bool) -> GeneratorState<<[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::Yield, <[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::Return> {<[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::resume}, val: Value(Scalar(<ZST>)) }
 +         StorageLive(_7);                 // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         _7 = const false;                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         StorageLive(_10);                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
index 9e92f025b76618c9b5080025b9e7fada8ad75272..ea6b91cba9e583e47097c4b4fe7db7452e3b783b 100644 (file)
       bb1: {
           _3 = &_4;                        // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
           StorageLive(_5);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
--         _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+-         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
 -                                          // mir::Constant
 -                                          // + span: $DIR/issue-78442.rs:11:5: 11:15
--                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
 +         _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
index a8ae4008cbc9647a6418670310903ec7c89a0f80..ba9da7678e7233a520e20d098ee7159654f0ff54 100644 (file)
           _3 = &_4;                        // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
           StorageLive(_5);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
           nop;                             // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
-          _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+-         _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
++         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
                                            // mir::Constant
                                            // + span: $DIR/issue-78442.rs:11:5: 11:15
-                                           // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
++                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
       }
   
       bb2: {
index 975e2ffbf01e7e85eac7e512c28ffc438d6e0bb8..9f235248ca59f9a2c61112c005979684576aa0a5 100644 (file)
@@ -42,7 +42,7 @@ fn use_x(_1: &'_#6r mut i32, _2: &'_#7r u32, _3: &'_#8r u32, _4: &'_#9r u32) ->
     let mut _0: bool;                    // return place in scope 0 at $DIR/named-lifetimes-basic.rs:12:81: 12:85
 
     bb0: {
-        _0 = const Const(Value(Scalar(0x01)): bool); // bb0[0]: scope 0 at $DIR/named-lifetimes-basic.rs:12:88: 12:92
+        _0 = const ConstValue(Scalar(0x01): bool); // bb0[0]: scope 0 at $DIR/named-lifetimes-basic.rs:12:88: 12:92
         return;                          // bb0[1]: scope 0 at $DIR/named-lifetimes-basic.rs:12:94: 12:94
     }
 }
index 3ef7844ce434ffe161ca05f57d617bd2a8bd4f3a..ed94a1ecf006252f79da61898d048595d549c779 100644 (file)
@@ -45,11 +45,11 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
-        _1 = [const Const(Value(Scalar(0x00000001)): usize), const Const(Value(Scalar(0x00000002)): usize), const Const(Value(Scalar(0x00000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
+        _1 = [const ConstValue(Scalar(0x00000001): usize), const ConstValue(Scalar(0x00000002): usize), const ConstValue(Scalar(0x00000003): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
         FakeRead(ForLet(None), _1);      // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
         StorageLive(_2);                 // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
         StorageLive(_3);                 // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
-        _3 = const Const(Value(Scalar(0x00000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
+        _3 = const ConstValue(Scalar(0x00000000): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
         _4 = Len(_1);                    // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
         _5 = Lt(_3, _4);                 // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
@@ -62,7 +62,7 @@ fn main() -> () {
         _6 = _2;                         // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14
         FakeRead(ForLet(None), _6);      // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
         StorageLive(_7);                 // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
-        _7 = const Const(Value(Scalar(0x01)): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
+        _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
         switchInt(move _7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
     }
 
@@ -70,7 +70,7 @@ fn main() -> () {
         StorageLive(_8);                 // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
         StorageLive(_9);                 // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
         _9 = (*_6);                      // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
-        _8 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
+        _8 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14
                                          // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
@@ -79,13 +79,13 @@ fn main() -> () {
     bb3: {
         StorageDead(_9);                 // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18
         StorageDead(_8);                 // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19
-        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
+        _0 = const ConstValue(Scalar(<ZST>): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
         goto -> bb6;                     // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
     bb4: {
         StorageLive(_10);                // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
-        _10 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x00000016)): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
+        _10 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14
                                          // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
@@ -93,7 +93,7 @@ fn main() -> () {
 
     bb5: {
         StorageDead(_10);                // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19
-        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
+        _0 = const ConstValue(Scalar(<ZST>): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
         goto -> bb6;                     // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
index d6b4a0beebd657a6751de68d0dfde771bd9d252d..95997b2070172d955de39b41256af0eec0df2c76 100644 (file)
@@ -45,11 +45,11 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
-        _1 = [const Const(Value(Scalar(0x0000000000000001)): usize), const Const(Value(Scalar(0x0000000000000002)): usize), const Const(Value(Scalar(0x0000000000000003)): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
+        _1 = [const ConstValue(Scalar(0x0000000000000001): usize), const ConstValue(Scalar(0x0000000000000002): usize), const ConstValue(Scalar(0x0000000000000003): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:17:17: 17:26
         FakeRead(ForLet(None), _1);      // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
         StorageLive(_2);                 // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
         StorageLive(_3);                 // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
-        _3 = const Const(Value(Scalar(0x0000000000000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
+        _3 = const ConstValue(Scalar(0x0000000000000000): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
         _4 = Len(_1);                    // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
         _5 = Lt(_3, _4);                 // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
@@ -62,7 +62,7 @@ fn main() -> () {
         _6 = _2;                         // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14
         FakeRead(ForLet(None), _6);      // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
         StorageLive(_7);                 // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
-        _7 = const Const(Value(Scalar(0x01)): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
+        _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
         switchInt(move _7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
     }
 
@@ -70,7 +70,7 @@ fn main() -> () {
         StorageLive(_8);                 // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
         StorageLive(_9);                 // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
         _9 = (*_6);                      // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
-        _8 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
+        _8 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14
                                          // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
@@ -79,13 +79,13 @@ fn main() -> () {
     bb3: {
         StorageDead(_9);                 // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18
         StorageDead(_8);                 // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19
-        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
+        _0 = const ConstValue(Scalar(<ZST>): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
         goto -> bb6;                     // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
     bb4: {
         StorageLive(_10);                // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
-        _10 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x0000000000000016)): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
+        _10 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14
                                          // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
@@ -93,7 +93,7 @@ fn main() -> () {
 
     bb5: {
         StorageDead(_10);                // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19
-        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
+        _0 = const ConstValue(Scalar(<ZST>): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
         goto -> bb6;                     // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
index a9af88189a67de78bcee02314831f56d355ebbab..af76d2ea42760c7fcbc3159f8566529858abc68b 100644 (file)
@@ -12,10 +12,10 @@ assert-property: (".top-doc .docblock table", {"scrollWidth": "1573"})
 
 // Logically, the ".docblock" and the "<p>" should have the same scroll width.
 compare-elements-property: (
-    "#implementations + details .docblock",
-    "#implementations + details .docblock > p",
+    "#implementations-list > details .docblock",
+    "#implementations-list > details .docblock > p",
     ["scrollWidth"],
 )
-assert-property: ("#implementations + details .docblock", {"scrollWidth": "801"})
+assert-property: ("#implementations-list > details .docblock", {"scrollWidth": "801"})
 // However, since there is overflow in the <table>, its scroll width is bigger.
-assert-property: ("#implementations + details .docblock table", {"scrollWidth": "1573"})
+assert-property: ("#implementations-list > details .docblock table", {"scrollWidth": "1573"})
index a680635ef8ae411f068db93f530ee913be1a2903..861f6928362c28e841541b3d91620b56c828fd85 100644 (file)
@@ -3,9 +3,9 @@ goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.borrow
 // In the blanket implementations list, "Borrow" is the second one, hence the ":nth(2)".
 assert-attribute: ("#blanket-implementations-list > details:nth-child(2)", {"open": ""})
 // We first check that the impl block is open by default.
-assert-attribute: ("#implementations + details", {"open": ""})
+assert-attribute: ("#implementations-list details", {"open": ""})
 // To ensure that we will click on the currently hidden method.
 assert-text: (".sidebar-elems section .block li > a", "must_use")
 click: ".sidebar-elems section .block li > a"
 // We check that the impl block was opened as expected so that we can see the method.
-assert-attribute: ("#implementations + details", {"open": ""})
+assert-attribute: ("#implementations-list > details", {"open": ""})
index 7c4496dc0cabc71e12f424e1e48101baa9907dac..6df2661e6c2bb800f67dc40e8878f3a2312263ba 100644 (file)
@@ -1,3 +1,3 @@
 // This test ensures that the impl blocks are open by default.
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
-assert-attribute: ("#main-content > details.implementors-toggle", {"open": ""})
+assert-attribute: ("#implementations-list details.implementors-toggle", {"open": ""})
index e70abcb83cf2beb76eacfd53d147aaa63d518abd..13b9b563d94e20d1cf4abefc1c9444bc0b44e5aa 100644 (file)
@@ -3,6 +3,7 @@ goto: file://|DOC_PATH|/staged_api/struct.Foo.html
 size: (400, 600)
 
 font-size: 18
+wait-for: 100 // wait a bit for the resize and the font-size change to be fully taken into account.
 
 // The out-of-band info (source, stable version, collapse) should be below the
 // h1 when the screen gets narrow enough.
@@ -18,10 +19,12 @@ assert-property: (".mobile-topbar h2.location", {"offsetHeight": 36})
 assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" })
 
 size: (1000, 1000)
+wait-for: 100 // wait a bit for the resize to be fully taken into account.
 assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since \"" })
 
 // On the settings page, the theme buttons should not line-wrap. Instead, they should
 // all be placed as a group on a line below the setting name "Theme."
 goto: file://|DOC_PATH|/settings.html
 size: (400, 600)
-compare-elements-position-near-false: ("#preferred-light-theme .setting-name", "#preferred-light-theme .choice", {"y": 16})
+// Ignored for now https://github.com/rust-lang/rust/issues/93784.
+// compare-elements-position-near-false: ("#preferred-light-theme .setting-name", "#preferred-light-theme .choice", {"y": 16})
index 375ff4878e5257e1262fe55ebb85953256a19168..ad7080c39b842cc44b7ae0827950634c8b0008f6 100644 (file)
@@ -14,3 +14,6 @@ assert-attribute: (".line-numbers > span:nth-child(6)", {"class": "line-highligh
 assert-attribute-false: (".line-numbers > span:nth-child(7)", {"class": "line-highlighted"})
 // This is to ensure that the content is correctly align with the line numbers.
 compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
+
+// Assert that the line numbers text is aligned to the right.
+assert-css: (".line-numbers", {"text-align": "right"})
index b502692300113120be7d128b5f04b066a5688c8d..ee6bc3cf7675c3d1dbf4428db04f2c2a9ce73328 100644 (file)
@@ -14,7 +14,7 @@ assert-attribute: (".top-doc", {"open": ""})
 // Assert the position of the toggle on the top doc block.
 assert-position: (".top-doc summary::before", {"x": 4})
 // Assert the position of the toggle on the impl block.
-assert-position: ("#implementations + details > summary::before", {"x": 4})
+assert-position: ("#implementations-list > details > summary::before", {"x": 4})
 // Assert the position of the toggle on a method.
 assert-position: (
     "#trait-implementations-list .impl-items .method-toggle > summary::before",
index 477105193d3eeb3e16b119ab1686eabe95fc7b14..bbc85ecd4ad49e3d75448c84bafb213644cbd601 100644 (file)
@@ -17,14 +17,21 @@ assert-text: ("#toggle-all-docs", "[−]")
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
 // We first check that everything is visible.
 assert-text: ("#toggle-all-docs", "[−]")
-assert-attribute: ("details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("#implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("#trait-implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute-false: (
+    "#blanket-implementations-list > details.rustdoc-toggle",
+    {"open": ""},
+    ALL,
+)
+
 // We collapse them all.
 click: "#toggle-all-docs"
 wait-for: 50
 assert-text: ("#toggle-all-docs", "[+]")
 // We check that all <details> are collapsed (except for the impl block ones).
 assert-attribute-false: ("details.rustdoc-toggle:not(.implementors-toggle)", {"open": ""}, ALL)
-assert-attribute: ("details.rustdoc-toggle.implementors-toggle", {"open": ""})
+assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""})
 // We now check that the other impl blocks are collapsed.
 assert-attribute-false: (
     "#blanket-implementations-list > details.rustdoc-toggle.implementors-toggle",
index 35036a89360e2734b74de01489a9fcfd7953975a..215ee228eb857dfba2f05370de52b9390a767dc8 100644 (file)
@@ -3,5 +3,5 @@
 #![allow(incomplete_features)]
 // make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647
 // @has foo/struct.Ice.html '//pre[@class="rust struct"]' \
-//      'pub struct Ice<const N: usize> where [(); N + 1]: ;'
+//      'pub struct Ice<const N: usize>;'
 pub struct Ice<const N: usize> where [(); N + 1]:;
index b018dd6cda58ac8f34819b988e4f5933fbfc3f39..84c9e4ac0cd8449200f19b4252e8c825a3adc312 100644 (file)
@@ -1,8 +1,10 @@
+// ignore-tidy-linelength
+
 // @has issue_33054/impls/struct.Foo.html
 // @has - '//h3[@class="code-header in-band"]' 'impl Foo'
 // @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
 // @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @count - '//*[@id="main-content"]/details/summary/*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1
 // @has issue_33054/impls/bar/trait.Bar.html
 // @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
 // @count - '//*[@class="struct"]' 1
diff --git a/src/test/rustdoc/generic-associated-types/issue-94683.rs b/src/test/rustdoc/generic-associated-types/issue-94683.rs
new file mode 100644 (file)
index 0000000..38ecf52
--- /dev/null
@@ -0,0 +1,13 @@
+#![crate_name = "foo"]
+#![feature(generic_associated_types)]
+
+pub trait Trait {
+    type Gat<'a>;
+}
+
+// Make sure that the elided lifetime shows up
+
+// @has foo/type.T.html
+// @has - "pub type T = "
+// @has - "&lt;'_&gt;"
+pub type T = fn(&<() as Trait>::Gat<'_>);
diff --git a/src/test/rustdoc/rfc-2632-const-trait-impl.rs b/src/test/rustdoc/rfc-2632-const-trait-impl.rs
new file mode 100644 (file)
index 0000000..2adf69f
--- /dev/null
@@ -0,0 +1,60 @@
+// Test that we do not currently display `~const` in rustdoc
+// as that syntax is currently provisional; `~const Drop` has
+// no effect on stable code so it should be hidden as well.
+//
+// To future blessers: make sure that `const_trait_impl` is
+// stabilized when changing `@!has` to `@has`, and please do
+// not remove this test.
+#![feature(const_trait_impl)]
+#![crate_name = "foo"]
+
+pub struct S<T>(T);
+
+// @!has foo/trait.Tr.html '//pre[@class="rust trait"]/code/a[@class="trait"]' '~const'
+// @!has - '//pre[@class="rust trait"]/code/a[@class="trait"]' 'Drop'
+// @has - '//pre[@class="rust trait"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//pre[@class="rust trait"]/code/span[@class="where"]' '~const'
+// @!has - '//pre[@class="rust trait"]/code/span[@class="where"]' 'Drop'
+// @has - '//pre[@class="rust trait"]/code/span[@class="where"]' ': Clone'
+pub trait Tr<T> {
+    // @!has - '//div[@id="method.a"]/h4[@class="code-header"]' '~const'
+    // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Drop'
+    // @has - '//div[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
+    // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const'
+    // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' 'Drop'
+    // @has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
+    #[default_method_body_is_const]
+    fn a<A: ~const Drop + ~const Clone>() where Option<A>: ~const Drop + ~const Clone {}
+}
+
+// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]' '~const'
+// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Drop'
+// @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Clone'
+// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where"]' '~const'
+// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' 'Drop'
+// @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' ': Clone'
+impl<T: ~const Drop + ~const Clone> const Tr<T> for T where Option<T>: ~const Drop + ~const Clone {
+    fn a<A: ~const Drop + ~const Clone>() where Option<A>: ~const Drop + ~const Clone {}
+}
+
+// @!has foo/fn.foo.html '//pre[@class="rust fn"]/code/a[@class="trait"]' '~const'
+// @!has - '//pre[@class="rust fn"]/code/a[@class="trait"]' 'Drop'
+// @has - '//pre[@class="rust fn"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' '~const'
+// @!has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' 'Drop'
+// @has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' ': Clone'
+pub const fn foo<F: ~const Drop + ~const Clone>() where Option<F>: ~const Drop + ~const Clone {
+    F::a()
+}
+
+impl<T> S<T> {
+    // @!has foo/struct.S.html '//section[@id="method.foo"]/h4[@class="code-header"]' '~const'
+    // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Drop'
+    // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
+    // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const'
+    // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' 'Drop'
+    // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
+    pub const fn foo<B: ~const Drop + ~const Clone>() where B: ~const Drop + ~const Clone {
+        B::a()
+    }
+}
index 9fb1bbebc96100847ee3e47bcf85f6c4c376743e..2f1858d39b3c6743218b3cd606bdce3751047722 100644 (file)
@@ -1,5 +1,5 @@
 // build-fail
-//~^ ERROR cycle detected when normalizing `<() as Tr>::A`
+//~^ ERROR cycle detected when normalizing `<() as Tr>::A` [E0391]
 
 // Cyclic assoc. const defaults don't error unless *used*
 trait Tr {
index 9e68e9e77515bc6633b0ad3e8a603f98c765d587..162f9e00edd81a369cfe739569cd28af4c81afe1 100644 (file)
@@ -15,9 +15,9 @@ pub trait ThriftService<Bug: NotFoo>:
 {
     fn get_service(
     //~^ ERROR the trait bound `Bug: Foo` is not satisfied
-    //~| ERROR the trait bound `Bug: Foo` is not satisfied
         &self,
     ) -> Self::AssocType;
+    //~^ the trait bound `Bug: Foo` is not satisfied
 }
 
 fn with_factory<H>(factory: dyn ThriftService<()>) {}
index 2f430d3055e1938d3820856af3c291d0988d808a..45d2dfb53757b3347685633aab67c5d4951e5257 100644 (file)
@@ -6,7 +6,7 @@ LL | |
 LL | |
 LL | |     Service<AssocType = <Bug as Foo>::OnlyFoo>
 ...  |
-LL | |     ) -> Self::AssocType;
+LL | |
 LL | | }
    | |_^ the trait `Foo` is not implemented for `Bug`
    |
@@ -23,7 +23,7 @@ LL | |
 LL | |
 LL | |     Service<AssocType = <Bug as Foo>::OnlyFoo>
 ...  |
-LL | |     ) -> Self::AssocType;
+LL | |
 LL | | }
    | |_^ the trait `Foo` is not implemented for `Bug`
    |
@@ -37,7 +37,6 @@ error[E0277]: the trait bound `Bug: Foo` is not satisfied
    |
 LL | /     fn get_service(
 LL | |
-LL | |
 LL | |         &self,
 LL | |     ) -> Self::AssocType;
    | |_________________________^ the trait `Foo` is not implemented for `Bug`
@@ -48,10 +47,10 @@ LL | pub trait ThriftService<Bug: NotFoo + Foo>:
    |                                     +++++
 
 error[E0277]: the trait bound `Bug: Foo` is not satisfied
-  --> $DIR/issue-59324.rs:16:8
+  --> $DIR/issue-59324.rs:19:10
    |
-LL |     fn get_service(
-   |        ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
+LL |     ) -> Self::AssocType;
+   |          ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
    |
 help: consider further restricting this bound
    |
index b74b16844408559a2234a3fe27a333508e4025c4..6e1b155e181eea8cc84ef2580991e7754f4f3427 100644 (file)
@@ -10,9 +10,9 @@
 
 impl IntoFuture for AwaitMe {
     type Output = i32;
-    type Future = Pin<Box<dyn Future<Output = i32>>>;
+    type IntoFuture = Pin<Box<dyn Future<Output = i32>>>;
 
-    fn into_future(self) -> Self::Future {
+    fn into_future(self) -> Self::IntoFuture {
         Box::pin(me())
     }
 }
index 8fb570d67562ab65bac889ef0cd538b902d90674..35f9c581c7b21b254a4add1f516668fa17c24229 100644 (file)
@@ -4,7 +4,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | async fn foo() {}
    | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -13,7 +13,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | fn baz() { async fn foo() {} }
    |            ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -22,7 +22,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | async fn async_baz() {
    | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -31,7 +31,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |     async fn bar() {}
    |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -40,7 +40,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |     async fn foo() {}
    |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -49,7 +49,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |     async fn foo() {}
    |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -58,7 +58,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |         async fn bar() {}
    |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -67,7 +67,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |         async fn foo() {}
    |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -76,7 +76,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |             async fn bar() {}
    |             ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0706]: functions in traits cannot be declared `async`
diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.rs b/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.rs
new file mode 100644 (file)
index 0000000..4919e0a
--- /dev/null
@@ -0,0 +1,47 @@
+// rustc-env:CARGO=/usr/bin/cargo
+
+use std::pin::Pin;
+use std::future::Future;
+
+fn main() {}
+
+fn await_on_struct_missing() {
+    struct S;
+    let x = S;
+    x.await;
+    //~^ ERROR no field `await` on type
+    //~| NOTE unknown field
+    //~| NOTE to `.await` a `Future`, switch to Rust 2018
+    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn await_on_struct_similar() {
+    struct S {
+        awai: u8,
+    }
+    let x = S { awai: 42 };
+    x.await;
+    //~^ ERROR no field `await` on type
+    //~| HELP a field with a similar name exists
+    //~| NOTE to `.await` a `Future`, switch to Rust 2018
+    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn await_on_63533(x: Pin<&mut dyn Future<Output = ()>>) {
+    x.await;
+    //~^ ERROR no field `await` on type
+    //~| NOTE unknown field
+    //~| NOTE to `.await` a `Future`, switch to Rust 2018
+    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn await_on_apit(x: impl Future<Output = ()>) {
+    x.await;
+    //~^ ERROR no field `await` on type
+    //~| NOTE to `.await` a `Future`, switch to Rust 2018
+    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.stderr b/src/test/ui/async-await/suggest-switching-edition-on-await-cargo.stderr
new file mode 100644 (file)
index 0000000..409eb17
--- /dev/null
@@ -0,0 +1,43 @@
+error[E0609]: no field `await` on type `await_on_struct_missing::S`
+  --> $DIR/suggest-switching-edition-on-await-cargo.rs:11:7
+   |
+LL |     x.await;
+   |       ^^^^^ unknown field
+   |
+   = note: to `.await` a `Future`, switch to Rust 2018 or later
+   = help: set `edition = "2021"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0609]: no field `await` on type `await_on_struct_similar::S`
+  --> $DIR/suggest-switching-edition-on-await-cargo.rs:24:7
+   |
+LL |     x.await;
+   |       ^^^^^ help: a field with a similar name exists: `awai`
+   |
+   = note: to `.await` a `Future`, switch to Rust 2018 or later
+   = help: set `edition = "2021"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0609]: no field `await` on type `Pin<&mut dyn Future<Output = ()>>`
+  --> $DIR/suggest-switching-edition-on-await-cargo.rs:33:7
+   |
+LL |     x.await;
+   |       ^^^^^ unknown field
+   |
+   = note: to `.await` a `Future`, switch to Rust 2018 or later
+   = help: set `edition = "2021"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0609]: no field `await` on type `impl Future<Output = ()>`
+  --> $DIR/suggest-switching-edition-on-await-cargo.rs:42:7
+   |
+LL |     x.await;
+   |       ^^^^^
+   |
+   = note: to `.await` a `Future`, switch to Rust 2018 or later
+   = help: set `edition = "2021"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0609`.
index f2e0fb19c631d366d6cfeee44abccb81ecc701a8..9852e8fc918fe61e2647c48e25a747444c73bd35 100644 (file)
@@ -10,7 +10,7 @@ fn await_on_struct_missing() {
     //~^ ERROR no field `await` on type
     //~| NOTE unknown field
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| HELP pass `--edition 2021` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -23,7 +23,7 @@ struct S {
     //~^ ERROR no field `await` on type
     //~| HELP a field with a similar name exists
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| HELP pass `--edition 2021` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -32,7 +32,7 @@ fn await_on_63533(x: Pin<&mut dyn Future<Output = ()>>) {
     //~^ ERROR no field `await` on type
     //~| NOTE unknown field
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| HELP pass `--edition 2021` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -40,6 +40,6 @@ fn await_on_apit(x: impl Future<Output = ()>) {
     x.await;
     //~^ ERROR no field `await` on type
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| HELP pass `--edition 2021` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
index b38c897fc7447aa8ff1866596907ec87d7e48b54..ef3334381b71524e051480a56a2a212c854caa81 100644 (file)
@@ -5,7 +5,7 @@ LL |     x.await;
    |       ^^^^^ unknown field
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0609]: no field `await` on type `await_on_struct_similar::S`
@@ -15,7 +15,7 @@ LL |     x.await;
    |       ^^^^^ help: a field with a similar name exists: `awai`
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0609]: no field `await` on type `Pin<&mut dyn Future<Output = ()>>`
@@ -25,7 +25,7 @@ LL |     x.await;
    |       ^^^^^ unknown field
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0609]: no field `await` on type `impl Future<Output = ()>`
@@ -35,7 +35,7 @@ LL |     x.await;
    |       ^^^^^
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: aborting due to 4 previous errors
index e2c8073241487c805e027e3925b5749ada3d8a23..d88185af778f16b75b31488f5b45bf67488b4ee8 100644 (file)
@@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard
   --> $DIR/borrowck-feature-nll-overrides-migrate.rs:22:18
    |
 LL |                 (|| { let bar = foo; bar.take() })();
-   |                  ^^             ---
-   |                  |              |
-   |                  |              move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
-   |                  |              move occurs due to use in closure
+   |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                  |
    |                  move out of `foo` occurs here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
index e2c8073241487c805e027e3925b5749ada3d8a23..d88185af778f16b75b31488f5b45bf67488b4ee8 100644 (file)
@@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard
   --> $DIR/borrowck-feature-nll-overrides-migrate.rs:22:18
    |
 LL |                 (|| { let bar = foo; bar.take() })();
-   |                  ^^             ---
-   |                  |              |
-   |                  |              move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
-   |                  |              move occurs due to use in closure
+   |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                  |
    |                  move out of `foo` occurs here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
index 257ec3fbb7fa237266afbbf31f219c92eea359e4..f81b34a641bf081c1121ea189dcdd929e2a2b626 100644 (file)
@@ -8,8 +8,8 @@ LL |       let _g = to_fn_mut(|| {
 LL | |         let _h = to_fn_once(move || -> isize { *bar });
    | |                             ^^^^^^^^^^^^^^^^   ----
    | |                             |                  |
+   | |                             |                  variable moved due to use in closure
    | |                             |                  move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
-   | |                             |                  move occurs due to use in closure
    | |                             move out of `bar` occurs here
 LL | |     });
    | |_____- captured by this `FnMut` closure
index 79745065070977f884d6f4f778251d40acdfea66..800f30b34e58921dd71977b9d9c753562928429a 100644 (file)
@@ -2,7 +2,16 @@ error[E0507]: cannot move out of an `Rc`
   --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:4:14
    |
 LL |     let _x = Rc::new(vec![1, 2]).into_iter();
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
+   |              ^^^^^^^^^^^^^^^^^^^^-----------
+   |              |                   |
+   |              |                   value moved due to this method call
+   |              move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
+   |
+note: this function takes ownership of the receiver `self`, which moves value
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/copy-suggestion-region-vid.rs b/src/test/ui/borrowck/copy-suggestion-region-vid.rs
new file mode 100644 (file)
index 0000000..dff9528
--- /dev/null
@@ -0,0 +1,17 @@
+pub struct DataStruct();
+
+pub struct HelperStruct<'n> {
+    pub helpers: [Vec<&'n i64>; 2],
+    pub is_empty: bool,
+}
+
+impl DataStruct {
+    pub fn f(&self) -> HelperStruct {
+        let helpers = [vec![], vec![]];
+
+        HelperStruct { helpers, is_empty: helpers[0].is_empty() }
+        //~^ ERROR borrow of moved value
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/copy-suggestion-region-vid.stderr b/src/test/ui/borrowck/copy-suggestion-region-vid.stderr
new file mode 100644 (file)
index 0000000..f03cdd8
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0382]: borrow of moved value: `helpers`
+  --> $DIR/copy-suggestion-region-vid.rs:12:43
+   |
+LL |         let helpers = [vec![], vec![]];
+   |             ------- move occurs because `helpers` has type `[Vec<&i64>; 2]`, which does not implement the `Copy` trait
+LL | 
+LL |         HelperStruct { helpers, is_empty: helpers[0].is_empty() }
+   |                        -------            ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
+   |                        |
+   |                        value moved here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
index 540f7f8a484776d3b36fcb795999f10f3dd074b4..c4ce7e62fda82bc24bb45d8b3f90b7afb8f9664b 100644 (file)
@@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard
   --> $DIR/issue-27282-mutation-in-guard.rs:6:18
    |
 LL |                 (|| { let bar = foo; bar.take() })();
-   |                  ^^             ---
-   |                  |              |
-   |                  |              move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
-   |                  |              move occurs due to use in closure
+   |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                  |
    |                  move out of `foo` occurs here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
index db348a50aa4298fe7690f74d0e943781f9d056dd..632f8dc3ad6f5dfe7c6dfe9a5a84b8e503a3c593 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 // Regression test related to issue 88434
 
 const _CONST: &() = &f(&|_| {});
index 845e1bdba8fc03fce5a3545390c32aec0621bcd1..d9635e1ee464ce514a16bd858292bcae3311dcc9 100644 (file)
@@ -1,14 +1,14 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-88434-minimal-example.rs:10:5
+  --> $DIR/issue-88434-minimal-example.rs:9:5
    |
 LL | const _CONST: &() = &f(&|_| {});
-   |                      ---------- inside `_CONST` at $DIR/issue-88434-minimal-example.rs:4:22
+   |                      ---------- inside `_CONST` at $DIR/issue-88434-minimal-example.rs:3:22
 ...
 LL |     panic!()
    |     ^^^^^^^^
    |     |
-   |     the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:10:5
-   |     inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:4:25: 4:31]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+   |     the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:9:5
+   |     inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:31]>` at $SRC_DIR/std/src/panic.rs:LL:COL
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index 4db073c66b1f368fb601a5d27132dd2bfd0b78c2..f0a6dcd4eb3b885a0b4eee555690ae1514590204 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 // Regression test for issue 88434
 
 const _CONST: &[u8] = &f(&[], |_| {});
index 8cbb6a6340c7f5b8641e65c4c1f62e41aaa14fce..44e244ae9cc3f9463736309c86628794d8eecbfb 100644 (file)
@@ -1,14 +1,14 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-88434-removal-index-should-be-less.rs:10:5
+  --> $DIR/issue-88434-removal-index-should-be-less.rs:9:5
    |
 LL | const _CONST: &[u8] = &f(&[], |_| {});
-   |                        -------------- inside `_CONST` at $DIR/issue-88434-removal-index-should-be-less.rs:4:24
+   |                        -------------- inside `_CONST` at $DIR/issue-88434-removal-index-should-be-less.rs:3:24
 ...
 LL |     panic!()
    |     ^^^^^^^^
    |     |
-   |     the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:10:5
-   |     inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:4:31: 4:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+   |     the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:9:5
+   |     inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index 1663ce81d6cf446b5819502eb7b14b8f8c108884..3ea7226200362c77be54afd1e5b56fd1f584691b 100644 (file)
@@ -6,10 +6,18 @@ LL |       let y = vec![format!("World")];
 LL |       call(|| {
    |  __________-
 LL | |         y.into_iter();
-   | |         ^ move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
+   | |         ^ ----------- `y` moved due to this method call
+   | |         |
+   | |         move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
 LL | |
 LL | |     });
    | |_____- captured by this `Fn` closure
+   |
+note: this function takes ownership of the receiver `self`, which moves `y`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to previous error
 
index a0fad583a1645a069f3fbbf0be75dd329ac0a648..b5276dc619bfb4c1835ff99ffae403b9fec0afdc 100644 (file)
@@ -19,6 +19,15 @@ fn main() {
     q as *const [i32]; //~ ERROR cannot cast
 
     // #21397
-    let t: *mut (dyn Trait + 'static) = 0 as *mut _; //~ ERROR casting
-    let mut fail: *const str = 0 as *const str; //~ ERROR casting
+    let t: *mut (dyn Trait + 'static) = 0 as *mut _;
+    //~^ ERROR cannot cast `usize` to a pointer that is wide
+    let mut fail: *const str = 0 as *const str;
+    //~^ ERROR cannot cast `usize` to a pointer that is wide
+    let mut fail2: *const str = 0isize as *const str;
+    //~^ ERROR cannot cast `isize` to a pointer that is wide
+}
+
+fn foo<T: ?Sized>() {
+    let s = 0 as *const T;
+    //~^ ERROR cannot cast `usize` to a pointer that may be wide
 }
index 0b0c288fe3b6169acbb88b0c191bcc0a75cf01b5..18e7b68ff3c22ad1c37e86661e08d22025118acc 100644 (file)
@@ -50,19 +50,39 @@ error[E0607]: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]
 LL |     q as *const [i32];
    |     ^^^^^^^^^^^^^^^^^
 
-error[E0606]: casting `usize` as `*mut (dyn Trait + 'static)` is invalid
-  --> $DIR/fat-ptr-cast.rs:22:41
+error[E0606]: cannot cast `usize` to a pointer that is wide
+  --> $DIR/fat-ptr-cast.rs:22:46
    |
 LL |     let t: *mut (dyn Trait + 'static) = 0 as *mut _;
-   |                                         ^^^^^^^^^^^
+   |                                         -    ^^^^^^ creating a `*mut (dyn Trait + 'static)` requires both an address and a vtable
+   |                                         |
+   |                                         consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
 
-error[E0606]: casting `usize` as `*const str` is invalid
-  --> $DIR/fat-ptr-cast.rs:23:32
+error[E0606]: cannot cast `usize` to a pointer that is wide
+  --> $DIR/fat-ptr-cast.rs:24:37
    |
 LL |     let mut fail: *const str = 0 as *const str;
-   |                                ^^^^^^^^^^^^^^^
+   |                                -    ^^^^^^^^^^ creating a `*const str` requires both an address and a length
+   |                                |
+   |                                consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
 
-error: aborting due to 9 previous errors
+error[E0606]: cannot cast `isize` to a pointer that is wide
+  --> $DIR/fat-ptr-cast.rs:26:43
+   |
+LL |     let mut fail2: *const str = 0isize as *const str;
+   |                                 ------    ^^^^^^^^^^ creating a `*const str` requires both an address and a length
+   |                                 |
+   |                                 consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
+
+error[E0606]: cannot cast `usize` to a pointer that may be wide
+  --> $DIR/fat-ptr-cast.rs:31:18
+   |
+LL |     let s = 0 as *const T;
+   |             -    ^^^^^^^^ creating a `*const T` requires both an address and type-specific metadata
+   |             |
+   |             consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
+
+error: aborting due to 11 previous errors
 
 Some errors have detailed explanations: E0605, E0606, E0607.
 For more information about an error, try `rustc --explain E0605`.
index a66568a2ffdc98efe62dc3830e52eab824e49fe2..e57fb69a1e05f2d94a7982ee39af6fa2b4fb03fd 100644 (file)
@@ -24,4 +24,10 @@ fn unix_misspell() {}
 #[cfg(unix)]
 fn unix() {}
 
+#[cfg(miri)]
+fn miri() {}
+
+#[cfg(doc)]
+fn doc() {}
+
 fn main() {}
index 46004be43d812291fe0215e38ed99730e33cfc10..96375dc8d3130e0518ddaa49d1df7974b3232898 100644 (file)
@@ -25,4 +25,18 @@ fn unix_with_value() {}
 #[cfg(unix)]
 fn unix() {}
 
+#[cfg(miri = "miri")]
+//~^ WARNING unexpected `cfg` condition value
+fn miri_with_value() {}
+
+#[cfg(miri)]
+fn miri() {}
+
+#[cfg(doc = "linux")]
+//~^ WARNING unexpected `cfg` condition value
+fn doc_with_value() {}
+
+#[cfg(doc)]
+fn doc() {}
+
 fn main() {}
index 8eefd6aaf35ec468548874d942b83be12d019632..8b04c770fb505f99c805aabaf8a938b56ceabf9d 100644 (file)
@@ -29,5 +29,25 @@ LL | #[cfg(unix = "aa")]
    |
    = note: no expected value for `unix`
 
-warning: 3 warnings emitted
+warning: unexpected `cfg` condition value
+  --> $DIR/well-known-values.rs:28:7
+   |
+LL | #[cfg(miri = "miri")]
+   |       ^^^^---------
+   |           |
+   |           help: remove the value
+   |
+   = note: no expected value for `miri`
+
+warning: unexpected `cfg` condition value
+  --> $DIR/well-known-values.rs:35:7
+   |
+LL | #[cfg(doc = "linux")]
+   |       ^^^----------
+   |          |
+   |          help: remove the value
+   |
+   = note: no expected value for `doc`
+
+warning: 5 warnings emitted
 
index f02d23464f168284574dd689d4cfc2666463250b..7e22defa98dd460e43b091b5b56af30f090b7981 100644 (file)
@@ -1,26 +1,38 @@
 error[E0004]: non-exhaustive patterns: `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
   --> $DIR/issue-88331.rs:11:20
    |
-LL | pub struct Opcode(pub u8);
-   | -------------------------- `Opcode` defined here
-...
 LL |     move |i| match msg_type {
    |                    ^^^^^^^^ patterns `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Opcode` defined here
+  --> $DIR/issue-88331.rs:4:12
+   |
+LL | pub struct Opcode(pub u8);
+   |            ^^^^^^
    = note: the matched value is of type `Opcode`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         Opcode::OP1 => unimplemented!(),
+LL ~         Opcode(0_u8) | Opcode(2_u8..=u8::MAX) => todo!(),
+   |
 
 error[E0004]: non-exhaustive patterns: `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
   --> $DIR/issue-88331.rs:27:20
    |
-LL | pub struct Opcode2(Opcode);
-   | --------------------------- `Opcode2` defined here
-...
 LL |     move |i| match msg_type {
    |                    ^^^^^^^^ patterns `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Opcode2` defined here
+  --> $DIR/issue-88331.rs:18:12
+   |
+LL | pub struct Opcode2(Opcode);
+   |            ^^^^^^^
    = note: the matched value is of type `Opcode2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         Opcode2::OP2=> unimplemented!(),
+LL ~         Opcode2(Opcode(0_u8)) | Opcode2(Opcode(2_u8..=u8::MAX)) => todo!(),
+   |
 
 error: aborting due to 2 previous errors
 
index 91ffe1a47f4134f460d65cb6e933cee0f6a2ea09..32d36274ff6ef7aed9b85878e020c4f044814e21 100644 (file)
@@ -1,17 +1,19 @@
 error[E0004]: non-exhaustive patterns: `B` not covered
   --> $DIR/non-exhaustive-match.rs:26:25
    |
-LL | enum L1 { A, B }
-   | ----------------
-   | |            |
-   | |            not covered
-   | `L1` defined here
-...
 LL |     let _b = || { match l1 { L1::A => () } };
    |                         ^^ pattern `B` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `L1` defined here
+  --> $DIR/non-exhaustive-match.rs:12:14
+   |
+LL | enum L1 { A, B }
+   |      --      ^ not covered
    = note: the matched value is of type `L1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |     let _b = || { match l1 { L1::A => (), B => todo!() } };
+   |                                         ++++++++++++++
 
 error[E0004]: non-exhaustive patterns: type `E1` is non-empty
   --> $DIR/non-exhaustive-match.rs:37:25
@@ -19,8 +21,18 @@ error[E0004]: non-exhaustive patterns: type `E1` is non-empty
 LL |     let _d = || { match e1 {} };
    |                         ^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E1` defined here
+  --> $DIR/auxiliary/match_non_exhaustive_lib.rs:2:1
+   |
+LL | pub enum E1 {}
+   | ^^^^^^^^^^^^^^
    = note: the matched value is of type `E1`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     let _d = || { match e1 {
+LL +         _ => todo!(),
+LL ~     } };
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/non-exhaustive-match.rs:39:25
@@ -28,8 +40,16 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     let _e = || { match e2 { E2::A => (), E2::B => () } };
    |                         ^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E2` defined here
+  --> $DIR/auxiliary/match_non_exhaustive_lib.rs:5:1
+   |
+LL | pub enum E2 { A, B }
+   | ^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `E2`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |     let _e = || { match e2 { E2::A => (), E2::B => (), _ => todo!() } };
+   |                                                      ++++++++++++++
 
 error[E0505]: cannot move out of `e3` because it is borrowed
   --> $DIR/non-exhaustive-match.rs:46:22
index 45641ea3de3e0812b30da2653a18bdf037830530..e55fb7ce4bbe9528a70b259251de935fda539d20 100644 (file)
@@ -4,8 +4,13 @@ error[E0004]: non-exhaustive patterns: type `u8` is non-empty
 LL |     let c1 = || match x { };
    |                       ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     let c1 = || match x {
+LL +         _ => todo!(),
+LL ~     };
+   |
 
 error[E0381]: use of possibly-uninitialized variable: `x`
   --> $DIR/pattern-matching-should-fail.rs:8:23
index 9e4521df8c34f4d84c065af641cf79abad1f29e8..bbc039bdf5c7bec56625d64c98ba26038f0d1c54 100644 (file)
@@ -7,6 +7,7 @@
 pub trait Sized { }
 #[lang="copy"]
 pub trait Copy { }
+impl Copy for u32 {}
 
 extern "rust-intrinsic" {
     pub fn transmute<T, U>(e: T) -> U;
index d5c67af2b41464fab168132c2e405752193e8963..b8112b20a54c6429832283028feb298334f2c64b 100644 (file)
@@ -7,6 +7,7 @@
 pub trait Sized { }
 #[lang="copy"]
 pub trait Copy { }
+impl Copy for u32 {}
 
 extern "rust-intrinsic" {
     pub fn transmute<T, U>(e: T) -> U;
index 8cde9ba58b93b0a3e24c228cc01186d5074bd935..5591a8a5864b5bb8e2d15e1e5799d18c07d7eecb 100644 (file)
@@ -7,6 +7,7 @@
 trait Sized { }
 #[lang="copy"]
 trait Copy { }
+impl Copy for u32 {}
 
 #[no_mangle]
 #[cmse_nonsecure_entry]
index 9a1b0a38d5eacc21656b6023ac27bde63369119f..39b41dac41f773aa86de0243068e64e8189f4205 100644 (file)
@@ -7,6 +7,7 @@
 trait Sized { }
 #[lang="copy"]
 trait Copy { }
+impl Copy for u32 {}
 
 #[no_mangle]
 #[cmse_nonsecure_entry]
diff --git a/src/test/ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs b/src/test/ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs
new file mode 100644 (file)
index 0000000..df454da
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(generic_const_exprs)]
+
+use std::str::FromStr;
+
+pub struct If<const CONDITION: bool>;
+
+pub trait True {}
+
+impl True for If<true> {}
+
+pub struct FixedI32<const FRAC: u32>;
+
+impl<const FRAC: u32> FromStr for FixedI32<FRAC>
+where
+    If<{ FRAC <= 32 }>: True,
+{
+    type Err = ();
+    fn from_str(_s: &str) -> Result<Self, Self::Err> {
+        unimplemented!()
+    }
+}
index 771e68b0db58a0c049309d42b14b5163b817650d..e86ffbf10757e6154f9326c5cfba2aee8cf706e1 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(const_fn_trait_bound, generic_const_exprs)]
+#![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
 
 trait _Contains<T> {
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-94287.rs b/src/test/ui/const-generics/generic_const_exprs/issue-94287.rs
new file mode 100644 (file)
index 0000000..643126a
--- /dev/null
@@ -0,0 +1,10 @@
+// aux-build:issue-94287-aux.rs
+// build-fail
+
+extern crate issue_94287_aux;
+
+use std::str::FromStr;
+
+fn main() {
+    let _ = <issue_94287_aux::FixedI32<16>>::from_str("");
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr
new file mode 100644 (file)
index 0000000..c918651
--- /dev/null
@@ -0,0 +1,14 @@
+error: failed to evaluate generic const expression
+  --> $DIR/auxiliary/issue-94287-aux.rs:15:8
+   |
+LL |     If<{ FRAC <= 32 }>: True,
+   |        ^^^^^^^^^^^^^^
+   |
+   = note: the crate this constant originates from uses `#![feature(generic_const_exprs)]`
+help: consider enabling this feature
+   |
+LL | #![feature(generic_const_exprs)]
+   |
+
+error: aborting due to previous error
+
index 2f196533dd88c931c131d9696c149a68ec14363b..ff141d328e6272b78a41cc26b65c900cf8cf931f 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(const_fn_trait_bound, generic_const_exprs)]
+#![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
 
 trait MiniTypeId {
index bf0b01a2ecfe0d89ed0005dc4af6ccb963a7df1a..88cea60e1b89e133344e14745939745f437166a0 100644 (file)
@@ -1,6 +1,5 @@
 // Crate that exports a const fn. Used for testing cross-crate.
 
-#![feature(const_fn_fn_ptr_basics)]
 #![crate_type="rlib"]
 
 pub const fn foo() -> usize { 22 }
index f3c82c5f96816280de4c0de4e239561b3f5c9bdf..1ccd0ee937067755115a138694e96246ff4ba31d 100644 (file)
@@ -1,5 +1,5 @@
 #![allow(unused)]
-#![feature(const_fn_trait_bound, const_trait_impl, inline_const, negative_impls)]
+#![feature(const_trait_impl, inline_const, negative_impls)]
 
 const fn f<T: ~const Drop>(x: T) {}
 
index 8c3959cc11a431c20c5fa78dd29eb27eb0663614..e73e54ff5f1b37d667fe486e3deb60312f4721e9 100644 (file)
@@ -1,5 +1,5 @@
-//~ERROR constructed but no error reported
 // compile-flags: -Ztreat-err-as-bug=2
+//~^ ERROR 1:1: 1:1: ty::ConstKind::Error constructed but no error reported
 // build-fail
 // failure-status: 101
 // rustc-env:RUST_BACKTRACE=1
index a16ac7b2a24ee9d1e740020fb85f68f96adbb1b3..ca1585f883759914e1eaed0887a109364d94c9b3 100644 (file)
@@ -10,23 +10,11 @@ help: skipping check that does not even have a feature gate
    |
 LL |     X_CONST(x)
    |     ^^^^^^^^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr.rs:18:14
-   |
-LL | const fn foo(x: fn(usize) -> usize, y: usize)  -> usize {
-   |              ^
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr.rs:19:5
-   |
-LL |     x(y)
-   |     ^
 help: skipping check that does not even have a feature gate
   --> $DIR/const_fn_ptr.rs:19:5
    |
 LL |     x(y)
    |     ^^^^
 
-error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
-
-error: aborting due to previous error; 1 warning emitted
+warning: 1 warning emitted
 
index 4f7a771f4184f8d50555f5476b9ae06d11dfdcaa..c17166263ba09ddaa34f9de7f07f7e8dc8940bba 100644 (file)
@@ -12,16 +12,6 @@ LL |     assert_eq!(Z, 4);
 
 warning: skipping const checks
    |
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr_fail2.rs:11:14
-   |
-LL | const fn bar(x: fn(usize) -> usize, y: usize) -> usize {
-   |              ^
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr_fail2.rs:12:5
-   |
-LL |     x(y)
-   |     ^
 help: skipping check that does not even have a feature gate
   --> $DIR/const_fn_ptr_fail2.rs:12:5
    |
index 80f6bbec2a181f04d6146376b12e96c246ee72a8..917777a32fff3118a842763679d5abe2f2b49581 100644 (file)
@@ -1,7 +1,5 @@
 // issue-49296: Unsafe shenigans in constants can result in missing errors
 
-#![feature(const_fn_trait_bound)]
-
 use std::mem::transmute;
 
 const fn wat(x: u64) -> &'static u64 {
index bc3074b10bee6f326c048121d07b093515e63e46..1864a284579109c3b4a6960414e7ae97f550fad4 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-49296.rs:11:16
+  --> $DIR/issue-49296.rs:9:16
    |
 LL | const X: u64 = *wat(42);
    |                ^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
index bf8bae5ea2c73609d5359a9b35ac19220d15e296..abd1d32abe28904fa78350c91b133d828e9828c5 100644 (file)
@@ -1,5 +1,4 @@
 // check-pass
-#![feature(const_fn_fn_ptr_basics)]
 
 const fn nested(x: (for<'a> fn(&'a ()), String)) -> (fn(&'static ()), String) {
     x
index 46748673067cebb02e795c78449a413186722521..c7078e46fa64fc21d694d602ad988df91cc790c0 100644 (file)
@@ -2,8 +2,6 @@
 
 const extern "C" fn unsize(x: &[u8; 3]) -> &[u8] { x }
 const unsafe extern "C" fn closure() -> fn() { || {} }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
 const unsafe extern "C" fn use_float() { 1.0 + 1.0; }
 //~^ ERROR floating point arithmetic
 const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
index 2b2d23477f681365370ce6589eb79005dda28b51..4bab466fb95a7e7b5892a4884a4cede9345c5256 100644 (file)
@@ -1,23 +1,5 @@
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/const-extern-fn-min-const-fn.rs:4:41
-   |
-LL | const unsafe extern "C" fn closure() -> fn() { || {} }
-   |                                         ^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/const-extern-fn-min-const-fn.rs:4:48
-   |
-LL | const unsafe extern "C" fn closure() -> fn() { || {} }
-   |                                                ^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
 error[E0658]: floating point arithmetic is not allowed in constant functions
-  --> $DIR/const-extern-fn-min-const-fn.rs:7:42
+  --> $DIR/const-extern-fn-min-const-fn.rs:5:42
    |
 LL | const unsafe extern "C" fn use_float() { 1.0 + 1.0; }
    |                                          ^^^^^^^^^
@@ -26,7 +8,7 @@ LL | const unsafe extern "C" fn use_float() { 1.0 + 1.0; }
    = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable
 
 error: pointers cannot be cast to integers during const eval
-  --> $DIR/const-extern-fn-min-const-fn.rs:9:48
+  --> $DIR/const-extern-fn-min-const-fn.rs:7:48
    |
 LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
    |                                                ^^^^^^^^^^^^
@@ -34,6 +16,6 @@ LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
    = note: at compile-time, pointers do not have an integer value
    = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index 1928c51885efff2d97205da720e57fad152097b1..59680e6e4a8e370ff23fa866a6306d85ce9fb81c 100644 (file)
@@ -4,7 +4,6 @@
 // A very basic test of const fn functionality.
 
 #![feature(const_indexing)]
-#![feature(const_fn_trait_bound)]
 
 const fn add(x: u32, y: u32) -> u32 {
     x + y
index 4141cc4ab1a48d90a0ebae26159c61ec0f7ad1ee..6e61dbbd8eee3906a3bb8b50131dff54d2f410b2 100644 (file)
@@ -7,10 +7,10 @@ LL |     A = { let 0 = 0; 0 },
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     A = { if let 0 = 0 { /* */ } 0 },
-   |           ~~~~~~~~~~~~~~~~~~~~~~
+LL |     A = { if let 0 = 0 { todo!() } 0 },
+   |           ++           ~~~~~~~~~~~
 
 error: aborting due to previous error
 
index af86ba0cc82f8684a440e85df82d0f1a20ca296e..1b3b6e06c3df611e98de7a42ec2d342ac19fb1b6 100644 (file)
@@ -7,10 +7,10 @@ LL |     let x: [i32; { let 0 = 0; 0 }] = [];
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     let x: [i32; { if let 0 = 0 { /* */ } 0 }] = [];
-   |                    ~~~~~~~~~~~~~~~~~~~~~~
+LL |     let x: [i32; { if let 0 = 0 { todo!() } 0 }] = [];
+   |                    ++           ~~~~~~~~~~~
 
 error: aborting due to previous error
 
index f71490eba613541be69dc6956a977315fc1dac49..bc8edfa7af9f488dacfabc9dffe769609f0ce517 100644 (file)
@@ -7,10 +7,10 @@ LL | const X: i32 = { let 0 = 0; 0 };
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL | const X: i32 = { if let 0 = 0 { /* */ } 0 };
-   |                  ~~~~~~~~~~~~~~~~~~~~~~
+LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
+   |                  ++           ~~~~~~~~~~~
 
 error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:8:23
@@ -21,10 +21,10 @@ LL | static Y: i32 = { let 0 = 0; 0 };
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL | static Y: i32 = { if let 0 = 0 { /* */ } 0 };
-   |                   ~~~~~~~~~~~~~~~~~~~~~~
+LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 };
+   |                   ++           ~~~~~~~~~~~
 
 error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:13:26
@@ -35,10 +35,10 @@ LL |     const X: i32 = { let 0 = 0; 0 };
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     const X: i32 = { if let 0 = 0 { /* */ } 0 };
-   |                      ~~~~~~~~~~~~~~~~~~~~~~
+LL |     const X: i32 = { if let 0 = 0 { todo!() } 0 };
+   |                      ++           ~~~~~~~~~~~
 
 error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:19:26
@@ -49,10 +49,10 @@ LL |     const X: i32 = { let 0 = 0; 0 };
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     const X: i32 = { if let 0 = 0 { /* */ } 0 };
-   |                      ~~~~~~~~~~~~~~~~~~~~~~
+LL |     const X: i32 = { if let 0 = 0 { todo!() } 0 };
+   |                      ++           ~~~~~~~~~~~
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/consts/const_fn_trait_bound.gated.stderr b/src/test/ui/consts/const_fn_trait_bound.gated.stderr
deleted file mode 100644 (file)
index ded05cb..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: fatal error triggered by #[rustc_error]
-  --> $DIR/const_fn_trait_bound.rs:17:1
-   |
-LL | fn main() {}
-   | ^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/consts/const_fn_trait_bound.rs b/src/test/ui/consts/const_fn_trait_bound.rs
deleted file mode 100644 (file)
index 19c08b6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// gate-test-const_fn_trait_bound
-
-// revisions: stock gated
-
-#![feature(rustc_attrs)]
-#![cfg_attr(gated, feature(const_fn_trait_bound))]
-
-const fn test1<T: std::ops::Add>() {}
-//[stock]~^ trait bounds
-const fn test2(_x: &dyn Send) {}
-//[stock]~^ trait objects in const fn are unstable
-const fn test3() -> &'static dyn Send { loop {} }
-//[stock]~^ trait objects in const fn are unstable
-
-
-#[rustc_error]
-fn main() {} //[gated]~ fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/consts/const_fn_trait_bound.stock.stderr b/src/test/ui/consts/const_fn_trait_bound.stock.stderr
deleted file mode 100644 (file)
index 7d9e18c..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/const_fn_trait_bound.rs:8:16
-   |
-LL | const fn test1<T: std::ops::Add>() {}
-   |                ^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/const_fn_trait_bound.rs:10:16
-   |
-LL | const fn test2(_x: &dyn Send) {}
-   |                ^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/const_fn_trait_bound.rs:12:21
-   |
-LL | const fn test3() -> &'static dyn Send { loop {} }
-   |                     ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/drop_box.rs b/src/test/ui/consts/drop_box.rs
new file mode 100644 (file)
index 0000000..58a373a
--- /dev/null
@@ -0,0 +1,4 @@
+const fn f<T>(_: Box<T>) {}
+//~^ ERROR destructors cannot be evaluated at compile-time
+
+fn main() {}
diff --git a/src/test/ui/consts/drop_box.stderr b/src/test/ui/consts/drop_box.stderr
new file mode 100644 (file)
index 0000000..b9d6581
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop_box.rs:1:15
+   |
+LL | const fn f<T>(_: Box<T>) {}
+   |               ^           - value is dropped here
+   |               |
+   |               constant functions cannot evaluate destructors
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0493`.
index 35b63bddca252937d815454a2a67733e42ea658b..4d00ac7fd0d59d23c256bbfd98a3ba9881f38bb9 100644 (file)
@@ -1,6 +1,8 @@
+// check-pass
+
 const fn x() {
     let t = true;
-    let x = || t; //~ ERROR function pointer
+    let x = || t;
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/issue-37550-1.stderr b/src/test/ui/consts/issue-37550-1.stderr
deleted file mode 100644 (file)
index f66d706..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/issue-37550-1.rs:3:9
-   |
-LL |     let x = || t;
-   |         ^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
index 15877c53747ec0a3171a7ee2159d069ffcdfdf4c..724eb28291ebc82b9f5ae650379a52e65c953eda 100644 (file)
@@ -2,8 +2,6 @@
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
-#![feature(const_fn_fn_ptr_basics)]
-
 const fn x() {
     let t = true;
     let x = || t;
index 0a1e835672de9db26f312254c9c7e608db2d126f..9438df1937bddecc20d7ac7edecb8a4867787205 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(const_fn_fn_ptr_basics)]
 #![deny(const_err)]
 
 pub struct Data<T> {
index 9c673d20b2a9565549532cd4ac1df0d0cab8cfba..22ac75514f62466611582baec0b931ee6bd2c2b9 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(const_fn_fn_ptr_basics)]
-
 const fn foo() { (||{})() }
 //~^ ERROR cannot call non-const closure
 
index 62a7c7db6b83ae0311894706e2ec70bcb2f69f3a..803424eedf32a18ed77393baf85f2db02d08dce7 100644 (file)
@@ -1,5 +1,5 @@
 error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/issue-56164.rs:3:18
+  --> $DIR/issue-56164.rs:1:18
    |
 LL | const fn foo() { (||{})() }
    |                  ^^^^^^^^
@@ -8,7 +8,7 @@ LL | const fn foo() { (||{})() }
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: function pointers are not allowed in const fn
-  --> $DIR/issue-56164.rs:7:5
+  --> $DIR/issue-56164.rs:5:5
    |
 LL |     input()
    |     ^^^^^^^
index a2d4a642128b4f9471b8fe3c46a31b448f5f7c63..1c38c43e6c0c51292592f592818580a3af00c81c 100644 (file)
@@ -3,7 +3,6 @@
 // regression test for #88071
 
 #![feature(const_btree_new)]
-#![feature(const_fn_trait_bound)]
 
 use std::collections::BTreeMap;
 
diff --git a/src/test/ui/consts/issue-94675.rs b/src/test/ui/consts/issue-94675.rs
new file mode 100644 (file)
index 0000000..0604aab
--- /dev/null
@@ -0,0 +1,16 @@
+#![feature(const_trait_impl, const_mut_refs)]
+
+struct Foo<'a> {
+    bar: &'a mut Vec<usize>,
+}
+
+impl<'a> Foo<'a> {
+    const fn spam(&mut self, baz: &mut Vec<u32>) {
+        self.bar[0] = baz.len();
+        //~^ ERROR cannot call non-const fn `Vec::<u32>::len` in constant functions
+        //~| ERROR the trait bound `Vec<usize>: ~const IndexMut<usize>` is not satisfied
+        //~| ERROR cannot call non-const operator in constant functions
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-94675.stderr b/src/test/ui/consts/issue-94675.stderr
new file mode 100644 (file)
index 0000000..6665e42
--- /dev/null
@@ -0,0 +1,38 @@
+error[E0015]: cannot call non-const fn `Vec::<u32>::len` in constant functions
+  --> $DIR/issue-94675.rs:9:27
+   |
+LL |         self.bar[0] = baz.len();
+   |                           ^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0277]: the trait bound `Vec<usize>: ~const IndexMut<usize>` is not satisfied
+  --> $DIR/issue-94675.rs:9:9
+   |
+LL |         self.bar[0] = baz.len();
+   |         ^^^^^^^^^^^ vector indices are of type `usize` or ranges of `usize`
+   |
+   = help: the trait `~const IndexMut<usize>` is not implemented for `Vec<usize>`
+note: the trait `IndexMut<usize>` is implemented for `Vec<usize>`, but that implementation is not `const`
+  --> $DIR/issue-94675.rs:9:9
+   |
+LL |         self.bar[0] = baz.len();
+   |         ^^^^^^^^^^^
+
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/issue-94675.rs:9:9
+   |
+LL |         self.bar[0] = baz.len();
+   |         ^^^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+   |
+LL | impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
deleted file mode 100644 (file)
index a0870ea..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(rustc_attrs, staged_api, rustc_allow_const_fn_unstable)]
-#![feature(const_fn_fn_ptr_basics)]
-#![stable(feature = "rust1", since = "1.0.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(since="1.0.0", feature = "mep")]
-const fn error(_: fn()) {}
-//~^ ERROR const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(since="1.0.0", feature = "mep")]
-#[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
-const fn compiles(_: fn()) {}
-
-fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
deleted file mode 100644 (file)
index 3523cab..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
-  --> $DIR/allow_const_fn_ptr.rs:7:16
-   |
-LL | const fn error(_: fn()) {}
-   |                ^
-   |
-help: if it is not part of the public API, make this function unstably const
-   |
-LL | #[rustc_const_unstable(feature = "...", issue = "...")]
-   |
-help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
-   |
-LL | #[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
-   |
-
-error: aborting due to previous error
-
index 430e911aacdee7fb09785b067fd9e0fd906337f3..2dbc424d3ba2d76dc59ca5096239457e54aaa7c2 100644 (file)
@@ -1,13 +1,11 @@
 // run-pass
 #![feature(rustc_allow_const_fn_unstable)]
-#![feature(const_fn_fn_ptr_basics)]
 
 #![feature(rustc_attrs, staged_api)]
 #![stable(feature = "rust1", since = "1.0.0")]
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(since="1.0.0", feature = "mep")]
-#[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
 const fn takes_fn_ptr(_: fn()) {}
 
 const FN: fn() = || ();
diff --git a/src/test/ui/consts/min_const_fn/cast_errors.rs b/src/test/ui/consts/min_const_fn/cast_errors.rs
deleted file mode 100644 (file)
index b68f47f..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-fn main() {}
-
-const fn unsize(x: &[u8; 3]) -> &[u8] { x }
-const fn closure() -> fn() { || {} }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
-const fn closure2() {
-    (|| {}) as fn();
-//~^ ERROR function pointer
-}
-const fn reify(f: fn()) -> unsafe fn() { f }
-//~^ ERROR function pointer
-//~| ERROR function pointer
-//~| ERROR function pointer cast
-const fn reify2() { main as unsafe fn(); }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
diff --git a/src/test/ui/consts/min_const_fn/cast_errors.stderr b/src/test/ui/consts/min_const_fn/cast_errors.stderr
deleted file mode 100644 (file)
index fb962bd..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/cast_errors.rs:4:23
-   |
-LL | const fn closure() -> fn() { || {} }
-   |                       ^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/cast_errors.rs:4:30
-   |
-LL | const fn closure() -> fn() { || {} }
-   |                              ^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/cast_errors.rs:8:5
-   |
-LL |     (|| {}) as fn();
-   |     ^^^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/cast_errors.rs:11:16
-   |
-LL | const fn reify(f: fn()) -> unsafe fn() { f }
-   |                ^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/cast_errors.rs:11:28
-   |
-LL | const fn reify(f: fn()) -> unsafe fn() { f }
-   |                            ^^^^^^^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/cast_errors.rs:11:42
-   |
-LL | const fn reify(f: fn()) -> unsafe fn() { f }
-   |                                          ^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/cast_errors.rs:15:21
-   |
-LL | const fn reify2() { main as unsafe fn(); }
-   |                     ^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/cast_errors.rs:15:21
-   |
-LL | const fn reify2() { main as unsafe fn(); }
-   |                     ^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to 8 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/cast_fn.rs b/src/test/ui/consts/min_const_fn/cast_fn.rs
new file mode 100644 (file)
index 0000000..85802a5
--- /dev/null
@@ -0,0 +1,11 @@
+// check-pass
+
+fn main() {}
+
+const fn unsize(x: &[u8; 3]) -> &[u8] { x }
+const fn closure() -> fn() { || {} }
+const fn closure2() {
+    (|| {}) as fn();
+}
+const fn reify(f: fn()) -> unsafe fn() { f }
+const fn reify2() { main as unsafe fn(); }
index 638ff1d8b9c1c6da948d0adb3479047fee9ee202..e07b269c386eabee6dfc0c5e59c673e973e82bd2 100644 (file)
@@ -1,6 +1,4 @@
 const fn cmp(x: fn(), y: fn()) -> bool {
-    //~^ ERROR function pointer
-    //~| ERROR function pointer
     unsafe { x == y }
     //~^ ERROR pointers cannot be reliably compared
 }
index 5d8483cd111bf4cc744814155ccd85716a78a913..3845068d8411c652cfca567167c846d75d0d4a4d 100644 (file)
@@ -1,29 +1,10 @@
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/cmp_fn_pointers.rs:1:14
-   |
-LL | const fn cmp(x: fn(), y: fn()) -> bool {
-   |              ^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/cmp_fn_pointers.rs:1:23
-   |
-LL | const fn cmp(x: fn(), y: fn()) -> bool {
-   |                       ^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
 error: pointers cannot be reliably compared during const eval
-  --> $DIR/cmp_fn_pointers.rs:4:14
+  --> $DIR/cmp_fn_pointers.rs:2:14
    |
 LL |     unsafe { x == y }
    |              ^^^^^^
    |
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
index 10347a02074ec56221053f5d095b13be2a1aac23..0bafaf2e81f7329fc5370326fa2878d4044a5795 100644 (file)
@@ -80,11 +80,10 @@ const fn char_cast(u: u8) -> char { u as char }
 const unsafe fn ret_null_ptr_no_unsafe<T>() -> *const T { core::ptr::null() }
 const unsafe fn ret_null_mut_ptr_no_unsafe<T>() -> *mut T { core::ptr::null_mut() }
 
-// not ok
 const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
 const fn foo11_2<T: Send>(t: T) -> T { t }
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+
+// not ok
 
 static BAR: u32 = 42;
 const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics
@@ -108,41 +107,28 @@ const fn foo37(a: bool, b: bool) -> bool { a || b }
 fn main() {}
 
 impl<T: std::fmt::Debug> Foo<T> {
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
     const fn foo(&self) {}
 }
 
 impl<T: std::fmt::Debug + Sized> Foo<T> {
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
     const fn foo2(&self) {}
 }
 
 impl<T: Sync + Sized> Foo<T> {
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
     const fn foo3(&self) {}
 }
 
 struct AlanTuring<T>(T);
 const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
-//~^ ERROR trait bounds other than `Sized`
-//~| ERROR destructor
+//~^ ERROR destructor
 const fn no_apit(_x: impl std::fmt::Debug) {}
-//~^ ERROR trait bounds other than `Sized`
-//~| ERROR destructor
+//~^ ERROR destructor
 const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
-//~^ ERROR trait objects in const fn are unstable
 const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-//~^ ERROR trait objects in const fn are unstable
 
 const fn no_unsafe() { unsafe {} }
 
-const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-//~^ ERROR trait objects in const fn are unstable
-//~| ERROR trait objects in const fn are unstable
-//~| ERROR trait objects in const fn are unstable
+const fn traits_are_ok_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
 
-const fn no_fn_ptrs(_x: fn()) {}
-//~^ ERROR function pointer
-const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
+const fn fn_ptrs(_x: fn()) {}
+const fn fn_ptrs2() -> fn() { fn foo() {} foo }
index 67cb604b6a7be0344258766ec7b3bd21478ab4d8..4ad17602c8452031f1ceee3bed7db076d43b063b 100644 (file)
@@ -130,26 +130,8 @@ LL |     const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
    = 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[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:84:16
-   |
-LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
-   |                ^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:86:18
-   |
-LL | const fn foo11_2<T: Send>(t: T) -> T { t }
-   |                  ^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
 error[E0013]: constant functions cannot refer to statics
-  --> $DIR/min_const_fn.rs:90:27
+  --> $DIR/min_const_fn.rs:89:27
    |
 LL | const fn foo25() -> u32 { BAR }
    |                           ^^^
@@ -157,7 +139,7 @@ LL | const fn foo25() -> u32 { BAR }
    = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error[E0013]: constant functions cannot refer to statics
-  --> $DIR/min_const_fn.rs:91:37
+  --> $DIR/min_const_fn.rs:90:37
    |
 LL | const fn foo26() -> &'static u32 { &BAR }
    |                                     ^^^
@@ -165,7 +147,7 @@ LL | const fn foo26() -> &'static u32 { &BAR }
    = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error: pointers cannot be cast to integers during const eval
-  --> $DIR/min_const_fn.rs:92:42
+  --> $DIR/min_const_fn.rs:91:42
    |
 LL | const fn foo30(x: *const u32) -> usize { x as usize }
    |                                          ^^^^^^^^^^
@@ -174,7 +156,7 @@ LL | const fn foo30(x: *const u32) -> usize { x as usize }
    = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
 
 error: pointers cannot be cast to integers during const eval
-  --> $DIR/min_const_fn.rs:94:63
+  --> $DIR/min_const_fn.rs:93:63
    |
 LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
    |                                                               ^^^^^^^^^^
@@ -183,7 +165,7 @@ LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize }
    = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
 
 error: pointers cannot be cast to integers during const eval
-  --> $DIR/min_const_fn.rs:96:42
+  --> $DIR/min_const_fn.rs:95:42
    |
 LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
    |                                          ^^^^^^^^^^
@@ -192,7 +174,7 @@ LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
    = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
 
 error: pointers cannot be cast to integers during const eval
-  --> $DIR/min_const_fn.rs:98:63
+  --> $DIR/min_const_fn.rs:97:63
    |
 LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
    |                                                               ^^^^^^^^^^
@@ -201,7 +183,7 @@ LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize }
    = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
 
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/min_const_fn.rs:101:14
+  --> $DIR/min_const_fn.rs:100:14
    |
 LL | const fn inc(x: &mut i32) { *x += 1 }
    |              ^
@@ -209,155 +191,23 @@ LL | const fn inc(x: &mut i32) { *x += 1 }
    = 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[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:110:6
-   |
-LL | impl<T: std::fmt::Debug> Foo<T> {
-   |      ^
-LL |
-LL |     const fn foo(&self) {}
-   |     ------------------- function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:115:6
-   |
-LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
-   |      ^
-LL |
-LL |     const fn foo2(&self) {}
-   |     -------------------- function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:120:6
-   |
-LL | impl<T: Sync + Sized> Foo<T> {
-   |      ^
-LL |
-LL |     const fn foo3(&self) {}
-   |     -------------------- function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:126:34
-   |
-LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
-   |                                  ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/min_const_fn.rs:126:19
+  --> $DIR/min_const_fn.rs:122:19
    |
 LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
    |                   ^^                                     - value is dropped here
    |                   |
    |                   constant functions cannot evaluate destructors
 
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:129:22
-   |
-LL | const fn no_apit(_x: impl std::fmt::Debug) {}
-   |                      ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/min_const_fn.rs:129:18
+  --> $DIR/min_const_fn.rs:124:18
    |
 LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    |                  ^^                         - value is dropped here
    |                  |
    |                  constant functions cannot evaluate destructors
 
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn.rs:132:23
-   |
-LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
-   |                       ^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn.rs:134:32
-   |
-LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn.rs:139:41
-   |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-   | -------------------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | |
-   | function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn.rs:139:42
-   |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-   | -------------------------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | |
-   | function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn.rs:139:42
-   |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-   | -------------------------------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | |
-   | function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/min_const_fn.rs:144:21
-   |
-LL | const fn no_fn_ptrs(_x: fn()) {}
-   |                     ^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/min_const_fn.rs:146:27
-   |
-LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
-   |                           ^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/min_const_fn.rs:146:46
-   |
-LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
-   |                                              ^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to 39 previous errors
+error: aborting due to 24 previous errors
 
 Some errors have detailed explanations: E0013, E0493, E0658.
 For more information about an error, try `rustc --explain E0013`.
index 1ab8253b414a3b7333052a6a44d3ff66fbbfceba..36c8880093ec32c2033db11269ecf792293428f7 100644 (file)
@@ -1,3 +1,5 @@
+// check-pass
+
 struct HasDyn {
     field: &'static dyn std::fmt::Debug,
 }
@@ -7,9 +9,7 @@ struct HasDyn {
 const fn no_inner_dyn_trait(_x: Hide) {}
 const fn no_inner_dyn_trait2(x: Hide) {
     x.0.field;
-//~^ ERROR trait objects in const fn are unstable
 }
 const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
-//~^ ERROR trait objects in const fn are unstable
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
deleted file mode 100644 (file)
index 4c21991..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn_dyn.rs:9:5
-   |
-LL | const fn no_inner_dyn_trait2(x: Hide) {
-   | ------------------------------------- function declared as const here
-LL |     x.0.field;
-   |     ^^^^^^^^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/min_const_fn_dyn.rs:12:66
-   |
-LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
-   | -----------------------------------------                        ^^
-   | |
-   | function declared as const here
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs
deleted file mode 100644 (file)
index bc6fe89..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// gate-test-const_fn_fn_ptr_basics
-
-struct HasPtr {
-    field: fn(),
-}
-
-struct Hide(HasPtr);
-
-fn field() {}
-
-const fn no_inner_dyn_trait(_x: Hide) {}
-const fn no_inner_dyn_trait2(x: Hide) {
-    x.0.field;
-//~^ ERROR function pointer
-}
-const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
-//~^ ERROR function pointer
-
-fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr
deleted file mode 100644 (file)
index 8d82674..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: function pointers cannot appear in constant functions
-  --> $DIR/min_const_fn_fn_ptr.rs:13:5
-   |
-LL |     x.0.field;
-   |     ^^^^^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error[E0658]: function pointer casts are not allowed in constant functions
-  --> $DIR/min_const_fn_fn_ptr.rs:16:59
-   |
-LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
-   |                                                           ^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs
deleted file mode 100644 (file)
index e062c9f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// gate-test-const_impl_trait
-
-struct AlanTuring<T>(T);
-const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { //~ `impl Trait`
-    AlanTuring(0)
-}
-
-const fn no_rpit() -> impl std::fmt::Debug {} //~ `impl Trait`
-
-fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr
deleted file mode 100644 (file)
index 01c797c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: `impl Trait` is not allowed in constant functions
-  --> $DIR/min_const_fn_impl_trait.rs:4:24
-   |
-LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> {
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #77463 <https://github.com/rust-lang/rust/issues/77463> for more information
-   = help: add `#![feature(const_impl_trait)]` to the crate attributes to enable
-
-error[E0658]: `impl Trait` is not allowed in constant functions
-  --> $DIR/min_const_fn_impl_trait.rs:8:23
-   |
-LL | const fn no_rpit() -> impl std::fmt::Debug {}
-   |                       ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #77463 <https://github.com/rust-lang/rust/issues/77463> for more information
-   = help: add `#![feature(const_impl_trait)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
index e2f9708ddcb0143509ce9918fb39dbbd717ae7ea..aaba19c2c8b0e6b8b014f44c1a10620be26ef4ec 100644 (file)
@@ -12,16 +12,6 @@ LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "
 
 warning: skipping const checks
    |
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/abi-mismatch.rs:9:23
-   |
-LL | const fn call_rust_fn(my_fn: extern "Rust" fn()) {
-   |                       ^^^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/abi-mismatch.rs:10:5
-   |
-LL |     my_fn();
-   |     ^^^^^
 help: skipping check that does not even have a feature gate
   --> $DIR/abi-mismatch.rs:10:5
    |
index cbc88bc4d9c382999971f5095021a03641ecd160..fee61907eb3caa8d593239a7c26c999a99a8fc3d 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(const_ptr_offset_from)]
+#![feature(const_ptr_offset_from, const_ptr_offset)]
 #![feature(core_intrinsics)]
 
 use std::intrinsics::ptr_offset_from;
@@ -44,4 +44,30 @@ struct Struct {
     //~| 0x10 is not a valid pointer
 };
 
+const OUT_OF_BOUNDS_1: isize = {
+    let start_ptr = &4 as *const _ as *const u8;
+    let length = 10;
+    let end_ptr = (start_ptr).wrapping_add(length);
+    // First ptr is out of bounds
+    unsafe { ptr_offset_from(end_ptr, start_ptr) } //~ERROR evaluation of constant value failed
+    //~| pointer at offset 10 is out-of-bounds
+};
+
+const OUT_OF_BOUNDS_2: isize = {
+    let start_ptr = &4 as *const _ as *const u8;
+    let length = 10;
+    let end_ptr = (start_ptr).wrapping_add(length);
+    // Second ptr is out of bounds
+    unsafe { ptr_offset_from(start_ptr, end_ptr) } //~ERROR evaluation of constant value failed
+    //~| pointer at offset 10 is out-of-bounds
+};
+
+const OUT_OF_BOUNDS_SAME: isize = {
+    let start_ptr = &4 as *const _ as *const u8;
+    let length = 10;
+    let end_ptr = (start_ptr).wrapping_add(length);
+    unsafe { ptr_offset_from(end_ptr, end_ptr) } //~ERROR evaluation of constant value failed
+    //~| pointer at offset 10 is out-of-bounds
+};
+
 fn main() {}
index ffd6ad58c301d69e392006cc569bbfac09957102..4d60d4df203b33d4659513cf21a07ae7a540a2a9 100644 (file)
@@ -10,7 +10,7 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  0x2a is not a valid pointer
+   |                  out-of-bounds offset_from: 0x2a is not a valid pointer
    |                  inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $DIR/offset_from_ub.rs:23:14
@@ -28,14 +28,32 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:36:14
    |
 LL |     unsafe { ptr_offset_from(ptr, ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is not a valid pointer
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:43:14
    |
 LL |     unsafe { ptr_offset_from(ptr2, ptr1) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0x10 is not a valid pointer
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: 0x10 is not a valid pointer
 
-error: aborting due to 5 previous errors
+error[E0080]: evaluation of constant value failed
+  --> $DIR/offset_from_ub.rs:52:14
+   |
+LL |     unsafe { ptr_offset_from(end_ptr, start_ptr) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc18 has size 4, so pointer at offset 10 is out-of-bounds
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/offset_from_ub.rs:61:14
+   |
+LL |     unsafe { ptr_offset_from(start_ptr, end_ptr) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc21 has size 4, so pointer at offset 10 is out-of-bounds
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/offset_from_ub.rs:69:14
+   |
+LL |     unsafe { ptr_offset_from(end_ptr, end_ptr) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc24 has size 4, so pointer at offset 10 is out-of-bounds
+
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index 4c3f373e0801c03eadb6f1610e86bdc046dda6ac..237950a30e841ba7fc56eb040446d91cf9775354 100644 (file)
@@ -144,7 +144,7 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: 0x0 is not a valid pointer
+   |                  pointer arithmetic failed: null pointer is not a valid pointer
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $DIR/offset_ub.rs:22:50
index 8ee1270805e27649b50ada7a710cf3a5d1d0afee..16b36c8d56d8d3e1e740e3fe2302d1185ccf9b7b 100644 (file)
@@ -5,7 +5,6 @@
 
 #![stable(feature = "core", since = "1.6.0")]
 #![feature(staged_api)]
-#![feature(const_fn_trait_bound)]
 
 enum Opt<T> {
     Some(T),
index 3ec9971b8e1e83652fc4b2b3ebab2575be1eaaae..180f9f10cc6bc656b9f30ae581b57c21634dd882 100644 (file)
@@ -1,5 +1,5 @@
 error[E0015]: cannot call non-const closure in constant functions
-  --> $DIR/unstable-const-fn-in-libcore.rs:23:26
+  --> $DIR/unstable-const-fn-in-libcore.rs:22:26
    |
 LL |             Opt::None => f(),
    |                          ^^^
@@ -11,7 +11,7 @@ LL |     const fn unwrap_or_else<F: FnOnce() -> T + ~const std::ops::FnOnce<()>>
    |                                              +++++++++++++++++++++++++++++
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/unstable-const-fn-in-libcore.rs:18:53
+  --> $DIR/unstable-const-fn-in-libcore.rs:17:53
    |
 LL |     const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
    |                                                     ^ constant functions cannot evaluate destructors
@@ -20,7 +20,7 @@ LL |     }
    |     - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/unstable-const-fn-in-libcore.rs:18:47
+  --> $DIR/unstable-const-fn-in-libcore.rs:17:47
    |
 LL |     const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
    |                                               ^^^^ constant functions cannot evaluate destructors
diff --git a/src/test/ui/debuginfo/debuginfo-box-with-large-allocator.rs b/src/test/ui/debuginfo/debuginfo-box-with-large-allocator.rs
new file mode 100644 (file)
index 0000000..7615392
--- /dev/null
@@ -0,0 +1,23 @@
+// build-pass
+// compile-flags: -Cdebuginfo=2
+// fixes issue #94725
+
+#![feature(allocator_api)]
+
+use std::alloc::{AllocError, Allocator, Layout};
+use std::ptr::NonNull;
+
+struct ZST;
+
+unsafe impl Allocator for &ZST {
+    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+        todo!()
+    }
+    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
+        todo!()
+    }
+}
+
+fn main() {
+    let _ = Box::<i32, &ZST>::new_in(43, &ZST);
+}
index 833a4726acb0fb20a6e375448b08054ca62b553f..b3f22ecf5115ea4ff6e06973ae7067eca67036ee 100644 (file)
@@ -1,4 +1,4 @@
-// check-pass
+// build-pass
 // compile-flags: -Cdebuginfo=2
 // fixes issue #94149
 
diff --git a/src/test/ui/deprecation/deprecation-in-staged-api.rs b/src/test/ui/deprecation/deprecation-in-staged-api.rs
deleted file mode 100644 (file)
index 910bfd1..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#![feature(staged_api)]
-#![stable(feature = "stable_test_feature", since = "1.0.0")]
-#[deprecated] //~ ERROR `#[deprecated]` cannot be used in staged API
-fn main() {}
diff --git a/src/test/ui/deprecation/deprecation-in-staged-api.stderr b/src/test/ui/deprecation/deprecation-in-staged-api.stderr
deleted file mode 100644 (file)
index 5c14f5e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `#[deprecated]` cannot be used in staged API
-  --> $DIR/deprecation-in-staged-api.rs:3:1
-   |
-LL | #[deprecated]
-   | ^^^^^^^^^^^^^ use `#[rustc_deprecated]` instead
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/deprecation/feature-gate-deprecated_suggestion.rs b/src/test/ui/deprecation/feature-gate-deprecated_suggestion.rs
new file mode 100644 (file)
index 0000000..a2d0023
--- /dev/null
@@ -0,0 +1,6 @@
+// compile-flags: --crate-type=lib
+
+#![no_implicit_prelude]
+
+#[deprecated(suggestion = "foo")] //~ ERROR suggestions on deprecated items are unstable
+struct Foo {}
diff --git a/src/test/ui/deprecation/feature-gate-deprecated_suggestion.stderr b/src/test/ui/deprecation/feature-gate-deprecated_suggestion.stderr
new file mode 100644 (file)
index 0000000..3b995fe
--- /dev/null
@@ -0,0 +1,11 @@
+error: suggestions on deprecated items are unstable
+  --> $DIR/feature-gate-deprecated_suggestion.rs:5:14
+   |
+LL | #[deprecated(suggestion = "foo")]
+   |              ^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(deprecated_suggestion)]` to the crate root
+   = note: see #XXX for more details
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/deprecation/rustc_deprecation-in-future.rs b/src/test/ui/deprecation/rustc_deprecation-in-future.rs
deleted file mode 100644 (file)
index 3715f8e..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#![deny(deprecated_in_future)]
-
-#![feature(staged_api)]
-
-#![stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
-
-#[rustc_deprecated(since = "99.99.99", reason = "effectively never")]
-#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
-pub struct S1;
-
-#[rustc_deprecated(since = "TBD", reason = "literally never")]
-#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
-pub struct S2;
-
-fn main() {
-    let _ = S1; //~ ERROR use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never
-    let _ = S2; //~ ERROR use of unit struct `S2` that will be deprecated in a future Rust version: literally never
-}
diff --git a/src/test/ui/deprecation/rustc_deprecation-in-future.stderr b/src/test/ui/deprecation/rustc_deprecation-in-future.stderr
deleted file mode 100644 (file)
index 1c3339a..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error: use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never
-  --> $DIR/rustc_deprecation-in-future.rs:16:13
-   |
-LL |     let _ = S1;
-   |             ^^
-   |
-note: the lint level is defined here
-  --> $DIR/rustc_deprecation-in-future.rs:1:9
-   |
-LL | #![deny(deprecated_in_future)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-
-error: use of unit struct `S2` that will be deprecated in a future Rust version: literally never
-  --> $DIR/rustc_deprecation-in-future.rs:17:13
-   |
-LL |     let _ = S2;
-   |             ^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/deprecation/staged-deprecation-in-future.rs b/src/test/ui/deprecation/staged-deprecation-in-future.rs
new file mode 100644 (file)
index 0000000..87b15ec
--- /dev/null
@@ -0,0 +1,18 @@
+#![deny(deprecated_in_future)]
+
+#![feature(staged_api)]
+
+#![stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+
+#[deprecated(since = "99.99.99", note = "effectively never")]
+#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+pub struct S1;
+
+#[deprecated(since = "TBD", note = "literally never")]
+#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")]
+pub struct S2;
+
+fn main() {
+    let _ = S1; //~ ERROR use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never
+    let _ = S2; //~ ERROR use of unit struct `S2` that will be deprecated in a future Rust version: literally never
+}
diff --git a/src/test/ui/deprecation/staged-deprecation-in-future.stderr b/src/test/ui/deprecation/staged-deprecation-in-future.stderr
new file mode 100644 (file)
index 0000000..13d9804
--- /dev/null
@@ -0,0 +1,20 @@
+error: use of unit struct `S1` that will be deprecated in future version 99.99.99: effectively never
+  --> $DIR/staged-deprecation-in-future.rs:16:13
+   |
+LL |     let _ = S1;
+   |             ^^
+   |
+note: the lint level is defined here
+  --> $DIR/staged-deprecation-in-future.rs:1:9
+   |
+LL | #![deny(deprecated_in_future)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: use of unit struct `S2` that will be deprecated in a future Rust version: literally never
+  --> $DIR/staged-deprecation-in-future.rs:17:13
+   |
+LL |     let _ = S2;
+   |             ^^
+
+error: aborting due to 2 previous errors
+
index 7d662227881ace5d0af3631968b9f4b1d2627add..d9fa2b56eeef705b94a316842252e34c1234600f 100644 (file)
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![feature(staged_api)]
+#![feature(deprecated_suggestion)]
 
 #![stable(since = "1.0.0", feature = "test")]
 
@@ -10,9 +11,9 @@
 struct Foo;
 
 impl Foo {
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.0.0",
-        reason = "replaced by `replacement`",
+        note = "replaced by `replacement`",
         suggestion = "replacement",
     )]
     #[stable(since = "1.0.0", feature = "test")]
@@ -22,9 +23,9 @@ impl Foo {
 }
 
 mod bar {
-    #[rustc_deprecated(
+    #[deprecated(
     since = "1.0.0",
-    reason = "replaced by `replacement`",
+    note = "replaced by `replacement`",
     suggestion = "replacement",
     )]
     #[stable(since = "1.0.0", feature = "test")]
index b34dc0eb83a206264a30eda1c5279fb03651f372..9dc2eaf25550710b4b945dc66a5170ccf248d366 100644 (file)
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![feature(staged_api)]
+#![feature(deprecated_suggestion)]
 
 #![stable(since = "1.0.0", feature = "test")]
 
@@ -10,9 +11,9 @@
 struct Foo;
 
 impl Foo {
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.0.0",
-        reason = "replaced by `replacement`",
+        note = "replaced by `replacement`",
         suggestion = "replacement",
     )]
     #[stable(since = "1.0.0", feature = "test")]
@@ -22,9 +23,9 @@ fn replacement(&self) {}
 }
 
 mod bar {
-    #[rustc_deprecated(
+    #[deprecated(
     since = "1.0.0",
-    reason = "replaced by `replacement`",
+    note = "replaced by `replacement`",
     suggestion = "replacement",
     )]
     #[stable(since = "1.0.0", feature = "test")]
index 7d78b2222444f1b769827ebe4f034d7633555d09..8d1e108345f30418210b459951133102253c6cd1 100644 (file)
@@ -1,17 +1,17 @@
 error: use of deprecated function `bar::deprecated`: replaced by `replacement`
-  --> $DIR/suggestion.rs:41:10
+  --> $DIR/suggestion.rs:42:10
    |
 LL |     bar::deprecated();
    |          ^^^^^^^^^^ help: replace the use of the deprecated function: `replacement`
    |
 note: the lint level is defined here
-  --> $DIR/suggestion.rs:7:9
+  --> $DIR/suggestion.rs:8:9
    |
 LL | #![deny(deprecated)]
    |         ^^^^^^^^^^
 
 error: use of deprecated associated function `Foo::deprecated`: replaced by `replacement`
-  --> $DIR/suggestion.rs:39:9
+  --> $DIR/suggestion.rs:40:9
    |
 LL |     foo.deprecated();
    |         ^^^^^^^^^^ help: replace the use of the deprecated associated function: `replacement`
index 24112c9855acd1d967f95ce213a708839086f553..3daf4930c5b4b349f981f98c9f6c815318897d44 100644 (file)
@@ -1,7 +1,7 @@
 async fn foo() {
 //~^ ERROR `async fn` is not permitted in Rust 2015
 //~| NOTE to use `async fn`, switch to Rust 2018 or later
-//~| HELP set `edition = "2021"` in `Cargo.toml`
+//~| HELP pass `--edition 2021` to `rustc`
 //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 
     let x = async {};
@@ -11,7 +11,7 @@ async fn foo() {
         let x = 42;
         //~^ ERROR expected identifier, found keyword `let`
         //~| NOTE expected identifier, found keyword
-        //~| HELP set `edition = "2021"` in `Cargo.toml`
+        //~| HELP pass `--edition 2021` to `rustc`
         //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
         42
     };
@@ -19,7 +19,7 @@ async fn foo() {
         42
         //~^ ERROR expected identifier, found `42`
         //~| NOTE expected identifier
-        //~| HELP set `edition = "2021"` in `Cargo.toml`
+        //~| HELP pass `--edition 2021` to `rustc`
         //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
     };
     y.await;
index da8412ddcb3333eafba7940ad8b8bca6526d80a2..b792b8c1e0dd84834e9b3353c851786df87a4022 100644 (file)
@@ -4,7 +4,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | async fn foo() {
    | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: expected identifier, found keyword `let`
@@ -15,7 +15,7 @@ LL |     let y = async {
 LL |         let x = 42;
    |         ^^^ expected identifier, found keyword
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: expected identifier, found `42`
@@ -26,7 +26,7 @@ LL |     let z = async {
 LL |         42
    |         ^^ expected identifier
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0422]: cannot find struct, variant or union type `async` in this scope
index 7e9b05587b075e56805c54349b1cb9841d351491..d319227b217a73624e0a64aeb079d05a104306bb 100644 (file)
@@ -1,5 +1,8 @@
+#![feature(lint_reasons)]
+
 #![deny(unused_attributes)]
 #![allow()] //~ ERROR unused attribute
+#![expect()] //~ ERROR unused attribute
 #![warn()] //~ ERROR unused attribute
 #![deny()] //~ ERROR unused attribute
 #![forbid()] //~ ERROR unused attribute
index e0798e4f0c69fc9b610fc5ad79113f887b321711..8653eaf5ccdf3e9f048541f859a19744745a59e8 100644 (file)
@@ -1,18 +1,18 @@
 error: unused attribute
-  --> $DIR/empty-attributes.rs:8:1
+  --> $DIR/empty-attributes.rs:11:1
    |
 LL | #[repr()]
    | ^^^^^^^^^ help: remove this attribute
    |
 note: the lint level is defined here
-  --> $DIR/empty-attributes.rs:1:9
+  --> $DIR/empty-attributes.rs:3:9
    |
 LL | #![deny(unused_attributes)]
    |         ^^^^^^^^^^^^^^^^^
    = note: attribute `repr` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:11:1
+  --> $DIR/empty-attributes.rs:14:1
    |
 LL | #[target_feature()]
    | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
@@ -20,7 +20,7 @@ LL | #[target_feature()]
    = note: attribute `target_feature` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:2:1
+  --> $DIR/empty-attributes.rs:4:1
    |
 LL | #![allow()]
    | ^^^^^^^^^^^ help: remove this attribute
@@ -28,7 +28,15 @@ LL | #![allow()]
    = note: attribute `allow` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:3:1
+  --> $DIR/empty-attributes.rs:5:1
+   |
+LL | #![expect()]
+   | ^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `expect` with an empty list has no effect
+
+error: unused attribute
+  --> $DIR/empty-attributes.rs:6:1
    |
 LL | #![warn()]
    | ^^^^^^^^^^ help: remove this attribute
@@ -36,7 +44,7 @@ LL | #![warn()]
    = note: attribute `warn` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:4:1
+  --> $DIR/empty-attributes.rs:7:1
    |
 LL | #![deny()]
    | ^^^^^^^^^^ help: remove this attribute
@@ -44,7 +52,7 @@ LL | #![deny()]
    = note: attribute `deny` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:5:1
+  --> $DIR/empty-attributes.rs:8:1
    |
 LL | #![forbid()]
    | ^^^^^^^^^^^^ help: remove this attribute
@@ -52,12 +60,12 @@ LL | #![forbid()]
    = note: attribute `forbid` with an empty list has no effect
 
 error: unused attribute
-  --> $DIR/empty-attributes.rs:6:1
+  --> $DIR/empty-attributes.rs:9:1
    |
 LL | #![feature()]
    | ^^^^^^^^^^^^^ help: remove this attribute
    |
    = note: attribute `feature` with an empty list has no effect
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
index 64d640c0e9dbcae0785a578de4ddd15ff8b514df..909aa73a74a38fb2a9b8313de32527f95ad9c9ce 100644 (file)
@@ -1,24 +1,27 @@
 error[E0005]: refutable pattern in local binding: `T(_, _)` not covered
   --> $DIR/empty-never-array.rs:10:9
    |
-LL | / enum Helper<T, U> {
-LL | |     T(T, [!; 0]),
-   | |     - not covered
-LL | |     #[allow(dead_code)]
-LL | |     U(U),
-LL | | }
-   | |_- `Helper<T, U>` defined here
-...
-LL |       let Helper::U(u) = Helper::T(t, []);
-   |           ^^^^^^^^^^^^ pattern `T(_, _)` not covered
+LL |     let Helper::U(u) = Helper::T(t, []);
+   |         ^^^^^^^^^^^^ pattern `T(_, _)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Helper<T, U>` defined here
+  --> $DIR/empty-never-array.rs:4:5
+   |
+LL | enum Helper<T, U> {
+   |      ------
+LL |     T(T, [!; 0]),
+   |     ^ not covered
    = note: the matched value is of type `Helper<T, U>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Helper::U(u) = Helper::T(t, []) { /* */ }
+LL |     let u = if let Helper::U(u) = Helper::T(t, []) { u } else { todo!() };
+   |     ++++++++++                                     ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
    |
+LL |     let Helper::U(u) = Helper::T(t, []) else { todo!() };
+   |                                         ++++++++++++++++
 
 error: aborting due to previous error
 
index fd0215e72ee24acb16a54ad9f088bbc8be1c219f..d4519af540859078b7587ba20c30a2ea998e9610 100644 (file)
@@ -4,16 +4,27 @@ error[E0004]: non-exhaustive patterns: `None` and `Some(_)` not covered
 LL |     match x { }
    |           ^ patterns `None` and `Some(_)` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<i32>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
    |
-LL |     None,
-   |     ---- not covered
-...
-LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     ---- not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     None,
+   | |     ^^^^ not covered
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   | |     ^^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~     match x {
+LL +         None | Some(_) => todo!(),
+LL ~     }
+   |
 
 error: aborting due to previous error
 
index 5bf375a64843a2bb2c82b7ac291362c6c82ec512..8ba151d9e65fa483bd0b5dfb61fc6058ecfcdd6f 100644 (file)
@@ -1,18 +1,22 @@
 error[E0004]: non-exhaustive patterns: `HastaLaVistaBaby` not covered
   --> $DIR/E0004.rs:9:11
    |
-LL | / enum Terminator {
-LL | |     HastaLaVistaBaby,
-   | |     ---------------- not covered
-LL | |     TalkToMyHand,
-LL | | }
-   | |_- `Terminator` defined here
-...
-LL |       match x {
-   |             ^ pattern `HastaLaVistaBaby` not covered
+LL |     match x {
+   |           ^ pattern `HastaLaVistaBaby` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Terminator` defined here
+  --> $DIR/E0004.rs:2:5
+   |
+LL | enum Terminator {
+   |      ----------
+LL |     HastaLaVistaBaby,
+   |     ^^^^^^^^^^^^^^^^ not covered
    = note: the matched value is of type `Terminator`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Terminator::TalkToMyHand => {}
+LL +         HastaLaVistaBaby => todo!()
+   |
 
 error: aborting due to previous error
 
index b95dcbd8935b33e45367922cbea953418e4dfcf2..55b1112b5f8ecb4e0f1993894fb6241c3f1f65e6 100644 (file)
@@ -4,18 +4,30 @@ error[E0005]: refutable pattern in local binding: `None` not covered
 LL |     let Some(y) = x;
    |         ^^^^^^^ pattern `None` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
-   |
-LL |     None,
-   |     ---- not covered
-   |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Option<i32>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     None,
+   | |     ^^^^ not covered
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+LL | | }
+   | |_-
    = note: the matched value is of type `Option<i32>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Some(y) = x { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     let y = if let Some(y) = x { y } else { todo!() };
+   |     ++++++++++                 ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+   |
+LL |     let Some(y) = x else { todo!() };
+   |                     ++++++++++++++++
 
 error: aborting due to previous error
 
index 957e79a9f398183c55f94d9561520b4efdc0e02a..95d95003c616f60e5cf0e5bfd46673aad2afa656 100644 (file)
@@ -4,11 +4,19 @@ error[E0005]: refutable pattern in `for` loop binding: `None` not covered
 LL |     for Some(x) in xs {}
    |         ^^^^^^^ pattern `None` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
-   |
-LL |     None,
-   |     ---- not covered
+note: `Option<i32>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
    |
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     None,
+   | |     ^^^^ not covered
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+LL | | }
+   | |_-
    = note: the matched value is of type `Option<i32>`
 
 error: aborting due to previous error
index 3837e206169d4756ccfad11ece429cd4f24d937c..ce8d1ef03493c277c960ec783ee3da0f1e1d2697 100644 (file)
@@ -2,7 +2,16 @@ error[E0507]: cannot move out of dereference of `Ref<'_, TheDarkKnight>`
   --> $DIR/E0507.rs:12:5
    |
 LL |     x.borrow().nothing_is_true();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait
+   |     ^^^^^^^^^^^-----------------
+   |     |          |
+   |     |          value moved due to this method call
+   |     move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait
+   |
+note: this function takes ownership of the receiver `self`, which moves value
+  --> $DIR/E0507.rs:6:24
+   |
+LL |     fn nothing_is_true(self) {}
+   |                        ^^^^
 
 error: aborting due to previous error
 
index c5ffa55ebec6f64985bca63f2e7ac730f6ced3c5..21180f31bbd26a11a59631f1f1966072ee34cbab 100644 (file)
@@ -4,18 +4,29 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
 LL |     let Ok(_x) = foo();
    |         ^^^^^^ pattern `Err(_)` not covered
    |
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
-   |     --- not covered
-   |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Result<u32, !>` defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | / pub enum Result<T, E> {
+LL | |     /// Contains the success value
+LL | |     #[lang = "Ok"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+   | |     ^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `Result<u32, !>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Ok(_x) = foo() { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     let _x = if let Ok(_x) = foo() { _x } else { todo!() };
+   |     +++++++++++                    +++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+   |
+LL |     let Ok(_x) = foo() else { todo!() };
+   |                        ++++++++++++++++
 
 error: aborting due to previous error
 
index 2a34ed4d4f64497177c0845538b2158150eed66c..29a6e1f8a016dce09c0fc95ff37c9e1803075725 100644 (file)
@@ -1,9 +1,11 @@
+// check-fail
+
 #![deny(non_exhaustive_omitted_patterns)]
-//~^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+//~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 #![allow(non_exhaustive_omitted_patterns)]
-//~^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+//~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 
 fn main() {
     enum Foo {
@@ -11,14 +13,15 @@ enum Foo {
     }
 
     #[allow(non_exhaustive_omitted_patterns)]
+    //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
     match Foo::A {
         Foo::A => {}
         Foo::B => {}
     }
-    //~^^^^^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-    //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-    //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-    //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+    //~^^^^ ERROR non-exhaustive patterns: `C` not covered
 
     match Foo::A {
         Foo::A => {}
@@ -26,6 +29,6 @@ enum Foo {
         #[warn(non_exhaustive_omitted_patterns)]
         _ => {}
     }
-    //~^^^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-    //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+    //~^^^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 }
index 691f64cf0addd443a43f258f9ae7ebeda0671058..dbeef6c2d2ae2533c03e17fea9190959c51d47d8 100644 (file)
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:1:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1
    |
 LL | #![deny(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: `#[warn(unknown_lints)]` on by default
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:4:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1
    |
 LL | #![allow(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:26:9
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9
    |
 LL |         #[warn(non_exhaustive_omitted_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:1:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1
    |
 LL | #![deny(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:4:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1
    |
 LL | #![allow(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:26:9
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9
    |
 LL |         #[warn(non_exhaustive_omitted_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error: aborting due to 10 previous errors
+error[E0004]: non-exhaustive patterns: `C` not covered
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:20:11
+   |
+LL |     match Foo::A {
+   |           ^^^^^^ pattern `C` not covered
+   |
+note: `Foo` defined here
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:12:15
+   |
+LL |     enum Foo {
+   |          ---
+LL |         A, B, C,
+   |               ^ not covered
+   = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo::B => {}
+LL +         C => todo!()
+   |
+
+error: aborting due to previous error; 10 warnings emitted
 
-For more information about this error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0004`.
index 9895646fc2ba477d8aa3c7d530acf78a79c46731..b5510683328f54097f884ca53d7c749371af823e 100644 (file)
@@ -4,10 +4,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0usize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
    = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         0..=usize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/feature-gate-precise_pointer_size_matching.rs:10:11
@@ -15,10 +19,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0isize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         isize::MIN..=isize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
index 04f816ea5016401112bd152625b6431456d77ae2..667bc9f8ddf182905e5a8f9f725cc4f24f39f73c 100644 (file)
@@ -2,6 +2,6 @@
 
 #[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable
 #[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable
-#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and will never be stable
+#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and libstd and will never be stable
 
 fn main() {}
index 822368a5946ecb2fa0b1210fec38a06e309f7a55..45a095903d2a7b59a39b9cabb9a0a2b6bee67558 100644 (file)
@@ -14,7 +14,7 @@ LL | #[rustc_error]
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and will never be stable
+error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and libstd and will never be stable
   --> $DIR/feature-gate-rustc-attrs-1.rs:5:1
    |
 LL | #[rustc_nonnull_optimization_guaranteed]
diff --git a/src/test/ui/feature-gates/feature-gate-test_unstable_lint.rs b/src/test/ui/feature-gates/feature-gate-test_unstable_lint.rs
new file mode 100644 (file)
index 0000000..c398394
--- /dev/null
@@ -0,0 +1,9 @@
+// check-pass
+
+// `test_unstable_lint` is for testing and should never be stabilized.
+#![allow(test_unstable_lint)]
+//~^ WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-test_unstable_lint.stderr b/src/test/ui/feature-gates/feature-gate-test_unstable_lint.stderr
new file mode 100644 (file)
index 0000000..a293224
--- /dev/null
@@ -0,0 +1,30 @@
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/feature-gate-test_unstable_lint.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_lints)]` on by default
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/feature-gate-test_unstable_lint.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/feature-gate-test_unstable_lint.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: 3 warnings emitted
+
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.rs b/src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.rs
deleted file mode 100644 (file)
index 3acfbd0..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-// Testing gating of `#[rustc_deprecated]` in "weird" places.
-//
-// This file sits on its own because these signal errors, making
-// this test incompatible with the "warnings only" nature of
-// issue-43106-gating-of-builtin-attrs.rs
-
-#![rustc_deprecated()]
-//~^ ERROR stability attributes may not be used outside of the standard library
-//~| ERROR missing 'since' [E0542]
-
-#[rustc_deprecated()]
-//~^ ERROR stability attributes may not be used outside of the standard library
-//~| ERROR missing 'since' [E0542]
-mod rustc_deprecated {
-    mod inner {
-        #![rustc_deprecated()]
-        //~^ ERROR stability attributes may not be used outside of the standard library
-        //~| ERROR missing 'since' [E0542]
-    }
-
-    #[rustc_deprecated()]
-    //~^ ERROR stability attributes may not be used outside of the standard library
-    //~| ERROR missing 'since' [E0542]
-    fn f() {}
-
-    #[rustc_deprecated()]
-    //~^ ERROR stability attributes may not be used outside of the standard library
-    //~| ERROR missing 'since' [E0542]
-    //~| ERROR missing 'since' [E0542]
-    struct S;
-
-    #[rustc_deprecated()]
-    //~^ ERROR stability attributes may not be used outside of the standard library
-    //~| ERROR missing 'since' [E0542]
-    type T = S;
-
-    #[rustc_deprecated()]
-    //~^ ERROR stability attributes may not be used outside of the standard library
-    //~| ERROR missing 'since' [E0542]
-    impl S {}
-}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-rustc_deprecated.stderr
deleted file mode 100644 (file)
index 4ec78f3..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:16:9
-   |
-LL |         #![rustc_deprecated()]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:21:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:32:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:37:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:11:1
-   |
-LL | #[rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:7:1
-   |
-LL | #![rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:7:1
-   |
-LL | #![rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:11:1
-   |
-LL | #[rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:16:9
-   |
-LL |         #![rustc_deprecated()]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:21:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:32:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:37:5
-   |
-LL |     #[rustc_deprecated()]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 15 previous errors
-
-Some errors have detailed explanations: E0542, E0734.
-For more information about an error, try `rustc --explain E0542`.
diff --git a/src/test/ui/generic-associated-types/issue-90729.rs b/src/test/ui/generic-associated-types/issue-90729.rs
new file mode 100644 (file)
index 0000000..98295cc
--- /dev/null
@@ -0,0 +1,38 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+use std::marker::PhantomData;
+
+pub trait Type {
+    type Ref<'a>;
+}
+
+pub trait AsBytes {}
+
+impl AsBytes for &str {}
+
+pub struct Utf8;
+
+impl Type for Utf8 {
+    type Ref<'a> = &'a str;
+}
+
+pub struct Bytes<T: Type> {
+    _marker: PhantomData<T>,
+}
+
+impl<T: Type> Bytes<T>
+where
+    for<'a> T::Ref<'a>: AsBytes,
+{
+    pub fn new() -> Self {
+        Self {
+            _marker: PhantomData,
+        }
+    }
+}
+
+fn main() {
+    let _b = Bytes::<Utf8>::new();
+}
diff --git a/src/test/ui/generic-associated-types/issue-91139.migrate.stderr b/src/test/ui/generic-associated-types/issue-91139.migrate.stderr
new file mode 100644 (file)
index 0000000..a27d811
--- /dev/null
@@ -0,0 +1,10 @@
+error[E0311]: the parameter type `T` may not live long enough
+  --> $DIR/issue-91139.rs:27:12
+   |
+LL | fn foo<T>() {
+   |        - help: consider adding an explicit lifetime bound...: `T: 'a`
+LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+
+error: aborting due to previous error
+
index 5c4a7cf6ffc6074977e1ff2ff6df4a1ea43ab438..78b2b63dadc5e94179cac8832248c65a9c27d00e 100644 (file)
@@ -1,4 +1,13 @@
-// check-pass
+// revisions: migrate nll
+//[nll]compile-flags: -Z borrowck=mir
+
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
+//[nll] check-pass
+//[migrate] check-fail
 
 #![feature(generic_associated_types)]
 
@@ -16,6 +25,7 @@ impl<T> Foo<T> for () {
 
 fn foo<T>() {
     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+    //[migrate]~^ the parameter type `T` may not live long enough
 }
 
 pub fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-93341.rs b/src/test/ui/generic-associated-types/issue-93341.rs
new file mode 100644 (file)
index 0000000..e96a768
--- /dev/null
@@ -0,0 +1,55 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+use std::marker::PhantomData;
+
+pub struct Id<'id>(PhantomData<fn(&'id ()) -> &'id ()>);
+
+fn new_id() -> Id<'static> {
+    Id(PhantomData)
+}
+
+pub trait HasLifetime where {
+    type AtLifetime<'a>;
+}
+
+pub struct ExistentialLifetime<S: HasLifetime>(S::AtLifetime<'static>);
+
+impl<S: HasLifetime> ExistentialLifetime<S> {
+    pub fn new<F>(f: F) -> ExistentialLifetime<S>
+        where for<'id> F: FnOnce(Id<'id>) -> S::AtLifetime<'id> {
+        ExistentialLifetime(f(new_id()))
+    }
+}
+
+
+struct ExampleS<'id>(Id<'id>);
+
+struct ExampleMarker;
+
+impl HasLifetime for ExampleMarker {
+    type AtLifetime<'id> = ExampleS<'id>;
+}
+
+
+fn broken0() -> ExistentialLifetime<ExampleMarker> {
+    fn new_helper<'id>(id: Id<'id>) -> ExampleS<'id> {
+        ExampleS(id)
+    }
+
+    ExistentialLifetime::<ExampleMarker>::new(new_helper)
+}
+
+fn broken1() -> ExistentialLifetime<ExampleMarker> {
+    fn new_helper<'id>(id: Id<'id>) -> <ExampleMarker as HasLifetime>::AtLifetime<'id> {
+        ExampleS(id)
+    }
+
+    ExistentialLifetime::<ExampleMarker>::new(new_helper)
+}
+
+fn broken2() -> ExistentialLifetime<ExampleMarker> {
+    ExistentialLifetime::<ExampleMarker>::new(|id| ExampleS(id))
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-93342.rs b/src/test/ui/generic-associated-types/issue-93342.rs
new file mode 100644 (file)
index 0000000..d8d7ada
--- /dev/null
@@ -0,0 +1,57 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+use std::marker::PhantomData;
+
+pub trait Scalar: 'static {
+    type RefType<'a>: ScalarRef<'a>;
+}
+
+pub trait ScalarRef<'a>: 'a {}
+
+impl Scalar for i32 {
+    type RefType<'a> = i32;
+}
+
+impl Scalar for String {
+    type RefType<'a> = &'a str;
+}
+
+impl Scalar for bool {
+    type RefType<'a> = i32;
+}
+
+impl<'a> ScalarRef<'a> for bool {}
+
+impl<'a> ScalarRef<'a> for i32 {}
+
+impl<'a> ScalarRef<'a> for &'a str {}
+
+fn str_contains(a: &str, b: &str) -> bool {
+    a.contains(b)
+}
+
+pub struct BinaryExpression<A: Scalar, B: Scalar, O: Scalar, F>
+where
+    F: Fn(A::RefType<'_>, B::RefType<'_>) -> O,
+{
+    f: F,
+    _phantom: PhantomData<(A, B, O)>,
+}
+
+impl<A: Scalar, B: Scalar, O: Scalar, F> BinaryExpression<A, B, O, F>
+where
+    F: Fn(A::RefType<'_>, B::RefType<'_>) -> O,
+{
+    pub fn new(f: F) -> Self {
+        Self {
+            f,
+            _phantom: PhantomData,
+        }
+    }
+}
+
+fn main() {
+    BinaryExpression::<String, String, bool, _>::new(str_contains);
+}
index 14dbca60b78f238d8202519ccd52e8d825a0fca8..c2c77290c4374a59ce9c0bb157c4e2d48d6dec21 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0f32, f32::NEG_INFINITY..);
    |        ^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `f32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:17:8
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0f32, ..f32::INFINITY);
    |        ^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `f32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8
@@ -22,8 +30,12 @@ error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
 LL |     m!('a', ..core::char::MAX);
    |        ^^^ pattern `'\u{10ffff}'` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         '\u{10ffff}' => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8
@@ -31,8 +43,12 @@ error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered
 LL |     m!('a', ..ALMOST_MAX);
    |        ^^^ pattern `'\u{10fffe}'..='\u{10ffff}'` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         '\u{10fffe}'..='\u{10ffff}' => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `'\u{0}'` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8
@@ -40,8 +56,12 @@ error[E0004]: non-exhaustive patterns: `'\u{0}'` not covered
 LL |     m!('a', ALMOST_MIN..);
    |        ^^^ pattern `'\u{0}'` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         '\u{0}' => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8
@@ -49,8 +69,12 @@ error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
 LL |     m!('a', ..=ALMOST_MAX);
    |        ^^^ pattern `'\u{10ffff}'` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         '\u{10ffff}' => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `'b'` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:30:8
@@ -58,8 +82,12 @@ error[E0004]: non-exhaustive patterns: `'b'` not covered
 LL |     m!('a', ..=VAL | VAL_2..);
    |        ^^^ pattern `'b'` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         'b' => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `'b'` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:31:8
@@ -67,8 +95,12 @@ error[E0004]: non-exhaustive patterns: `'b'` not covered
 LL |     m!('a', ..VAL_1 | VAL_2..);
    |        ^^^ pattern `'b'` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         'b' => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12
@@ -76,8 +108,12 @@ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
 LL |         m!(0, ..u8::MAX);
    |            ^ pattern `u8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
@@ -85,8 +121,12 @@ error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `254_u8..=u8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         254_u8..=u8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12
@@ -94,8 +134,12 @@ error[E0004]: non-exhaustive patterns: `0_u8` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12
@@ -103,8 +147,12 @@ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:45:12
@@ -112,8 +160,12 @@ error[E0004]: non-exhaustive patterns: `43_u8` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:46:12
@@ -121,8 +173,12 @@ error[E0004]: non-exhaustive patterns: `43_u8` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12
@@ -130,8 +186,12 @@ error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
 LL |         m!(0, ..u16::MAX);
    |            ^ pattern `u16::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u16::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
@@ -139,8 +199,12 @@ error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `65534_u16..=u16::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         65534_u16..=u16::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12
@@ -148,8 +212,12 @@ error[E0004]: non-exhaustive patterns: `0_u16` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u16` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u16 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12
@@ -157,8 +225,12 @@ error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u16::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u16::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:58:12
@@ -166,8 +238,12 @@ error[E0004]: non-exhaustive patterns: `43_u16` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u16` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u16 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:59:12
@@ -175,8 +251,12 @@ error[E0004]: non-exhaustive patterns: `43_u16` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u16` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u16 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12
@@ -184,8 +264,12 @@ error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
 LL |         m!(0, ..u32::MAX);
    |            ^ pattern `u32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u32::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
@@ -193,8 +277,12 @@ error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `4294967294_u32..=u32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         4294967294_u32..=u32::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12
@@ -202,8 +290,12 @@ error[E0004]: non-exhaustive patterns: `0_u32` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u32` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u32 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12
@@ -211,8 +303,12 @@ error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u32::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:71:12
@@ -220,8 +316,12 @@ error[E0004]: non-exhaustive patterns: `43_u32` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u32` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u32 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:72:12
@@ -229,8 +329,12 @@ error[E0004]: non-exhaustive patterns: `43_u32` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u32` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u32 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12
@@ -238,8 +342,12 @@ error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
 LL |         m!(0, ..u64::MAX);
    |            ^ pattern `u64::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u64::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
@@ -247,8 +355,12 @@ error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `18446744073709551614_u64..=u64::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         18446744073709551614_u64..=u64::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12
@@ -256,8 +368,12 @@ error[E0004]: non-exhaustive patterns: `0_u64` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u64` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u64 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12
@@ -265,8 +381,12 @@ error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u64::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u64::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:84:12
@@ -274,8 +394,12 @@ error[E0004]: non-exhaustive patterns: `43_u64` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u64` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u64 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:85:12
@@ -283,8 +407,12 @@ error[E0004]: non-exhaustive patterns: `43_u64` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u64` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u64 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12
@@ -292,8 +420,12 @@ error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
 LL |         m!(0, ..u128::MAX);
    |            ^ pattern `u128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
@@ -301,8 +433,12 @@ error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         340282366920938463463374607431768211454_u128..=u128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12
@@ -310,8 +446,12 @@ error[E0004]: non-exhaustive patterns: `0_u128` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `0_u128` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u128 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12
@@ -319,8 +459,12 @@ error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `u128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:97:12
@@ -328,8 +472,12 @@ error[E0004]: non-exhaustive patterns: `43_u128` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_u128` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u128 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_u128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:98:12
@@ -337,8 +485,12 @@ error[E0004]: non-exhaustive patterns: `43_u128` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_u128` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_u128 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12
@@ -346,8 +498,12 @@ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
 LL |         m!(0, ..i8::MAX);
    |            ^ pattern `i8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
@@ -355,8 +511,12 @@ error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `126_i8..=i8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         126_i8..=i8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12
@@ -364,8 +524,12 @@ error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i8::MIN` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i8::MIN => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12
@@ -373,8 +537,12 @@ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:113:12
@@ -382,8 +550,12 @@ error[E0004]: non-exhaustive patterns: `43_i8` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:114:12
@@ -391,8 +563,12 @@ error[E0004]: non-exhaustive patterns: `43_i8` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12
@@ -400,8 +576,12 @@ error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
 LL |         m!(0, ..i16::MAX);
    |            ^ pattern `i16::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i16::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
@@ -409,8 +589,12 @@ error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `32766_i16..=i16::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         32766_i16..=i16::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i16::MIN` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12
@@ -418,8 +602,12 @@ error[E0004]: non-exhaustive patterns: `i16::MIN` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i16::MIN` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i16::MIN => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12
@@ -427,8 +615,12 @@ error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i16::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i16::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:126:12
@@ -436,8 +628,12 @@ error[E0004]: non-exhaustive patterns: `43_i16` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i16` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i16 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:127:12
@@ -445,8 +641,12 @@ error[E0004]: non-exhaustive patterns: `43_i16` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i16` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i16 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12
@@ -454,8 +654,12 @@ error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
 LL |         m!(0, ..i32::MAX);
    |            ^ pattern `i32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i32::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
@@ -463,8 +667,12 @@ error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `2147483646_i32..=i32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         2147483646_i32..=i32::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i32::MIN` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12
@@ -472,8 +680,12 @@ error[E0004]: non-exhaustive patterns: `i32::MIN` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i32::MIN` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i32::MIN => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12
@@ -481,8 +693,12 @@ error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i32::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:139:12
@@ -490,8 +706,12 @@ error[E0004]: non-exhaustive patterns: `43_i32` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i32` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i32 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:140:12
@@ -499,8 +719,12 @@ error[E0004]: non-exhaustive patterns: `43_i32` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i32` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i32 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12
@@ -508,8 +732,12 @@ error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
 LL |         m!(0, ..i64::MAX);
    |            ^ pattern `i64::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i64::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
@@ -517,8 +745,12 @@ error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `9223372036854775806_i64..=i64::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         9223372036854775806_i64..=i64::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i64::MIN` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12
@@ -526,8 +758,12 @@ error[E0004]: non-exhaustive patterns: `i64::MIN` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i64::MIN` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i64::MIN => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12
@@ -535,8 +771,12 @@ error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i64::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i64::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:152:12
@@ -544,8 +784,12 @@ error[E0004]: non-exhaustive patterns: `43_i64` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i64` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i64 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:153:12
@@ -553,8 +797,12 @@ error[E0004]: non-exhaustive patterns: `43_i64` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i64` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i64 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12
@@ -562,8 +810,12 @@ error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
 LL |         m!(0, ..i128::MAX);
    |            ^ pattern `i128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
@@ -571,8 +823,12 @@ error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_
 LL |         m!(0, ..ALMOST_MAX);
    |            ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         170141183460469231731687303715884105726_i128..=i128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i128::MIN` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12
@@ -580,8 +836,12 @@ error[E0004]: non-exhaustive patterns: `i128::MIN` not covered
 LL |         m!(0, ALMOST_MIN..);
    |            ^ pattern `i128::MIN` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i128::MIN => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12
@@ -589,8 +849,12 @@ error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
 LL |         m!(0, ..=ALMOST_MAX);
    |            ^ pattern `i128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:165:12
@@ -598,8 +862,12 @@ error[E0004]: non-exhaustive patterns: `43_i128` not covered
 LL |         m!(0, ..=VAL | VAL_2..);
    |            ^ pattern `43_i128` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i128 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `43_i128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:166:12
@@ -607,8 +875,12 @@ error[E0004]: non-exhaustive patterns: `43_i128` not covered
 LL |         m!(0, ..VAL_1 | VAL_2..);
    |            ^ pattern `43_i128` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         43_i128 => todo!() }
+   |
 
 error: aborting due to 68 previous errors
 
index 7c3c72e04cb781d32091328e33310422e858e473..c6f29fa59085d9258cf9636d2aa84076875ffddd 100644 (file)
@@ -1,3 +1,5 @@
+// check-pass
+
 // FamilyType (GAT workaround)
 pub trait FamilyLt<'a> {
     type Out;
@@ -78,8 +80,6 @@ fn task<P>(processor: P) -> Task
 
 fn main() {
     task(annotate(
-        //~^ the size
-        //~^^ the trait bound
         Annotate::<RefMutFamily<usize>>::new(),
         |value: &mut usize| {
             *value = 2;
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr
deleted file mode 100644 (file)
index 01b1466..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-error[E0277]: the size for values of type `impl Execute` cannot be known at compilation time
-  --> $DIR/issue-62529-1.rs:80:10
-   |
-LL |       task(annotate(
-   |  _____----_^
-   | |     |
-   | |     required by a bound introduced by this call
-LL | |
-LL | |
-LL | |         Annotate::<RefMutFamily<usize>>::new(),
-...  |
-LL | |         }
-LL | |     ));
-   | |_____^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `impl Execute`
-note: required by a bound in `task`
-  --> $DIR/issue-62529-1.rs:69:9
-   |
-LL | fn task<P>(processor: P) -> Task
-   |         ^ required by this bound in `task`
-help: consider relaxing the implicit `Sized` restriction
-   |
-LL | fn task<P: ?Sized>(processor: P) -> Task
-   |          ++++++++
-
-error[E0277]: the trait bound `impl Execute: Execute` is not satisfied
-  --> $DIR/issue-62529-1.rs:80:10
-   |
-LL |       task(annotate(
-   |  _____----_^
-   | |     |
-   | |     required by a bound introduced by this call
-LL | |
-LL | |
-LL | |         Annotate::<RefMutFamily<usize>>::new(),
-...  |
-LL | |         }
-LL | |     ));
-   | |_____^ the trait `Execute` is not implemented for `impl Execute`
-   |
-note: required by a bound in `task`
-  --> $DIR/issue-62529-1.rs:70:10
-   |
-LL | fn task<P>(processor: P) -> Task
-   |    ---- required by a bound in this
-LL | where P: Execute + 'static {
-   |          ^^^^^^^ required by this bound in `task`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
index 7da6b029c26f0f6ad6e712410fa3fe9e16a4fbf0..e6ffe38ee92e871329391f24edee74efa7b7bba1 100644 (file)
@@ -1,5 +1,5 @@
 error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:57:5
+  --> $DIR/issue-71955.rs:54:5
    |
 LL |     foo(bar, "string", |s| s.len() == 5);
    |     ^^^ implementation of `Parser` is not general enough
@@ -8,79 +8,7 @@ LL |     foo(bar, "string", |s| s.len() == 5);
    = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
 
 error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:57:5
-   |
-LL |     foo(bar, "string", |s| s.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:57:5
-   |
-LL |     foo(bar, "string", |s| s.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:57:5
-   |
-LL |     foo(bar, "string", |s| s.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:57:5
-   |
-LL |     foo(bar, "string", |s| s.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:63:5
-   |
-LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:63:5
-   |
-LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:63:5
-   |
-LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:63:5
-   |
-LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |     ^^^ implementation of `Parser` is not general enough
-   |
-   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
-   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
-  --> $DIR/issue-71955.rs:63:5
+  --> $DIR/issue-71955.rs:58:5
    |
 LL |     foo(baz, "string", |s| s.0.len() == 5);
    |     ^^^ implementation of `Parser` is not general enough
@@ -88,5 +16,5 @@ LL |     foo(baz, "string", |s| s.0.len() == 5);
    = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
    = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
 
-error: aborting due to 10 previous errors
+error: aborting due to 2 previous errors
 
index c2feaa91280557c001a6d88fe53b304e89e5905b..0f38f8e3283a278a5a6579706eee58b6e1fe4800 100644 (file)
@@ -1,8 +1,79 @@
-error: fatal error triggered by #[rustc_error]
-  --> $DIR/issue-71955.rs:47:1
+error[E0308]: mismatched types
+  --> $DIR/issue-71955.rs:54:5
    |
-LL | fn main() {
-   | ^^^^^^^^^
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r, 's> FnOnce<(&'r &'s str,)>`
+              found type `for<'r> FnOnce<(&'r &str,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-71955.rs:54:24
+   |
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |                        ^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-71955.rs:34:9
+   |
+LL |     F2: FnOnce(&<F1 as Parser>::Output) -> bool
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-71955.rs:54:5
+   |
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `FnOnce<(&&str,)>`
+              found type `for<'r> FnOnce<(&'r &str,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-71955.rs:54:24
+   |
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |                        ^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-71955.rs:34:44
+   |
+LL |     F2: FnOnce(&<F1 as Parser>::Output) -> bool
+   |                                            ^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-71955.rs:58:5
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>`
+              found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-71955.rs:58:24
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |                        ^^^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-71955.rs:34:9
+   |
+LL |     F2: FnOnce(&<F1 as Parser>::Output) -> bool
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-71955.rs:58:5
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `FnOnce<(&Wrapper<'_>,)>`
+              found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-71955.rs:58:24
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |                        ^^^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-71955.rs:34:44
+   |
+LL |     F2: FnOnce(&<F1 as Parser>::Output) -> bool
+   |                                            ^^^^
 
-error: aborting due to previous error
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
index 3d6778b6942c52c8213684d14fc30ae50ff1df9d..4b7e207b96d49d403512cc978ab55fdeb2f20434 100644 (file)
@@ -42,10 +42,7 @@ fn foo<F1, F2>(
 
 struct Wrapper<'a>(&'a str);
 
-// Because nll currently succeeds and migrate doesn't
-#[rustc_error]
 fn main() {
-    //[nll]~^ fatal
     fn bar<'a>(s: &'a str) -> (&'a str, &'a str) {
         (&s[..1], &s[..])
     }
@@ -56,14 +53,10 @@ fn baz<'a>(s: &'a str) -> (&'a str, Wrapper<'a>) {
 
     foo(bar, "string", |s| s.len() == 5);
     //[migrate]~^ ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
+    //[nll]~^^ ERROR mismatched types
+    //[nll]~| ERROR mismatched types
     foo(baz, "string", |s| s.0.len() == 5);
     //[migrate]~^ ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
-    //[migrate]~| ERROR implementation of `Parser` is not general enough
+    //[nll]~^^ ERROR mismatched types
+    //[nll]~| ERROR mismatched types
 }
index 3a4d6c02a159fd06a0019ec6331950da6d1c15c5..fe319e6c8515c7ff51b02b48f72f0b70304220cd 100644 (file)
@@ -6,7 +6,8 @@ trait SomeTrait<'a> {
 
 fn give_me_ice<T>() {
     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
-    //~^ ERROR: the trait bound `T: SomeTrait<'_>` is not satisfied
+    //~^ ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277]
+    //~| ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277]
 }
 
 fn callee<T: Fn<(&'static (),)>>() {
index aaf45dc7ad5642514b11428fa6b794403ab46369..13b68b072403a57b148fcca053f9d3b43ea5029c 100644 (file)
@@ -9,6 +9,17 @@ help: consider restricting type parameter `T`
 LL | fn give_me_ice<T: SomeTrait<'_>>() {
    |                 +++++++++++++++
 
-error: aborting due to previous error
+error[E0277]: the trait bound `T: SomeTrait<'_>` is not satisfied
+  --> $DIR/issue-85455.rs:8:14
+   |
+LL |     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait<'_>` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | fn give_me_ice<T: SomeTrait<'_>>() {
+   |                 +++++++++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index 4c9ec2a83ff37959c37c945fcd6866e3f8f0ab51..362c67dafd2c5e88c7d050ba45e0bdbcbdcfb7d3 100644 (file)
@@ -6,7 +6,7 @@ LL |         let f: impl core::future::Future<Output = u8> = async { 1 };
    |                                                         |
    |                                                         `async` blocks are only allowed in Rust 2018 or later
    |
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
index 3d8478f06db0ea0875c640774d7a3f371955ee0b..6eabd9b1015b79602886d27770a93f7de498c1fb 100644 (file)
@@ -29,6 +29,11 @@ fn foo6<const X: usize>() {}
 #[rustc_legacy_const_generics(0)] //~ ERROR #[rustc_legacy_const_generics] functions must only have
 fn foo8<X>() {}
 
+impl S {
+    #[rustc_legacy_const_generics(0)] //~ ERROR attribute should be applied to a function
+    fn foo9<const X: usize>() {}
+}
+
 #[rustc_legacy_const_generics] //~ ERROR malformed `rustc_legacy_const_generics` attribute
 fn bar1() {}
 
index 1f55a8e72d2cb29795b0c1dcc37ff071a5d4a166..bfe7bb2e10dccf7d9cd14252eb430fc64a0cc78c 100644 (file)
@@ -7,13 +7,13 @@ LL | #[rustc_legacy_const_generics(0usize)]
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: malformed `rustc_legacy_const_generics` attribute input
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:32:1
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:37:1
    |
 LL | #[rustc_legacy_const_generics]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]`
 
 error: malformed `rustc_legacy_const_generics` attribute input
-  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:35:1
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:40:1
    |
 LL | #[rustc_legacy_const_generics = 1]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]`
@@ -66,6 +66,14 @@ LL | #[rustc_legacy_const_generics(0)]
 LL | fn foo8<X>() {}
    |         - non-const generic parameter
 
+error: attribute should be applied to a function
+  --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:33:5
+   |
+LL |     #[rustc_legacy_const_generics(0)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fn foo9<const X: usize>() {}
+   |     ---------------------------- not a function
+
 error: attribute should be applied to a function
   --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:5
    |
@@ -82,6 +90,6 @@ LL |     fn foo7<const X: usize>();
    |
    = help: replace the const parameters with concrete consts
 
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
 
 For more information about this error, try `rustc --explain E0044`.
index 3fd81401e00fd57d15679c5aea99f0180ddbcff2..193f89f83789713ceee17de020266ad0c9925ccc 100644 (file)
@@ -7,7 +7,7 @@
 
 impl Foo {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn foo(self) {}
 }
 
index b0524f056ef7fdabfef8a94f188c032918d6895d..a336d1b0ed55d7e5707a1131dde331581ecaefce 100644 (file)
@@ -1,8 +1,8 @@
-error[E0599]: the method `to_string` exists for raw pointer `*const u8`, but its trait bounds were not satisfied
+error[E0599]: `*const u8` doesn't implement `std::fmt::Display`
   --> $DIR/issue-21596.rs:4:22
    |
 LL |     println!("{}", z.to_string());
-   |                      ^^^^^^^^^ method cannot be called on `*const u8` due to unsatisfied trait bounds
+   |                      ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter
    |
    = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref
    = note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior
index ac24648e49e915fda9e1e08a72cb55744c1c3155..d67f184720e6cb82be639057fdc5bc888390bdcd 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-wasm32-bare FIXME(#93923) llvm miscompilation
 
 use std::collections::HashMap;
 use std::path::Path;
index 7895cefb4cb2ed9eb4396f173f4b56f2646ef1b8..a0d32616f83b74f2dad691636171476b1d40cc59 100644 (file)
@@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard
   --> $DIR/issue-27282-move-ref-mut-into-guard.rs:9:19
    |
 LL |             if { (|| { let bar = foo; bar.take() })(); false } => {},
-   |                   ^^             ---
-   |                   |              |
-   |                   |              move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
-   |                   |              move occurs due to use in closure
+   |                   ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                   |
    |                   move out of `foo` occurs here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
index 6f345f56d1aa112ff8f8ca44bf0cbcf56d63229e..e5b671d7b7ab0b71bbf6e871864094dd35c6ed2a 100644 (file)
@@ -4,10 +4,7 @@ error[E0382]: borrow of moved value: `bad_letters`
 LL |     let mut bad_letters = vec!['e', 't', 'o', 'i'];
    |         --------------- move occurs because `bad_letters` has type `Vec<char>`, which does not implement the `Copy` trait
 LL |     for l in bad_letters {
-   |              -----------
-   |              |
-   |              `bad_letters` moved due to this implicit call to `.into_iter()`
-   |              help: consider borrowing to avoid moving into the for loop: `&bad_letters`
+   |              ----------- `bad_letters` moved due to this implicit call to `.into_iter()`
 ...
 LL |     bad_letters.push('s');
    |     ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
@@ -17,6 +14,10 @@ note: this function takes ownership of the receiver `self`, which moves `bad_let
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider iterating over a slice of the `Vec<char>`'s content to avoid moving into the `for` loop
+   |
+LL |     for l in &bad_letters {
+   |              +
 
 error: aborting due to previous error
 
index e0da3fd5195cb26df853777f30ee45abfcc9dd61..ef178bbd155388f94e8b832d5c48c2a6bb65ade4 100644 (file)
@@ -4,10 +4,7 @@ error[E0382]: use of moved value: `orig`
 LL |     let orig = vec![true];
    |         ---- move occurs because `orig` has type `Vec<bool>`, which does not implement the `Copy` trait
 LL |     for _val in orig {}
-   |                 ----
-   |                 |
-   |                 `orig` moved due to this implicit call to `.into_iter()`
-   |                 help: consider borrowing to avoid moving into the for loop: `&orig`
+   |                 ---- `orig` moved due to this implicit call to `.into_iter()`
 LL |     let _closure = || orig;
    |                    ^^ ---- use occurs due to use in closure
    |                    |
@@ -18,6 +15,10 @@ note: this function takes ownership of the receiver `self`, which moves `orig`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider iterating over a slice of the `Vec<bool>`'s content to avoid moving into the `for` loop
+   |
+LL |     for _val in &orig {}
+   |                 +
 
 error: aborting due to previous error
 
index d2e9343f86cd50fa853f993610390868e4f2cff0..26e9e2c8f91cf67409f196878302ee80dfcfa51a 100644 (file)
@@ -1,6 +1,7 @@
 // test for #87707
 // edition:2018
 // run-fail
+// exec-env:RUST_BACKTRACE=0
 // check-run-results
 
 use std::sync::Once;
index 8f82ccc0c2abeb19ce4a013e6ca7c704865e7feb..e6c9ea0eb53c39033cca72cfa11f927268799a73 100644 (file)
@@ -1,3 +1,3 @@
-thread 'main' panicked at 'Here Once instance is poisoned.', $DIR/issue-87707.rs:12:24
+thread 'main' panicked at 'Here Once instance is poisoned.', $DIR/issue-87707.rs:13:24
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-thread 'main' panicked at 'Once instance has previously been poisoned', $DIR/issue-87707.rs:14:7
+thread 'main' panicked at 'Once instance has previously been poisoned', $DIR/issue-87707.rs:15:7
index 1e7eb26fde2725abe6834b2d4d22e15b2bb7a41a..62100e5cc9496c0dd153155c3402582d6817823f 100644 (file)
@@ -20,7 +20,7 @@ pub fn stable() {}
 #[unstable(feature = "unstable_test_feature", issue = "none")]
 pub mod unstable_mod {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated() {}
 
     pub fn unstable() {}
index 58cae180196d360ea03b9511e4f57938feba8d52..4e3547250e4c4f1016d42924d0779ae9bedab482 100644 (file)
@@ -4,7 +4,7 @@
 #![unstable(feature = "unstable_test_feature", issue = "none")]
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn foo() -> usize {
     20
 }
index de4058887cffd786bc2f9eb9cc09bf1673bcb94a..99c29dcdda6777f28e7d8d43438caf2a5881fdfc 100644 (file)
@@ -5,21 +5,21 @@
 #![stable(feature = "lint_stability", since = "1.0.0")]
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated() {}
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated_text() {}
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "99.99.99", reason = "text")]
+#[deprecated(since = "99.99.99", note = "text")]
 pub fn deprecated_future() {}
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated_unstable() {}
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated_unstable_text() {}
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -37,17 +37,17 @@ pub fn stable_text() {}
 
 impl MethodTester {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated(&self) {}
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated_unstable(&self) {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated_unstable_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -64,17 +64,17 @@ pub fn method_stable_text(&self) {}
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub trait Trait {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated(&self) {}
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated_unstable(&self) {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated_unstable_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -93,7 +93,7 @@ pub trait TraitWithAssociatedTypes {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     type TypeUnstable = u8;
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     type TypeDeprecated = u8;
 }
 
@@ -104,18 +104,18 @@ impl Trait for MethodTester {}
 pub trait UnstableTrait { fn dummy(&self) { } }
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub trait DeprecatedTrait {
     #[stable(feature = "stable_test_feature", since = "1.0.0")] fn dummy(&self) { }
 }
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedStruct {
     #[stable(feature = "stable_test_feature", since = "1.0.0")] pub i: isize
 }
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnstableStruct {
     #[stable(feature = "stable_test_feature", since = "1.0.0")] pub i: isize
 }
@@ -133,10 +133,10 @@ pub enum UnstableEnum {}
 pub enum StableEnum {}
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnitStruct;
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnstableUnitStruct;
 #[unstable(feature = "unstable_test_feature", issue = "none")]
 pub struct UnstableUnitStruct;
@@ -146,10 +146,10 @@ pub enum StableEnum {}
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub enum Enum {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     DeprecatedVariant,
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     DeprecatedUnstableVariant,
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     UnstableVariant,
@@ -159,10 +159,10 @@ pub enum Enum {
 }
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
 #[unstable(feature = "unstable_test_feature", issue = "none")]
 pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
index 3cbb48c4a6be0567dff147330b0f7301e0705743..e72a501e11b40cf643781d266f91b09135ecb5f2 100644 (file)
@@ -6,7 +6,7 @@ pub struct Stable {
     pub inherit: u8,
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub override1: u8,
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub override2: u8,
     #[stable(feature = "rust2", since = "2.0.0")]
@@ -17,7 +17,7 @@ pub struct Stable {
 pub struct Stable2(#[stable(feature = "rust2", since = "2.0.0")] pub u8,
                    #[unstable(feature = "unstable_test_feature", issue = "none")] pub u8,
                    #[unstable(feature = "unstable_test_feature", issue = "none")]
-                   #[rustc_deprecated(since = "1.0.0", reason = "text")] pub u8,
+                   #[deprecated(since = "1.0.0", note = "text")] pub u8,
                    pub u8);
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -28,7 +28,7 @@ pub enum Stable3 {
     Override1,
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     Override2,
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     Override3,
 }
@@ -38,7 +38,7 @@ pub struct Unstable {
     pub inherit: u8,
     #[stable(feature = "rust1", since = "1.0.0")]
     pub override1: u8,
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub override2: u8,
 }
@@ -47,10 +47,10 @@ pub struct Unstable {
 pub struct Unstable2(pub u8,
                      #[stable(feature = "rust1", since = "1.0.0")] pub u8,
                      #[unstable(feature = "unstable_test_feature", issue = "none")]
-                     #[rustc_deprecated(since = "1.0.0", reason = "text")] pub u8);
+                     #[deprecated(since = "1.0.0", note = "text")] pub u8);
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct Deprecated {
     pub inherit: u8,
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -60,7 +60,7 @@ pub struct Deprecated {
 }
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct Deprecated2(pub u8,
                        #[stable(feature = "rust1", since = "1.0.0")] pub u8,
                        #[unstable(feature = "unstable_test_feature", issue = "none")] pub u8);
index 2a4f95f555fd995a2428def9393f8cfc6c0f9e7c..94a8d08c8fe9ce98750b3960aa3ad3f080175e4a 100644 (file)
@@ -169,10 +169,10 @@ trait LocalTrait2 : DeprecatedTrait { }
 
 mod this_crate {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated() {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated_text() {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -190,10 +190,10 @@ pub fn stable_text() {}
 
     impl MethodTester {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         pub fn method_deprecated(&self) {}
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         pub fn method_deprecated_text(&self) {}
 
         #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -209,10 +209,10 @@ pub fn method_stable_text(&self) {}
 
     pub trait Trait {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn trait_deprecated(&self) {}
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn trait_deprecated_text(&self) {}
 
         #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -229,7 +229,7 @@ fn trait_stable_text(&self) {}
     impl Trait for MethodTester {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedStruct {
         #[stable(feature = "stable_test_feature", since = "1.0.0")] i: isize
     }
@@ -243,7 +243,7 @@ pub struct StableStruct {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedUnitStruct;
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub struct UnstableUnitStruct;
@@ -252,7 +252,7 @@ pub struct StableStruct {
 
     pub enum Enum {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         DeprecatedVariant,
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         UnstableVariant,
@@ -262,7 +262,7 @@ pub enum Enum {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedTupleStruct(isize);
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub struct UnstableTupleStruct(isize);
@@ -382,7 +382,7 @@ fn test_method_object(foo: &dyn Trait) {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn test_fn_body() {
         fn fn_in_body() {}
         fn_in_body();
@@ -390,7 +390,7 @@ fn fn_in_body() {}
 
     impl MethodTester {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn test_method_body(&self) {
             fn fn_in_body() {}
             fn_in_body();
@@ -398,7 +398,7 @@ fn fn_in_body() {}
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub trait DeprecatedTrait {
         fn dummy(&self) { }
     }
index 2f600971da113acd640856ae8b87374acd0833b9..bdc66e83083f66e6704b198354088eec67bf4a68 100644 (file)
@@ -219,10 +219,10 @@ fn test_inheritance() {
 
 mod this_crate {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated() {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated_text() {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -240,10 +240,10 @@ pub fn stable_text() {}
 
     impl MethodTester {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         pub fn method_deprecated(&self) {}
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         pub fn method_deprecated_text(&self) {}
 
         #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -259,10 +259,10 @@ pub fn method_stable_text(&self) {}
 
     pub trait Trait {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn trait_deprecated(&self) {}
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn trait_deprecated_text(&self) {}
 
         #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -279,7 +279,7 @@ fn trait_stable_text(&self) {}
     impl Trait for MethodTester {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedStruct {
         #[stable(feature = "stable_test_feature", since = "1.0.0")] i: isize
     }
@@ -293,7 +293,7 @@ pub struct StableStruct {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedUnitStruct;
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub struct UnstableUnitStruct;
@@ -302,7 +302,7 @@ pub struct StableStruct {
 
     pub enum Enum {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         DeprecatedVariant,
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         UnstableVariant,
@@ -312,7 +312,7 @@ pub enum Enum {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedTupleStruct(isize);
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub struct UnstableTupleStruct(isize);
@@ -433,7 +433,7 @@ fn test_method_object(foo: &dyn Trait) {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn test_fn_body() {
         fn fn_in_body() {}
         fn_in_body(); //~ WARN use of deprecated function `this_crate::test_fn_body::fn_in_body`: text
@@ -441,7 +441,7 @@ fn fn_in_body() {}
 
     impl MethodTester {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn test_method_body(&self) {
             fn fn_in_body() {}
             fn_in_body(); //~ WARN use of deprecated function `this_crate::MethodTester::test_method_body::fn_in_body`: text
@@ -449,7 +449,7 @@ fn fn_in_body() {}
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub trait DeprecatedTrait {
         fn dummy(&self) { }
     }
index a44eb1ce10a22aea4734f6dfe69f687a1c7e42bf..a5511966d7e79bad5793724f0623b8f87f973bdd 100644 (file)
@@ -160,7 +160,7 @@ struct Stable {
         inherit: u8,
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         override1: u8,
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         override2: u8,
     }
@@ -169,14 +169,14 @@ struct Stable {
     struct Stable2(u8,
                    #[stable(feature = "rust1", since = "1.0.0")] u8,
                    #[unstable(feature = "unstable_test_feature", issue = "none")]
-                   #[rustc_deprecated(since = "1.0.0", reason = "text")] u8);
+                   #[deprecated(since = "1.0.0", note = "text")] u8);
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     struct Unstable {
         inherit: u8,
         #[stable(feature = "rust1", since = "1.0.0")]
         override1: u8,
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         override2: u8,
     }
@@ -185,10 +185,10 @@ struct Unstable {
     struct Unstable2(u8,
                      #[stable(feature = "rust1", since = "1.0.0")] u8,
                      #[unstable(feature = "unstable_test_feature", issue = "none")]
-                     #[rustc_deprecated(since = "1.0.0", reason = "text")] u8);
+                     #[deprecated(since = "1.0.0", note = "text")] u8);
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     struct Deprecated {
         inherit: u8,
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -198,7 +198,7 @@ struct Deprecated {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     struct Deprecated2(u8,
                        #[stable(feature = "rust1", since = "1.0.0")] u8,
                        #[unstable(feature = "unstable_test_feature", issue = "none")] u8);
index 4083648984867b475aa73ccafd79b71dc51f1a82..51990b6eef161fba0eb8a6d8593b8ff422b1b20f 100644 (file)
@@ -135,7 +135,7 @@ struct Stable {
         inherit: u8,
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         override1: u8,
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         override2: u8,
         #[stable(feature = "rust2", since = "2.0.0")]
@@ -146,14 +146,14 @@ struct Stable {
     struct Stable2(u8,
                    #[stable(feature = "rust2", since = "2.0.0")] u8,
                    #[unstable(feature = "unstable_test_feature", issue = "none")]
-                   #[rustc_deprecated(since = "1.0.0", reason = "text")] u8);
+                   #[deprecated(since = "1.0.0", note = "text")] u8);
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     struct Unstable {
         inherit: u8,
         #[stable(feature = "rust1", since = "1.0.0")]
         override1: u8,
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         override2: u8,
     }
@@ -162,10 +162,10 @@ struct Unstable {
     struct Unstable2(u8,
                      #[stable(feature = "rust1", since = "1.0.0")] u8,
                      #[unstable(feature = "unstable_test_feature", issue = "none")]
-                     #[rustc_deprecated(since = "1.0.0", reason = "text")] u8);
+                     #[deprecated(since = "1.0.0", note = "text")] u8);
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     struct Deprecated {
         inherit: u8,
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -175,7 +175,7 @@ struct Deprecated {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     struct Deprecated2(u8,
                        #[stable(feature = "rust1", since = "1.0.0")] u8,
                        #[unstable(feature = "unstable_test_feature", issue = "none")] u8);
index e5620a9f8e710d37de55464758315f8b15416dc0..464b32c5f43ed994ac6a1259da96e5f41a185757 100644 (file)
@@ -204,14 +204,14 @@ fn test_inheritance() {
 
 mod this_crate {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated() {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn deprecated_text() {}
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(since = "99.99.99", reason = "text")]
+    #[deprecated(since = "99.99.99", note = "text")]
     pub fn deprecated_future() {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -229,10 +229,10 @@ pub fn stable_text() {}
 
     impl MethodTester {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         pub fn method_deprecated(&self) {}
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         pub fn method_deprecated_text(&self) {}
 
         #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -248,10 +248,10 @@ pub fn method_stable_text(&self) {}
 
     pub trait Trait {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn trait_deprecated(&self) {}
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn trait_deprecated_text(&self) {}
 
         #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -268,7 +268,7 @@ fn trait_stable_text(&self) {}
     impl Trait for MethodTester {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedStruct {
         #[stable(feature = "stable_test_feature", since = "1.0.0")] i: isize
     }
@@ -282,7 +282,7 @@ pub struct StableStruct {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedUnitStruct;
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub struct UnstableUnitStruct;
@@ -291,7 +291,7 @@ pub struct StableStruct {
 
     pub enum Enum {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         DeprecatedVariant,
         #[unstable(feature = "unstable_test_feature", issue = "none")]
         UnstableVariant,
@@ -301,7 +301,7 @@ pub enum Enum {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub struct DeprecatedTupleStruct(isize);
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     pub struct UnstableTupleStruct(isize);
@@ -423,7 +423,7 @@ fn test_method_object(foo: &dyn Trait) {
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn test_fn_body() {
         fn fn_in_body() {}
         fn_in_body();
@@ -431,7 +431,7 @@ fn fn_in_body() {}
 
     impl MethodTester {
         #[unstable(feature = "unstable_test_feature", issue = "none")]
-        #[rustc_deprecated(since = "1.0.0", reason = "text")]
+        #[deprecated(since = "1.0.0", note = "text")]
         fn test_method_body(&self) {
             fn fn_in_body() {}
             fn_in_body();
@@ -439,7 +439,7 @@ fn fn_in_body() {}
     }
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub trait DeprecatedTrait {
         fn dummy(&self) { }
     }
index acb81b0bf9def5ef9b8a65a085e4a29fe6a9bd69..b73a76555296fc5b5c7e1c2dae7cbc65d6b42d16 100644 (file)
@@ -1,12 +1,15 @@
+// check-pass
+
 // edition:2018
-#![deny(must_not_suspend)]  //~ ERROR the `must_not_suspend`
-//~| ERROR the `must_not_suspend`
-//~| ERROR the `must_not_suspend`
+#![deny(must_not_suspend)]
+//~^ WARNING unknown lint: `must_not_suspend`
+//~| WARNING unknown lint: `must_not_suspend`
+//~| WARNING unknown lint: `must_not_suspend`
 
 async fn other() {}
 
 pub async fn uhoh(m: std::sync::Mutex<()>) {
-    let _guard = m.lock().unwrap(); //~ ERROR `MutexGuard` held across
+    let _guard = m.lock().unwrap();
     other().await;
 }
 
index 0d4319670e6622e7ade73ade1dc610e6e25feb41..b58ecb55596ab01f4ee49ba81428cc9fed8add0f 100644 (file)
@@ -1,54 +1,33 @@
-error[E0658]: the `must_not_suspend` lint is unstable
-  --> $DIR/gated.rs:2:1
+warning: unknown lint: `must_not_suspend`
+  --> $DIR/gated.rs:4:1
    |
 LL | #![deny(must_not_suspend)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: `#[warn(unknown_lints)]` on by default
+   = note: the `must_not_suspend` lint is unstable
    = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
    = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
 
-error[E0658]: the `must_not_suspend` lint is unstable
-  --> $DIR/gated.rs:2:1
+warning: unknown lint: `must_not_suspend`
+  --> $DIR/gated.rs:4:1
    |
 LL | #![deny(must_not_suspend)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `must_not_suspend` lint is unstable
    = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
    = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
 
-error[E0658]: the `must_not_suspend` lint is unstable
-  --> $DIR/gated.rs:2:1
+warning: unknown lint: `must_not_suspend`
+  --> $DIR/gated.rs:4:1
    |
 LL | #![deny(must_not_suspend)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `must_not_suspend` lint is unstable
    = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
    = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
 
-error: `MutexGuard` held across a suspend point, but should not be
-  --> $DIR/gated.rs:9:9
-   |
-LL |     let _guard = m.lock().unwrap();
-   |         ^^^^^^
-LL |     other().await;
-   |            ------ the value is held across this suspend point
-   |
-note: the lint level is defined here
-  --> $DIR/gated.rs:2:9
-   |
-LL | #![deny(must_not_suspend)]
-   |         ^^^^^^^^^^^^^^^^
-note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send`
-  --> $DIR/gated.rs:9:9
-   |
-LL |     let _guard = m.lock().unwrap();
-   |         ^^^^^^
-help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/gated.rs:9:9
-   |
-LL |     let _guard = m.lock().unwrap();
-   |         ^^^^^^
-
-error: aborting due to 4 previous errors
+warning: 3 warnings emitted
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs b/src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.rs
new file mode 100644 (file)
index 0000000..bafdea9
--- /dev/null
@@ -0,0 +1,14 @@
+#![feature(lint_reasons)]
+
+#![deny(unused_attributes)]
+
+#[allow(reason = "I want to allow something")]//~ ERROR unused attribute
+#[expect(reason = "I don't know what I'm waiting for")]//~ ERROR unused attribute
+#[warn(reason = "This should be warn by default")]//~ ERROR unused attribute
+#[deny(reason = "All listed lints are denied")]//~ ERROR unused attribute
+#[forbid(reason = "Just some reason")]//~ ERROR unused attribute
+
+#[allow(clippy::box_collection, reason = "This is still valid")]
+#[warn(dead_code, reason = "This is also reasonable")]
+
+fn main() {}
diff --git a/src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr b/src/test/ui/lint/rfc-2383-lint-reason/lint-attribute-only-with-reason.stderr
new file mode 100644 (file)
index 0000000..3bf8137
--- /dev/null
@@ -0,0 +1,47 @@
+error: unused attribute
+  --> $DIR/lint-attribute-only-with-reason.rs:5:1
+   |
+LL | #[allow(reason = "I want to allow something")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: the lint level is defined here
+  --> $DIR/lint-attribute-only-with-reason.rs:3:9
+   |
+LL | #![deny(unused_attributes)]
+   |         ^^^^^^^^^^^^^^^^^
+   = note: attribute `allow` without any lints has no effect
+
+error: unused attribute
+  --> $DIR/lint-attribute-only-with-reason.rs:6:1
+   |
+LL | #[expect(reason = "I don't know what I'm waiting for")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `expect` without any lints has no effect
+
+error: unused attribute
+  --> $DIR/lint-attribute-only-with-reason.rs:7:1
+   |
+LL | #[warn(reason = "This should be warn by default")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `warn` without any lints has no effect
+
+error: unused attribute
+  --> $DIR/lint-attribute-only-with-reason.rs:8:1
+   |
+LL | #[deny(reason = "All listed lints are denied")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `deny` without any lints has no effect
+
+error: unused attribute
+  --> $DIR/lint-attribute-only-with-reason.rs:9:1
+   |
+LL | #[forbid(reason = "Just some reason")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `forbid` without any lints has no effect
+
+error: aborting due to 5 previous errors
+
index ad42cce71f6865a31262142deb1ef984763cb8a3..57d76016c4539d3e8ff8f0623af847d73ae30a08 100644 (file)
@@ -4,10 +4,7 @@ error[E0382]: use of moved value: `x`
 LL | fn foo(x: Vec<S>) {
    |        - move occurs because `x` has type `Vec<S>`, which does not implement the `Copy` trait
 LL |     for y in x {
-   |              -
-   |              |
-   |              `x` moved due to this implicit call to `.into_iter()`
-   |              help: consider borrowing to avoid moving into the for loop: `&x`
+   |              - `x` moved due to this implicit call to `.into_iter()`
 ...
 LL |     let z = x;
    |             ^ value used here after move
@@ -17,6 +14,10 @@ note: this function takes ownership of the receiver `self`, which moves `x`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider iterating over a slice of the `Vec<S>`'s content to avoid moving into the `for` loop
+   |
+LL |     for y in &x {
+   |              +
 
 error: aborting due to previous error
 
index 50e6b81dcf4b4a62a95111d230bb6a7b061638af..f66afa94f4da71fe9db1e389001a7d101c97c3da 100644 (file)
@@ -1,6 +1,6 @@
 warning: Linking globals named 'foo': symbol multiply defined!
 
-error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu.0.rcgu.o": 
+error: failed to load bitcode of module "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu.0.rcgu.o": 
 
 error: aborting due to previous error; 1 warning emitted
 
index 123e244a53eb44dc220e5caa11bab06fa203184a..3aadd4b0ca64181d732e9b2dcbe649bc173f58b9 100644 (file)
@@ -7,7 +7,7 @@
 macro_rules! unstable_macro{ () => () }
 
 #[stable(feature = "deprecated_macros", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "deprecation reason")]
+#[deprecated(since = "1.0.0", note = "deprecation note")]
 #[macro_export]
 macro_rules! deprecated_macro{ () => () }
 
index 019f6a874cab3719395af067d12db0073f8c694b..ed7618a672be8910d0a710132a68374e8b1fa2d4 100644 (file)
@@ -14,7 +14,7 @@ macro_rules! local_unstable { () => () }
 macro local_unstable_modern() {}
 
 #[stable(feature = "deprecated_macros", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "local deprecation reason")]
+#[deprecated(since = "1.0.0", note = "local deprecation note")]
 #[macro_export]
 macro_rules! local_deprecated{ () => () }
 
@@ -25,7 +25,7 @@ fn main() {
     // unstable_macro_modern!(); // ERROR use of unstable library feature 'unstable_macros'
 
     deprecated_macro!();
-    //~^ WARN use of deprecated macro `deprecated_macro`: deprecation reason
+    //~^ WARN use of deprecated macro `deprecated_macro`: deprecation note
     local_deprecated!();
-    //~^ WARN use of deprecated macro `local_deprecated`: local deprecation reason
+    //~^ WARN use of deprecated macro `local_deprecated`: local deprecation note
 }
index 75da9f47a3573e45a78d05e75f3d87b6cd189ab2..2cfdb52b174a90f3dce9ecc667e2f026fda7dc96 100644 (file)
@@ -22,7 +22,7 @@ LL |     unstable_macro!();
    |
    = help: add `#![feature(unstable_macros)]` to the crate attributes to enable
 
-warning: use of deprecated macro `deprecated_macro`: deprecation reason
+warning: use of deprecated macro `deprecated_macro`: deprecation note
   --> $DIR/macro-stability.rs:27:5
    |
 LL |     deprecated_macro!();
@@ -30,7 +30,7 @@ LL |     deprecated_macro!();
    |
    = note: `#[warn(deprecated)]` on by default
 
-warning: use of deprecated macro `local_deprecated`: local deprecation reason
+warning: use of deprecated macro `local_deprecated`: local deprecation note
   --> $DIR/macro-stability.rs:29:5
    |
 LL |     local_deprecated!();
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs b/src/test/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs
new file mode 100644 (file)
index 0000000..ed94c27
--- /dev/null
@@ -0,0 +1,28 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+macro_rules! nested {
+    ( $a:ident ) => {
+        macro_rules! $a {
+            ( $$( $b:ident ),* ) => {
+                $$(
+                    macro_rules! $b {
+                        ( $$$$( $c:ident ),* ) => {
+                            $$$$(
+                                fn $c() -> &'static str { stringify!($c) }
+                            ),*
+                        };
+                    }
+                )*
+            };
+        }
+    };
+}
+
+fn main() {
+    nested!(a);
+    a!(b);
+    b!(c);
+    assert_eq!(c(), "c");
+}
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs b/src/test/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs
new file mode 100644 (file)
index 0000000..6434ecc
--- /dev/null
@@ -0,0 +1,14 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+macro_rules! ignore {
+    ( $( $i:ident ),* ) => {{
+        let array: [i32; 0] = [$( ${ignore(i)} )*];
+        array
+    }};
+}
+
+fn main() {
+    assert_eq!(ignore!(a, b, c), []);
+}
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs
new file mode 100644 (file)
index 0000000..cff6f29
--- /dev/null
@@ -0,0 +1,9 @@
+macro_rules! count {
+    ( $( $e:stmt ),* ) => {
+        ${ count(e) }
+        //~^ ERROR meta-variable expressions are unstable
+    };
+}
+
+fn main() {
+}
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
new file mode 100644 (file)
index 0000000..f573194
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: meta-variable expressions are unstable
+  --> $DIR/required-feature.rs:3:10
+   |
+LL |         ${ count(e) }
+   |          ^^^^^^^^^^^^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs b/src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
new file mode 100644 (file)
index 0000000..ea73fd0
--- /dev/null
@@ -0,0 +1,148 @@
+#![feature(macro_metavar_expr)]
+
+// `curly` = Right hand side curly brackets
+// `no_rhs_dollar` = No dollar sign at the right hand side meta variable "function"
+// `round` = Left hand side round brackets
+
+macro_rules! curly__no_rhs_dollar__round {
+    ( $( $i:ident ),* ) => { ${ count(i) } };
+}
+
+macro_rules! curly__no_rhs_dollar__no_round {
+    ( $i:ident ) => { ${ count(i) } };
+}
+
+macro_rules! curly__rhs_dollar__round {
+    ( $( $i:ident ),* ) => { ${ count($i) } };
+    //~^ ERROR expected identifier, found `$`
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! curly__rhs_dollar__no_round {
+    ( $i:ident ) => { ${ count($i) } };
+    //~^ ERROR expected identifier, found `$`
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! no_curly__no_rhs_dollar__round {
+    ( $( $i:ident ),* ) => { count(i) };
+    //~^ ERROR cannot find function `count` in this scope
+    //~| ERROR cannot find value `i` in this scope
+}
+
+macro_rules! no_curly__no_rhs_dollar__no_round {
+    ( $i:ident ) => { count(i) };
+    //~^ ERROR cannot find function `count` in this scope
+    //~| ERROR cannot find value `i` in this scope
+}
+
+macro_rules! no_curly__rhs_dollar__round {
+    ( $( $i:ident ),* ) => { count($i) };
+    //~^ ERROR variable 'i' is still repeating at this depth
+}
+
+macro_rules! no_curly__rhs_dollar__no_round {
+    ( $i:ident ) => { count($i) };
+    //~^ ERROR cannot find function `count` in this scope
+}
+
+// Other scenarios
+
+macro_rules! dollar_dollar_in_the_lhs {
+    ( $$ $a:ident ) => {
+    //~^ ERROR unexpected token: $
+    };
+}
+
+macro_rules! extra_garbage_after_metavar {
+    ( $( $i:ident ),* ) => {
+        ${count() a b c}
+        //~^ ERROR unexpected token: a
+        //~| ERROR expected expression, found `$`
+        ${count(i a b c)}
+        //~^ ERROR unexpected token: a
+        ${count(i, 1 a b c)}
+        //~^ ERROR unexpected token: a
+        ${count(i) a b c}
+        //~^ ERROR unexpected token: a
+
+        ${ignore(i) a b c}
+        //~^ ERROR unexpected token: a
+        ${ignore(i a b c)}
+        //~^ ERROR unexpected token: a
+
+        ${index() a b c}
+        //~^ ERROR unexpected token: a
+        ${index(1 a b c)}
+        //~^ ERROR unexpected token: a
+
+        ${index() a b c}
+        //~^ ERROR unexpected token: a
+        ${index(1 a b c)}
+        //~^ ERROR unexpected token: a
+    };
+}
+
+const IDX: usize = 1;
+macro_rules! metavar_depth_is_not_literal {
+    ( $( $i:ident ),* ) => { ${ index(IDX) } };
+    //~^ ERROR meta-variable expression depth must be a literal
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_in_the_lhs {
+    ( ${ length() } ) => {
+        //~^ ERROR unexpected token: {
+        //~| ERROR expected one of: `*`, `+`, or `?`
+    };
+}
+
+macro_rules! metavar_token_without_ident {
+    ( $( $i:ident ),* ) => { ${ ignore() } };
+    //~^ ERROR expected identifier
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_with_literal_suffix {
+    ( $( $i:ident ),* ) => { ${ index(1u32) } };
+    //~^ ERROR only unsuffixes integer literals are supported in meta-variable expressions
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_without_parens {
+    ( $( $i:ident ),* ) => { ${ count{i} } };
+    //~^ ERROR meta-variable expression parameter must be wrapped in parentheses
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! open_brackets_without_tokens {
+    ( $( $i:ident ),* ) => { ${ {} } };
+    //~^ ERROR expected expression, found `$`
+    //~| ERROR expected identifier
+}
+
+macro_rules! unknown_metavar {
+    ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+    //~^ ERROR unrecognized meta-variable expression
+    //~| ERROR expected expression
+}
+
+fn main() {
+    curly__no_rhs_dollar__round!(a, b, c);
+    curly__no_rhs_dollar__no_round!(a);
+    curly__rhs_dollar__round!(a, b, c);
+    curly__rhs_dollar__no_round!(a);
+    no_curly__no_rhs_dollar__round!(a, b, c);
+    no_curly__no_rhs_dollar__no_round!(a);
+    no_curly__rhs_dollar__round!(a, b, c);
+    no_curly__rhs_dollar__no_round!(a);
+    //~^ ERROR cannot find value `a` in this scope
+
+    extra_garbage_after_metavar!(a);
+    unknown_metavar!(a);
+    metavar_without_parens!(a);
+    metavar_token_without_ident!(a);
+    metavar_depth_is_not_literal!(a);
+    metavar_with_literal_suffix!(a);
+    open_brackets_without_tokens!(a)
+}
diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
new file mode 100644 (file)
index 0000000..dc8b7a6
--- /dev/null
@@ -0,0 +1,367 @@
+error: expected identifier, found `$`
+  --> $DIR/syntax-errors.rs:16:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ count($i) } };
+   |                                 ^^^^^ - help: try removing `$`
+
+error: expected identifier, found `$`
+  --> $DIR/syntax-errors.rs:22:26
+   |
+LL |     ( $i:ident ) => { ${ count($i) } };
+   |                          ^^^^^ - help: try removing `$`
+
+error: unexpected token: $
+  --> $DIR/syntax-errors.rs:52:8
+   |
+LL |     ( $$ $a:ident ) => {
+   |        ^
+
+note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
+  --> $DIR/syntax-errors.rs:52:8
+   |
+LL |     ( $$ $a:ident ) => {
+   |        ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:59:19
+   |
+LL |         ${count() a b c}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:59:19
+   |
+LL |         ${count() a b c}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:62:19
+   |
+LL |         ${count(i a b c)}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:62:19
+   |
+LL |         ${count(i a b c)}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:64:22
+   |
+LL |         ${count(i, 1 a b c)}
+   |                      ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:64:22
+   |
+LL |         ${count(i, 1 a b c)}
+   |                      ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:66:20
+   |
+LL |         ${count(i) a b c}
+   |                    ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:66:20
+   |
+LL |         ${count(i) a b c}
+   |                    ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:69:21
+   |
+LL |         ${ignore(i) a b c}
+   |                     ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:69:21
+   |
+LL |         ${ignore(i) a b c}
+   |                     ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:71:20
+   |
+LL |         ${ignore(i a b c)}
+   |                    ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:71:20
+   |
+LL |         ${ignore(i a b c)}
+   |                    ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:74:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:74:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:76:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:76:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:79:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:79:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:81:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:81:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+
+error: meta-variable expression depth must be a literal
+  --> $DIR/syntax-errors.rs:88:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ index(IDX) } };
+   |                                 ^^^^^
+
+error: unexpected token: {
+  --> $DIR/syntax-errors.rs:94:8
+   |
+LL |     ( ${ length() } ) => {
+   |        ^^^^^^^^^^^^
+
+note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
+  --> $DIR/syntax-errors.rs:94:8
+   |
+LL |     ( ${ length() } ) => {
+   |        ^^^^^^^^^^^^
+
+error: expected one of: `*`, `+`, or `?`
+  --> $DIR/syntax-errors.rs:94:8
+   |
+LL |     ( ${ length() } ) => {
+   |        ^^^^^^^^^^^^
+
+error: expected identifier
+  --> $DIR/syntax-errors.rs:101:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ ignore() } };
+   |                                 ^^^^^^
+
+error: only unsuffixes integer literals are supported in meta-variable expressions
+  --> $DIR/syntax-errors.rs:107:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ index(1u32) } };
+   |                                 ^^^^^
+
+error: meta-variable expression parameter must be wrapped in parentheses
+  --> $DIR/syntax-errors.rs:113:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ count{i} } };
+   |                                 ^^^^^
+
+error: expected identifier
+  --> $DIR/syntax-errors.rs:119:31
+   |
+LL |     ( $( $i:ident ),* ) => { ${ {} } };
+   |                               ^^^^^^
+
+error: unrecognized meta-variable expression
+  --> $DIR/syntax-errors.rs:125:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+   |                                 ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and length
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:16:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ count($i) } };
+   |                              ^ expected expression
+...
+LL |     curly__rhs_dollar__round!(a, b, c);
+   |     ---------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `curly__rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:22:23
+   |
+LL |     ( $i:ident ) => { ${ count($i) } };
+   |                       ^ expected expression
+...
+LL |     curly__rhs_dollar__no_round!(a);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `curly__rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: variable 'i' is still repeating at this depth
+  --> $DIR/syntax-errors.rs:40:36
+   |
+LL |     ( $( $i:ident ),* ) => { count($i) };
+   |                                    ^^
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:59:9
+   |
+LL |         ${count() a b c}
+   |         ^ expected expression
+...
+LL |     extra_garbage_after_metavar!(a);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `extra_garbage_after_metavar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:125:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+   |                              ^ expected expression
+...
+LL |     unknown_metavar!(a);
+   |     ------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `unknown_metavar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:113:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ count{i} } };
+   |                              ^ expected expression
+...
+LL |     metavar_without_parens!(a);
+   |     -------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `metavar_without_parens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:101:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ ignore() } };
+   |                              ^ expected expression
+...
+LL |     metavar_token_without_ident!(a);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `metavar_token_without_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:88:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ index(IDX) } };
+   |                              ^ expected expression
+...
+LL |     metavar_depth_is_not_literal!(a);
+   |     -------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `metavar_depth_is_not_literal` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:107:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ index(1u32) } };
+   |                              ^ expected expression
+...
+LL |     metavar_with_literal_suffix!(a);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `metavar_with_literal_suffix` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:119:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ {} } };
+   |                              ^ expected expression
+...
+LL |     open_brackets_without_tokens!(a)
+   |     -------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `open_brackets_without_tokens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+  --> $DIR/syntax-errors.rs:28:30
+   |
+LL |     ( $( $i:ident ),* ) => { count(i) };
+   |                              ^^^^^ not found in this scope
+...
+LL |     no_curly__no_rhs_dollar__round!(a, b, c);
+   |     ---------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `i` in this scope
+  --> $DIR/syntax-errors.rs:28:36
+   |
+LL |     ( $( $i:ident ),* ) => { count(i) };
+   |                                    ^ not found in this scope
+...
+LL |     no_curly__no_rhs_dollar__round!(a, b, c);
+   |     ---------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+  --> $DIR/syntax-errors.rs:34:23
+   |
+LL |     ( $i:ident ) => { count(i) };
+   |                       ^^^^^ not found in this scope
+...
+LL |     no_curly__no_rhs_dollar__no_round!(a);
+   |     ------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `i` in this scope
+  --> $DIR/syntax-errors.rs:34:29
+   |
+LL |     ( $i:ident ) => { count(i) };
+   |                             ^ not found in this scope
+...
+LL |     no_curly__no_rhs_dollar__no_round!(a);
+   |     ------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+  --> $DIR/syntax-errors.rs:45:23
+   |
+LL |     ( $i:ident ) => { count($i) };
+   |                       ^^^^^ not found in this scope
+...
+LL |     no_curly__rhs_dollar__no_round!(a);
+   |     ---------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/syntax-errors.rs:138:37
+   |
+LL |     no_curly__rhs_dollar__no_round!(a);
+   |                                     ^ not found in this scope
+
+error: aborting due to 37 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
index 5debfe1c566c4893f477988c03d7573eb2af6f71..6206dc85ea05f81c72ab6854ef03416a232cbcb5 100644 (file)
@@ -1,17 +1,19 @@
 error[E0004]: non-exhaustive patterns: `B` not covered
   --> $DIR/match_non_exhaustive.rs:23:11
    |
-LL | enum L { A, B }
-   | ---------------
-   | |           |
-   | |           not covered
-   | `L` defined here
-...
 LL |     match l { L::A => () };
    |           ^ pattern `B` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `L` defined here
+  --> $DIR/match_non_exhaustive.rs:10:13
+   |
+LL | enum L { A, B }
+   |      -      ^ not covered
    = note: the matched value is of type `L`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |     match l { L::A => (), B => todo!() };
+   |                         ++++++++++++++
 
 error[E0004]: non-exhaustive patterns: type `E1` is non-empty
   --> $DIR/match_non_exhaustive.rs:28:11
@@ -19,8 +21,18 @@ error[E0004]: non-exhaustive patterns: type `E1` is non-empty
 LL |     match e1 {};
    |           ^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E1` defined here
+  --> $DIR/auxiliary/match_non_exhaustive_lib.rs:2:1
+   |
+LL | pub enum E1 {}
+   | ^^^^^^^^^^^^^^
    = note: the matched value is of type `E1`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match e1 {
+LL +         _ => todo!(),
+LL ~     };
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/match_non_exhaustive.rs:30:11
@@ -28,8 +40,16 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match e2 { E2::A => (), E2::B => () };
    |           ^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E2` defined here
+  --> $DIR/auxiliary/match_non_exhaustive_lib.rs:5:1
+   |
+LL | pub enum E2 { A, B }
+   | ^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `E2`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |     match e2 { E2::A => (), E2::B => (), _ => todo!() };
+   |                                        ++++++++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/methods/issues/issue-94581.rs b/src/test/ui/methods/issues/issue-94581.rs
new file mode 100644 (file)
index 0000000..df393e9
--- /dev/null
@@ -0,0 +1,7 @@
+fn get_slice() -> &'static [i32] {
+    &[1, 2, 3, 4]
+}
+
+fn main() {
+    let sqsum = get_slice().map(|i| i * i).sum(); //~ ERROR [E0599]
+}
diff --git a/src/test/ui/methods/issues/issue-94581.stderr b/src/test/ui/methods/issues/issue-94581.stderr
new file mode 100644 (file)
index 0000000..d6be29c
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0599]: `&'static [i32]` is not an iterator
+  --> $DIR/issue-94581.rs:6:29
+   |
+LL |     let sqsum = get_slice().map(|i| i * i).sum();
+   |                             ^^^ `&'static [i32]` is not an iterator; try calling `.iter()`
+   |
+   = note: the following trait bounds were not satisfied:
+           `&'static [i32]: Iterator`
+           which is required by `&mut &'static [i32]: Iterator`
+           `[i32]: Iterator`
+           which is required by `&mut [i32]: Iterator`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
index 86d00ca37602615a84fc8645e031f93295ac7782..d53ef445afc1bcf06174bf700cb2098ae2a7ac31 100644 (file)
@@ -16,7 +16,7 @@ fn main() {
 
     let y = Foo;
     y.zero()
-     .take()    //~ ERROR the method
+     .take()    //~ ERROR not an iterator
      .one(0);
     y.three::<usize>(); //~ ERROR this function takes 3 arguments but 0 arguments were supplied
 }
index c1183e053eb43095a58050f9b37cbefbeb7fce67..c410e076dde2655babda04452050473b7cdc44d2 100644 (file)
@@ -40,7 +40,7 @@ note: associated function defined here
 LL |     fn two(self, _: isize, _: isize) -> Foo { self }
    |        ^^^ ----  --------  --------
 
-error[E0599]: the method `take` exists for struct `Foo`, but its trait bounds were not satisfied
+error[E0599]: `Foo` is not an iterator
   --> $DIR/method-call-err-msg.rs:19:7
    |
 LL | pub struct Foo;
@@ -50,7 +50,7 @@ LL | pub struct Foo;
    | doesn't satisfy `Foo: Iterator`
 ...
 LL |      .take()
-   |       ^^^^ method cannot be called on `Foo` due to unsatisfied trait bounds
+   |       ^^^^ `Foo` is not an iterator
    |
    = note: the following trait bounds were not satisfied:
            `Foo: Iterator`
index b8d12fb9809ced8af56340cc997e3c8af0acf420..57222f45947b41d8e9d8dea3f3fb863d750f98ac 100644 (file)
@@ -48,7 +48,7 @@ fn main()
     let _ = E::A as *const u8; //~ ERROR is invalid
     let _ = 'a' as *const u8; //~ ERROR is invalid
 
-    let _ = 42usize as *const [u8]; //~ ERROR is invalid
+    let _ = 42usize as *const [u8]; //~ ERROR cannot cast `usize` to a pointer that is wide
     let _ = v as *const [u8]; //~ ERROR cannot cast
     let _ = fat_v as *const dyn Foo; //~ ERROR the size for values of type
     let _ = foo as *const str; //~ ERROR is invalid
index 6dbf24baf2315d8c05d7a3481fb96107b8062d0e..5f11e4ded8004e9b9552e0dc8bb9d39692c5a254 100644 (file)
@@ -148,11 +148,13 @@ error[E0606]: casting `char` as `*const u8` is invalid
 LL |     let _ = 'a' as *const u8;
    |             ^^^^^^^^^^^^^^^^
 
-error[E0606]: casting `usize` as `*const [u8]` is invalid
-  --> $DIR/cast-rfc0401.rs:51:13
+error[E0606]: cannot cast `usize` to a pointer that is wide
+  --> $DIR/cast-rfc0401.rs:51:24
    |
 LL |     let _ = 42usize as *const [u8];
-   |             ^^^^^^^^^^^^^^^^^^^^^^
+   |             -------    ^^^^^^^^^^^ creating a `*const [u8]` requires both an address and a length
+   |             |
+   |             consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
 
 error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
   --> $DIR/cast-rfc0401.rs:52:13
index 17d2292baaf683298c17e48edb0474e1b311f438..0252ba2eb04606e860492fec1757de88a3015de4 100644 (file)
@@ -5,6 +5,6 @@
 use std::iter::once;
 fn main() {
     once::<&str>("str").fuse().filter(|a: &str| true).count();
-    //~^ ERROR the method
+    //~^ ERROR not an iterator
     //~| ERROR type mismatch in closure arguments
 }
index a8bcdf5efe91e30214a5f24f844e1d80dfd2f79a..b1010171eb23560fee29e2c705c15b8a6b55f736 100644 (file)
@@ -12,11 +12,11 @@ note: required by a bound in `filter`
 LL |         P: FnMut(&Self::Item) -> bool,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `filter`
 
-error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>`, but its trait bounds were not satisfied
+error[E0599]: `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` is not an iterator
   --> $DIR/issue-36053-2.rs:7:55
    |
 LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
-   |                                       --------------  ^^^^^ method cannot be called on `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` due to unsatisfied trait bounds
+   |                                       --------------  ^^^^^ `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` is not an iterator
    |                                       |
    |                                       doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool`
    |                                       doesn't satisfy `_: FnMut<(&&str,)>`
index db4c3979e3ad694a90ec6c31b2ec5f79b986b5ce..baa87e3e9fdb2111f386b81cfa0ba958d7bb4d80 100644 (file)
@@ -4,10 +4,7 @@ error[E0382]: use of moved value: `b`
 LL |     let b = Box::new(true);
    |         - move occurs because `b` has type `Box<bool>`, which does not implement the `Copy` trait
 LL |     test!({b});
-   |            ^
-   |            |
-   |            value moved here
-   |            value used here after move
+   |            ^ value used here after move
 
 error: aborting due to previous error
 
index 57be5fb4d8a59160181fa33d80b780215bc14049..3a686121a9283c802073af9bd935eab1e72c76db 100644 (file)
@@ -119,12 +119,14 @@ error[E0382]: use of moved value: `implicit_into_iter`
 LL |     let implicit_into_iter = vec![true];
    |         ------------------ move occurs because `implicit_into_iter` has type `Vec<bool>`, which does not implement the `Copy` trait
 LL |     for _val in implicit_into_iter {}
-   |                 ------------------
-   |                 |
-   |                 `implicit_into_iter` moved due to this implicit call to `.into_iter()`
-   |                 help: consider borrowing to avoid moving into the for loop: `&implicit_into_iter`
+   |                 ------------------ `implicit_into_iter` moved due to this implicit call to `.into_iter()`
 LL |     implicit_into_iter;
    |     ^^^^^^^^^^^^^^^^^^ value used here after move
+   |
+help: consider iterating over a slice of the `Vec<bool>`'s content to avoid moving into the `for` loop
+   |
+LL |     for _val in &implicit_into_iter {}
+   |                 +
 
 error[E0382]: use of moved value: `explicit_into_iter`
   --> $DIR/move-fn-self-receiver.rs:67:5
index ea350926b1519f77a1264274880d4dda57509274..8d636c11b78c7bd25500a5dfa364b9c6a4aaea2b 100644 (file)
@@ -5,10 +5,7 @@ LL |     let x: Box<_> = Box::new(1);
    |         - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
 ...
 LL |         (_, 2) if take(x) => (),
-   |                        ^
-   |                        |
-   |                        value moved here
-   |                        value used here after move
+   |                        ^ value used here after move
 
 error: aborting due to previous error
 
index c9efccd15b7c5016a44e19abb2b680f1fb2fe18b..17c4a0496b6d882af86867574e33f5a8b43befbf 100644 (file)
@@ -1,8 +1,10 @@
 // Regression test for issue #55825
 // Tests that we don't emit a spurious warning in NLL mode
 
+// check-pass
+
 #![feature(nll)]
 
-const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~ ERROR const
+const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
 
 fn main() { }
diff --git a/src/test/ui/nll/issue-55825-const-fn.stderr b/src/test/ui/nll/issue-55825-const-fn.stderr
deleted file mode 100644 (file)
index c834f8b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: trait objects in const fn are unstable
-  --> $DIR/issue-55825-const-fn.rs:6:32
-   |
-LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
-   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/nll/lint-no-err.rs b/src/test/ui/nll/lint-no-err.rs
new file mode 100644 (file)
index 0000000..4b4169f
--- /dev/null
@@ -0,0 +1,28 @@
+// check-pass
+
+// mir borrowck previously incorrectly set `tainted_by_errors`
+// when buffering lints, which resulted in ICE later on,
+// see #94502.
+
+// Errors with `nll` which is already tested in enough other tests,
+// so we ignore it here.
+//
+// ignore-compare-mode-nll
+
+struct Repro;
+impl Repro {
+    fn get(&self) -> &i32 {
+        &3
+    }
+
+    fn insert(&mut self, _: i32) {}
+}
+
+fn main() {
+    let x = &0;
+    let mut conflict = Repro;
+    let prev = conflict.get();
+    conflict.insert(*prev + *x);
+    //~^ WARN cannot borrow `conflict` as mutable because it is also borrowed as immutable
+    //~| WARN this borrowing pattern was not meant to be accepted
+}
diff --git a/src/test/ui/nll/lint-no-err.stderr b/src/test/ui/nll/lint-no-err.stderr
new file mode 100644 (file)
index 0000000..1e7aecf
--- /dev/null
@@ -0,0 +1,17 @@
+warning: cannot borrow `conflict` as mutable because it is also borrowed as immutable
+  --> $DIR/lint-no-err.rs:25:5
+   |
+LL |     let prev = conflict.get();
+   |                -------------- immutable borrow occurs here
+LL |     conflict.insert(*prev + *x);
+   |     ^^^^^^^^^^^^^^^^-----^^^^^^
+   |     |               |
+   |     |               immutable borrow later used here
+   |     mutable borrow occurs here
+   |
+   = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
+   = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
+   = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
+
+warning: 1 warning emitted
+
index df6d65056acd2c8870b6731b7f6c05b8d26abcf4..c0fb5f65382dce4eccdd3be95cecabd71085d28b 100644 (file)
@@ -2,10 +2,8 @@ error[E0507]: cannot move out of `foo` in pattern guard
   --> $DIR/match-guards-always-borrow.rs:8:14
    |
 LL |             (|| { let bar = foo; bar.take() })();
-   |              ^^             ---
-   |              |              |
-   |              |              move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
-   |              |              move occurs due to use in closure
+   |              ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |              |
    |              move out of `foo` occurs here
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
diff --git a/src/test/ui/on-unimplemented/impl-substs.rs b/src/test/ui/on-unimplemented/impl-substs.rs
new file mode 100644 (file)
index 0000000..fe9c50e
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(rustc_attrs)]
+
+trait Foo<A> {
+    fn foo(self);
+}
+
+#[rustc_on_unimplemented = "an impl did not match: {A} {B} {C}"]
+impl<A, B, C> Foo<A> for (A, B, C) {
+    fn foo(self) {}
+}
+
+fn main() {
+    Foo::<usize>::foo((1i32, 1i32, 1i32));
+    //~^ ERROR the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied
+}
diff --git a/src/test/ui/on-unimplemented/impl-substs.stderr b/src/test/ui/on-unimplemented/impl-substs.stderr
new file mode 100644 (file)
index 0000000..db66ab0
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0277]: the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied
+  --> $DIR/impl-substs.rs:13:23
+   |
+LL |     Foo::<usize>::foo((1i32, 1i32, 1i32));
+   |     ----------------- ^^^^^^^^^^^^^^^^^^ an impl did not match: usize _ _
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Foo<usize>` is not implemented for `(i32, i32, i32)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 44f334eee9386cf99d12306e276f32c53a10526c..9aa808e6bc9a69db9b07d19d49e945961335ce92 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(2_u8..=u8::MAX, _)` not covered
 LL |     match (0u8, 0u8) {
    |           ^^^^^^^^^^ pattern `(2_u8..=u8::MAX, _)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(u8, u8)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         (0 | 1, 2 | 3) => {}
+LL +         (2_u8..=u8::MAX, _) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered
   --> $DIR/exhaustiveness-non-exhaustive.rs:9:11
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered
 LL |     match ((0u8,),) {
    |           ^^^^^^^^^ pattern `((4_u8..=u8::MAX))` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `((u8,),)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         ((0 | 1,) | (2 | 3,),) => {}
+LL +         ((4_u8..=u8::MAX)) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered
   --> $DIR/exhaustiveness-non-exhaustive.rs:13:11
@@ -22,8 +30,12 @@ error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered
 LL |     match (Some(0u8),) {
    |           ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Option<u8>,)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         (None | Some(0 | 1),) => {}
+LL +         (Some(2_u8..=u8::MAX)) => todo!()
+   |
 
 error: aborting due to 3 previous errors
 
index 8e6964e30623ddbe9932faf75e5668c72b17bfde..95b22ac059482fa52a97051b5ca6050321410f74 100644 (file)
@@ -7,10 +7,10 @@ LL |     let (0 | (1 | 2)) = 0;
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let (0 | (1 | 2)) = 0 { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     if let (0 | (1 | 2)) = 0 { todo!() }
+   |     ++                       ~~~~~~~~~~~
 
 error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
   --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:3:11
@@ -18,8 +18,12 @@ error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX
 LL |     match 0 {
    |           ^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         0 | (1 | 2) => {}
+LL +         i32::MIN..=-1_i32 | 3_i32..=i32::MAX => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
index 2ca774a48b66b73339ca92b4260f8c627334d6ae..cd5c283f9fd93c75c4d551c900317d2b29ecfde0 100644 (file)
@@ -4,23 +4,33 @@ error[E0004]: non-exhaustive patterns: type `&!` is non-empty
 LL |     match uninhab_ref() {
    |           ^^^^^^^^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&!`
    = note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match uninhab_ref() {
+LL +         _ => todo!(),
+LL +     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
   --> $DIR/always-inhabited-union-ref.rs:27:11
    |
-LL | / pub union Foo {
-LL | |     foo: !,
-LL | | }
-   | |_- `Foo` defined here
-...
-LL |       match uninhab_union() {
-   |             ^^^^^^^^^^^^^^^
+LL |     match uninhab_union() {
+   |           ^^^^^^^^^^^^^^^
+   |
+note: `Foo` defined here
+  --> $DIR/always-inhabited-union-ref.rs:10:11
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | pub union Foo {
+   |           ^^^
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match uninhab_union() {
+LL +         _ => todo!(),
+LL +     }
+   |
 
 error: aborting due to 2 previous errors
 
index 6c9539822b3dd6de105fb42ec08fa81a134e3339..7d0b71a497ec2f91f0fb290bf18f9f74a77cb900 100644 (file)
@@ -4,8 +4,22 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match Foo::A {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+  --> $DIR/auxiliary/hidden.rs:1:1
+   |
+LL | / pub enum Foo {
+LL | |     A,
+LL | |     B,
+LL | |     #[doc(hidden)]
+LL | |     C,
+LL | | }
+   | |_^
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo::B => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `B` not covered
   --> $DIR/doc-hidden-non-exhaustive.rs:14:11
@@ -13,13 +27,23 @@ error[E0004]: non-exhaustive patterns: `B` not covered
 LL |     match Foo::A {
    |           ^^^^^^ pattern `B` not covered
    |
-  ::: $DIR/auxiliary/hidden.rs:3:5
+note: `Foo` defined here
+  --> $DIR/auxiliary/hidden.rs:3:5
    |
-LL |     B,
-   |     - not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Foo {
+LL | |     A,
+LL | |     B,
+   | |     ^ not covered
+LL | |     #[doc(hidden)]
+LL | |     C,
+LL | | }
+   | |_-
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo::C => {}
+LL +         B => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `B` and `_` not covered
   --> $DIR/doc-hidden-non-exhaustive.rs:20:11
@@ -27,13 +51,23 @@ error[E0004]: non-exhaustive patterns: `B` and `_` not covered
 LL |     match Foo::A {
    |           ^^^^^^ patterns `B` and `_` not covered
    |
-  ::: $DIR/auxiliary/hidden.rs:3:5
+note: `Foo` defined here
+  --> $DIR/auxiliary/hidden.rs:3:5
    |
-LL |     B,
-   |     - not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Foo {
+LL | |     A,
+LL | |     B,
+   | |     ^ not covered
+LL | |     #[doc(hidden)]
+LL | |     C,
+LL | | }
+   | |_-
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         Foo::A => {}
+LL +         B | _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Some(B)` and `Some(_)` not covered
   --> $DIR/doc-hidden-non-exhaustive.rs:25:11
@@ -41,13 +75,24 @@ error[E0004]: non-exhaustive patterns: `Some(B)` and `Some(_)` not covered
 LL |     match None {
    |           ^^^^ patterns `Some(B)` and `Some(_)` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<Foo>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
    |
-LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     ---- not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   | |     ^^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `Option<Foo>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         Some(Foo::A) => {}
+LL +         Some(B) | Some(_) => todo!()
+   |
 
 error: aborting due to 4 previous errors
 
index b99386e74020e8da394e86cf987b490000c32ffe..d31ee0dbd14e5a032c8327c20a244021f269b4a2 100644 (file)
@@ -46,107 +46,112 @@ error[E0004]: non-exhaustive patterns: type `u8` is non-empty
 LL |     match_no_arms!(0u8);
    |                    ^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
   --> $DIR/empty-match.rs:79:20
    |
-LL | struct NonEmptyStruct1;
-   | ----------------------- `NonEmptyStruct1` defined here
-...
 LL |     match_no_arms!(NonEmptyStruct1);
    |                    ^^^^^^^^^^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+  --> $DIR/empty-match.rs:14:8
+   |
+LL | struct NonEmptyStruct1;
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct1`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
   --> $DIR/empty-match.rs:80:20
    |
-LL | struct NonEmptyStruct2(bool);
-   | ----------------------------- `NonEmptyStruct2` defined here
-...
 LL |     match_no_arms!(NonEmptyStruct2(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+  --> $DIR/empty-match.rs:15:8
+   |
+LL | struct NonEmptyStruct2(bool);
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct2`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
   --> $DIR/empty-match.rs:81:20
    |
-LL | / union NonEmptyUnion1 {
-LL | |     foo: (),
-LL | | }
-   | |_- `NonEmptyUnion1` defined here
-...
-LL |       match_no_arms!((NonEmptyUnion1 { foo: () }));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     match_no_arms!((NonEmptyUnion1 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `NonEmptyUnion1` defined here
+  --> $DIR/empty-match.rs:16:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion1`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
   --> $DIR/empty-match.rs:82:20
    |
-LL | / union NonEmptyUnion2 {
-LL | |     foo: (),
-LL | |     bar: (),
-LL | | }
-   | |_- `NonEmptyUnion2` defined here
-...
-LL |       match_no_arms!((NonEmptyUnion2 { foo: () }));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     match_no_arms!((NonEmptyUnion2 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `NonEmptyUnion2` defined here
+  --> $DIR/empty-match.rs:19:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion2`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
   --> $DIR/empty-match.rs:83:20
    |
-LL | / enum NonEmptyEnum1 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum1` defined here
-...
-LL |       match_no_arms!(NonEmptyEnum1::Foo(true));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL |     match_no_arms!(NonEmptyEnum1::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+  --> $DIR/empty-match.rs:24:5
+   |
+LL | enum NonEmptyEnum1 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum1`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
   --> $DIR/empty-match.rs:84:20
    |
-LL | / enum NonEmptyEnum2 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |     Bar,
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum2` defined here
-...
-LL |       match_no_arms!(NonEmptyEnum2::Foo(true));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match_no_arms!(NonEmptyEnum2::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+note: `NonEmptyEnum2` defined here
+  --> $DIR/empty-match.rs:27:5
+   |
+LL | enum NonEmptyEnum2 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
+LL |     Bar,
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum2`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
   --> $DIR/empty-match.rs:85:20
    |
-LL | / enum NonEmptyEnum5 {
-LL | |     V1, V2, V3, V4, V5,
-LL | | }
-   | |_- `NonEmptyEnum5` defined here
-...
-LL |       match_no_arms!(NonEmptyEnum5::V1);
-   |                      ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL |     match_no_arms!(NonEmptyEnum5::V1);
+   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+note: `NonEmptyEnum5` defined here
+  --> $DIR/empty-match.rs:30:6
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+   |      ^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyEnum5`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/empty-match.rs:87:24
@@ -154,107 +159,144 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match_guarded_arm!(0u8);
    |                        ^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
   --> $DIR/empty-match.rs:88:24
    |
-LL | struct NonEmptyStruct1;
-   | ----------------------- `NonEmptyStruct1` defined here
-...
 LL |     match_guarded_arm!(NonEmptyStruct1);
    |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+  --> $DIR/empty-match.rs:14:8
+   |
+LL | struct NonEmptyStruct1;
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyStruct1 => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
   --> $DIR/empty-match.rs:89:24
    |
-LL | struct NonEmptyStruct2(bool);
-   | ----------------------------- `NonEmptyStruct2` defined here
-...
 LL |     match_guarded_arm!(NonEmptyStruct2(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+  --> $DIR/empty-match.rs:15:8
+   |
+LL | struct NonEmptyStruct2(bool);
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyStruct2(_) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
   --> $DIR/empty-match.rs:90:24
    |
-LL | / union NonEmptyUnion1 {
-LL | |     foo: (),
-LL | | }
-   | |_- `NonEmptyUnion1` defined here
-...
-LL |       match_guarded_arm!((NonEmptyUnion1 { foo: () }));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+LL |     match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+   |
+note: `NonEmptyUnion1` defined here
+  --> $DIR/empty-match.rs:16:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyUnion1 { .. } => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
   --> $DIR/empty-match.rs:91:24
    |
-LL | / union NonEmptyUnion2 {
-LL | |     foo: (),
-LL | |     bar: (),
-LL | | }
-   | |_- `NonEmptyUnion2` defined here
-...
-LL |       match_guarded_arm!((NonEmptyUnion2 { foo: () }));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+LL |     match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+   |
+note: `NonEmptyUnion2` defined here
+  --> $DIR/empty-match.rs:19:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyUnion2 { .. } => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
   --> $DIR/empty-match.rs:92:24
    |
-LL | / enum NonEmptyEnum1 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum1` defined here
-...
-LL |       match_guarded_arm!(NonEmptyEnum1::Foo(true));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL |     match_guarded_arm!(NonEmptyEnum1::Foo(true));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+  --> $DIR/empty-match.rs:24:5
+   |
+LL | enum NonEmptyEnum1 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             Foo(_) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
   --> $DIR/empty-match.rs:93:24
    |
-LL | / enum NonEmptyEnum2 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |     Bar,
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum2` defined here
-...
-LL |       match_guarded_arm!(NonEmptyEnum2::Foo(true));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match_guarded_arm!(NonEmptyEnum2::Foo(true));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+note: `NonEmptyEnum2` defined here
+  --> $DIR/empty-match.rs:27:5
+   |
+LL | enum NonEmptyEnum2 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
+LL |     Bar,
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~             _ if false => {}
+LL +             Foo(_) | Bar => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
   --> $DIR/empty-match.rs:94:24
    |
-LL | / enum NonEmptyEnum5 {
-LL | |     V1, V2, V3, V4, V5,
-LL | | }
-   | |_- `NonEmptyEnum5` defined here
-...
-LL |       match_guarded_arm!(NonEmptyEnum5::V1);
-   |                          ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL |     match_guarded_arm!(NonEmptyEnum5::V1);
+   |                        ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+note: `NonEmptyEnum5` defined here
+  --> $DIR/empty-match.rs:30:6
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+   |      ^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyEnum5`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~             _ if false => {}
+LL +             _ => todo!()
+   |
 
 error: aborting due to 22 previous errors
 
index b99386e74020e8da394e86cf987b490000c32ffe..d31ee0dbd14e5a032c8327c20a244021f269b4a2 100644 (file)
@@ -46,107 +46,112 @@ error[E0004]: non-exhaustive patterns: type `u8` is non-empty
 LL |     match_no_arms!(0u8);
    |                    ^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
   --> $DIR/empty-match.rs:79:20
    |
-LL | struct NonEmptyStruct1;
-   | ----------------------- `NonEmptyStruct1` defined here
-...
 LL |     match_no_arms!(NonEmptyStruct1);
    |                    ^^^^^^^^^^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+  --> $DIR/empty-match.rs:14:8
+   |
+LL | struct NonEmptyStruct1;
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct1`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
   --> $DIR/empty-match.rs:80:20
    |
-LL | struct NonEmptyStruct2(bool);
-   | ----------------------------- `NonEmptyStruct2` defined here
-...
 LL |     match_no_arms!(NonEmptyStruct2(true));
    |                    ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+  --> $DIR/empty-match.rs:15:8
+   |
+LL | struct NonEmptyStruct2(bool);
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct2`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
   --> $DIR/empty-match.rs:81:20
    |
-LL | / union NonEmptyUnion1 {
-LL | |     foo: (),
-LL | | }
-   | |_- `NonEmptyUnion1` defined here
-...
-LL |       match_no_arms!((NonEmptyUnion1 { foo: () }));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     match_no_arms!((NonEmptyUnion1 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `NonEmptyUnion1` defined here
+  --> $DIR/empty-match.rs:16:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion1`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
   --> $DIR/empty-match.rs:82:20
    |
-LL | / union NonEmptyUnion2 {
-LL | |     foo: (),
-LL | |     bar: (),
-LL | | }
-   | |_- `NonEmptyUnion2` defined here
-...
-LL |       match_no_arms!((NonEmptyUnion2 { foo: () }));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     match_no_arms!((NonEmptyUnion2 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `NonEmptyUnion2` defined here
+  --> $DIR/empty-match.rs:19:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion2`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
   --> $DIR/empty-match.rs:83:20
    |
-LL | / enum NonEmptyEnum1 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum1` defined here
-...
-LL |       match_no_arms!(NonEmptyEnum1::Foo(true));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL |     match_no_arms!(NonEmptyEnum1::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+  --> $DIR/empty-match.rs:24:5
+   |
+LL | enum NonEmptyEnum1 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum1`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
   --> $DIR/empty-match.rs:84:20
    |
-LL | / enum NonEmptyEnum2 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |     Bar,
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum2` defined here
-...
-LL |       match_no_arms!(NonEmptyEnum2::Foo(true));
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match_no_arms!(NonEmptyEnum2::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+note: `NonEmptyEnum2` defined here
+  --> $DIR/empty-match.rs:27:5
+   |
+LL | enum NonEmptyEnum2 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
+LL |     Bar,
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum2`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
   --> $DIR/empty-match.rs:85:20
    |
-LL | / enum NonEmptyEnum5 {
-LL | |     V1, V2, V3, V4, V5,
-LL | | }
-   | |_- `NonEmptyEnum5` defined here
-...
-LL |       match_no_arms!(NonEmptyEnum5::V1);
-   |                      ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL |     match_no_arms!(NonEmptyEnum5::V1);
+   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+note: `NonEmptyEnum5` defined here
+  --> $DIR/empty-match.rs:30:6
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+   |      ^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyEnum5`
+   = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/empty-match.rs:87:24
@@ -154,107 +159,144 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match_guarded_arm!(0u8);
    |                        ^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
   --> $DIR/empty-match.rs:88:24
    |
-LL | struct NonEmptyStruct1;
-   | ----------------------- `NonEmptyStruct1` defined here
-...
 LL |     match_guarded_arm!(NonEmptyStruct1);
    |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+  --> $DIR/empty-match.rs:14:8
+   |
+LL | struct NonEmptyStruct1;
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyStruct1 => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
   --> $DIR/empty-match.rs:89:24
    |
-LL | struct NonEmptyStruct2(bool);
-   | ----------------------------- `NonEmptyStruct2` defined here
-...
 LL |     match_guarded_arm!(NonEmptyStruct2(true));
    |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+  --> $DIR/empty-match.rs:15:8
+   |
+LL | struct NonEmptyStruct2(bool);
+   |        ^^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyStruct2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyStruct2(_) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
   --> $DIR/empty-match.rs:90:24
    |
-LL | / union NonEmptyUnion1 {
-LL | |     foo: (),
-LL | | }
-   | |_- `NonEmptyUnion1` defined here
-...
-LL |       match_guarded_arm!((NonEmptyUnion1 { foo: () }));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+LL |     match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+   |
+note: `NonEmptyUnion1` defined here
+  --> $DIR/empty-match.rs:16:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyUnion1 { .. } => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
   --> $DIR/empty-match.rs:91:24
    |
-LL | / union NonEmptyUnion2 {
-LL | |     foo: (),
-LL | |     bar: (),
-LL | | }
-   | |_- `NonEmptyUnion2` defined here
-...
-LL |       match_guarded_arm!((NonEmptyUnion2 { foo: () }));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+LL |     match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+   |
+note: `NonEmptyUnion2` defined here
+  --> $DIR/empty-match.rs:19:7
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+   |       ^^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyUnion2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             NonEmptyUnion2 { .. } => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
   --> $DIR/empty-match.rs:92:24
    |
-LL | / enum NonEmptyEnum1 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum1` defined here
-...
-LL |       match_guarded_arm!(NonEmptyEnum1::Foo(true));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL |     match_guarded_arm!(NonEmptyEnum1::Foo(true));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+  --> $DIR/empty-match.rs:24:5
+   |
+LL | enum NonEmptyEnum1 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             _ if false => {}
+LL +             Foo(_) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
   --> $DIR/empty-match.rs:93:24
    |
-LL | / enum NonEmptyEnum2 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |     Bar,
-   | |     --- not covered
-LL | | }
-   | |_- `NonEmptyEnum2` defined here
-...
-LL |       match_guarded_arm!(NonEmptyEnum2::Foo(true));
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match_guarded_arm!(NonEmptyEnum2::Foo(true));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+note: `NonEmptyEnum2` defined here
+  --> $DIR/empty-match.rs:27:5
+   |
+LL | enum NonEmptyEnum2 {
+   |      -------------
+LL |     Foo(bool),
+   |     ^^^ not covered
+LL |     Bar,
+   |     ^^^ not covered
    = note: the matched value is of type `NonEmptyEnum2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~             _ if false => {}
+LL +             Foo(_) | Bar => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
   --> $DIR/empty-match.rs:94:24
    |
-LL | / enum NonEmptyEnum5 {
-LL | |     V1, V2, V3, V4, V5,
-LL | | }
-   | |_- `NonEmptyEnum5` defined here
-...
-LL |       match_guarded_arm!(NonEmptyEnum5::V1);
-   |                          ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL |     match_guarded_arm!(NonEmptyEnum5::V1);
+   |                        ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+note: `NonEmptyEnum5` defined here
+  --> $DIR/empty-match.rs:30:6
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+   |      ^^^^^^^^^^^^^
    = note: the matched value is of type `NonEmptyEnum5`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~             _ if false => {}
+LL +             _ => todo!()
+   |
 
 error: aborting due to 22 previous errors
 
index 464bfbdb2c3b2a864d72c0ed341b097ef6cd9d7c..c926e50b3580bd58d0b003d833588687e0c05dd8 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0.0 {
    |           ^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `f64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~       0.0..=1.0 => {}
+LL +       _ => todo!()
+   |
 
 error: unreachable pattern
   --> $DIR/floats.rs:16:7
index 61f7facb330da959681c000eb5bd0f0600ad0352..0c1563c160c1c092928918ed492b2b5e358a468b 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered
 LL |     match 0u8 {
    |           ^^^ pattern `128_u8..=u8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         128 ..= 255 if true => {}
+LL +         128_u8..=u8::MAX => todo!()
+   |
 
 error: aborting due to previous error
 
index 2e0023348e4d837f526c7c81018f7d484b3335a5..fec54e89d63cf091f175dd0ea06581584e6bced9 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
 LL |     m!(0u8, 0..255);
    |        ^^^ pattern `u8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
   --> $DIR/exhaustiveness.rs:48:8
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
 LL |     m!(0u8, 0..=254);
    |        ^^^ pattern `u8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u8` not covered
   --> $DIR/exhaustiveness.rs:49:8
@@ -22,8 +30,12 @@ error[E0004]: non-exhaustive patterns: `0_u8` not covered
 LL |     m!(0u8, 1..=255);
    |        ^^^ pattern `0_u8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `42_u8` not covered
   --> $DIR/exhaustiveness.rs:50:8
@@ -31,8 +43,12 @@ error[E0004]: non-exhaustive patterns: `42_u8` not covered
 LL |     m!(0u8, 0..42 | 43..=255);
    |        ^^^ pattern `42_u8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         42_u8 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
   --> $DIR/exhaustiveness.rs:51:8
@@ -40,8 +56,12 @@ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
 LL |     m!(0i8, -128..127);
    |        ^^^ pattern `i8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
   --> $DIR/exhaustiveness.rs:52:8
@@ -49,8 +69,12 @@ error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
 LL |     m!(0i8, -128..=126);
    |        ^^^ pattern `i8::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i8::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
   --> $DIR/exhaustiveness.rs:53:8
@@ -58,8 +82,12 @@ error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
 LL |     m!(0i8, -127..=127);
    |        ^^^ pattern `i8::MIN` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         i8::MIN => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_i8` not covered
   --> $DIR/exhaustiveness.rs:54:11
@@ -67,8 +95,12 @@ error[E0004]: non-exhaustive patterns: `0_i8` not covered
 LL |     match 0i8 {
    |           ^^^ pattern `0_i8` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         1 ..= i8::MAX => {}
+LL +         0_i8 => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
   --> $DIR/exhaustiveness.rs:59:8
@@ -76,8 +108,12 @@ error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
 LL |     m!(0u128, 0..=ALMOST_MAX);
    |        ^^^^^ pattern `u128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         u128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
   --> $DIR/exhaustiveness.rs:60:8
@@ -85,8 +121,12 @@ error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
 LL |     m!(0u128, 0..=4);
    |        ^^^^^ pattern `5_u128..=u128::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         5_u128..=u128::MAX => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `0_u128` not covered
   --> $DIR/exhaustiveness.rs:61:8
@@ -94,8 +134,12 @@ error[E0004]: non-exhaustive patterns: `0_u128` not covered
 LL |     m!(0u128, 1..=u128::MAX);
    |        ^^^^^ pattern `0_u128` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         0_u128 => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
   --> $DIR/exhaustiveness.rs:69:11
@@ -103,8 +147,12 @@ error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
 LL |     match (0u8, true) {
    |           ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(u8, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         (0 ..= 255, true) => {}
+LL +         (126_u8..=127_u8, false) => todo!()
+   |
 
 error: aborting due to 12 previous errors
 
index 2563293458379588806282642f8ba03488a4b968..9f277fa1e1800a1cf3da3cf816f2bd79b3419dd2 100644 (file)
@@ -4,8 +4,13 @@ error[E0004]: non-exhaustive patterns: type `usize` is non-empty
 LL |     match 7usize {}
    |           ^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match 7usize {
+LL +         _ => todo!(),
+LL +     }
+   |
 
 error: aborting due to previous error
 
index e8ac9f3cfe15633697828c909169053894fd1950..fa4146a7ad892268d13713830f79cabd45d42d95 100644 (file)
@@ -4,10 +4,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0usize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
    = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         0 ..= usize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:17:11
@@ -15,10 +19,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0isize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         isize::MIN ..= isize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:22:8
@@ -26,10 +34,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0usize, 0..=usize::MAX);
    |        ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
    = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:24:8
@@ -37,10 +49,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0usize, 0..5 | 5..=usize::MAX);
    |        ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
    = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:26:8
@@ -48,10 +64,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0usize, 0..usize::MAX | usize::MAX);
    |        ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
    = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `(_, _)` not covered
   --> $DIR/pointer-sized-int.rs:28:8
@@ -59,8 +79,12 @@ error[E0004]: non-exhaustive patterns: `(_, _)` not covered
 LL |     m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
    |        ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(usize, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         (_, _) => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:31:8
@@ -68,10 +92,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0isize, isize::MIN..=isize::MAX);
    |        ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:33:8
@@ -79,10 +107,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0isize, isize::MIN..5 | 5..=isize::MAX);
    |        ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:35:8
@@ -90,10 +122,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     m!(0isize, isize::MIN..isize::MAX | isize::MAX);
    |        ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         _ => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `(_, _)` not covered
   --> $DIR/pointer-sized-int.rs:37:8
@@ -101,8 +137,12 @@ error[E0004]: non-exhaustive patterns: `(_, _)` not covered
 LL |     m!((0isize, true), (isize::MIN..5, true)
    |        ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(isize, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         match $s { $($t)+ => {}
+LL ~         (_, _) => todo!() }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/pointer-sized-int.rs:41:11
@@ -110,10 +150,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0isize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         1 ..= isize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: type `usize` is non-empty
   --> $DIR/pointer-sized-int.rs:48:11
@@ -121,8 +165,13 @@ error[E0004]: non-exhaustive patterns: type `usize` is non-empty
 LL |     match 7usize {}
    |           ^^^^^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match 7usize {
+LL +         _ => todo!(),
+LL +     }
+   |
 
 error: aborting due to 12 previous errors
 
index 37e73a68f22bb005a707afcba4f4dae662687abd..30492c98206c90729923710f265f482976963a5c 100644 (file)
@@ -4,10 +4,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0usize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
    = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         0..=usize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/precise_pointer_matching-message.rs:11:11
@@ -15,10 +19,14 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0isize {
    |           ^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
    = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
    = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         isize::MIN..=isize::MAX => {}
+LL +         _ => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
index 79a77240937ac7803fe7096ed662a099d70ee1bf..af60f3ff50bf37583622e13c2b3472b8e3155f91 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` n
 LL |     match (T::T1(()), V::V2(true)) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(T, V)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         (T::T2(()), V::V2(b)) => (),
+LL ~         (T1(()), V2(_)) | (T2(()), V1(_)) => todo!(),
+   |
 
 error: aborting due to previous error
 
index 60d9b8514b7fbfe9115b84a0e56611b19af8a516..01890b73cbdd8a77875e2f677b976717f880197c 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(None, None)` and `(Some(_), Some(_))` n
 LL |     match (a, b) {
    |           ^^^^^^ patterns `(None, None)` and `(Some(_), Some(_))` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Option<usize>, Option<usize>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         (Some(_), None) | (None, Some(_)) => {}
+LL +         (None, None) | (Some(_), Some(_)) => todo!()
+   |
 
 error: aborting due to previous error
 
index a2c58d6e051b54214ddd332fa42edf8feca04d2e..759fdeafe4eb545202f947b8e7e78d3a7bf61f64 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `&_` not covered
 LL |     match "world" {
    |           ^^^^^^^ pattern `&_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&str`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         "hello" => {}
+LL +         &_ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&_` not covered
   --> $DIR/issue-30240.rs:6:11
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `&_` not covered
 LL |     match "world" {
    |           ^^^^^^^ pattern `&_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&str`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         "hello" => {}
+LL +         &_ => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
index 97c34755189de9115a62fcaad0267619ae3d06fb..d8884394f8e9619a0b501090c18a7ea865cc48a5 100644 (file)
@@ -4,8 +4,13 @@ error[E0004]: non-exhaustive patterns: type `()` is non-empty
 LL |     match () { }
    |           ^^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `()`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match () {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error: aborting due to previous error
 
index 472d1a91e6a15835c94e5b936c43119ed0543c84..2df8911badcda230b55b572dbd8f7355658bffe8 100644 (file)
@@ -4,8 +4,13 @@ error[E0004]: non-exhaustive patterns: type `*const Bottom` is non-empty
 LL |     match x { }
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `*const Bottom`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error: aborting due to previous error
 
index 2f562b23692deffc3128c6a612eb893d436977b5..9da6b5eeead235a575107bbde68c86eda7eb0204 100644 (file)
@@ -1,25 +1,30 @@
 error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered
   --> $DIR/issue-31561.rs:8:9
    |
-LL | / enum Thing {
-LL | |     Foo(u8),
-LL | |     Bar,
-   | |     --- not covered
-LL | |     Baz
-   | |     --- not covered
-LL | | }
-   | |_- `Thing` defined here
-...
-LL |       let Thing::Foo(y) = Thing::Foo(1);
-   |           ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
+LL |     let Thing::Foo(y) = Thing::Foo(1);
+   |         ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Thing` defined here
+  --> $DIR/issue-31561.rs:3:5
+   |
+LL | enum Thing {
+   |      -----
+LL |     Foo(u8),
+LL |     Bar,
+   |     ^^^ not covered
+LL |     Baz
+   |     ^^^ not covered
    = note: the matched value is of type `Thing`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let Thing::Foo(y) = Thing::Foo(1) { /* */ }
+LL |     let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() };
+   |     ++++++++++                                   ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched
    |
+LL |     let Thing::Foo(y) = Thing::Foo(1) else { todo!() };
+   |                                       ++++++++++++++++
 
 error: aborting due to previous error
 
index 0598c8d6f38c574b263700206d8955bb5b53d9b7..717bb53c32750e0df2dfc527505bb4d3296b1494 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(B, _)`, `(C, _)`, `(D, _)` and 2 more n
 LL |     match (A, ()) {
    |           ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Enum, ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         (A, _) => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
   --> $DIR/issue-35609.rs:14:11
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more n
 LL |     match (A, A) {
    |           ^^^^^^ patterns `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Enum, Enum)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         (_, A) => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
   --> $DIR/issue-35609.rs:18:11
@@ -22,8 +30,12 @@ error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _
 LL |     match ((A, ()), ()) {
    |           ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `((Enum, ()), ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         ((A, ()), _) => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
   --> $DIR/issue-35609.rs:22:11
@@ -31,8 +43,12 @@ error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _
 LL |     match ((A, ()), A) {
    |           ^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `((Enum, ()), Enum)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         ((A, ()), _) => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
   --> $DIR/issue-35609.rs:26:11
@@ -40,32 +56,48 @@ error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _
 LL |     match ((A, ()), ()) {
    |           ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `((Enum, ()), ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         ((A, _), _) => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered
   --> $DIR/issue-35609.rs:31:11
    |
-LL | struct S(Enum, ());
-   | ------------------- `S` defined here
-...
 LL |     match S(A, ()) {
    |           ^^^^^^^^ patterns `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `S` defined here
+  --> $DIR/issue-35609.rs:6:8
+   |
+LL | struct S(Enum, ());
+   |        ^
    = note: the matched value is of type `S`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         S(A, _) => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered
   --> $DIR/issue-35609.rs:35:11
    |
-LL | struct Sd { x: Enum, y: () }
-   | ---------------------------- `Sd` defined here
-...
 LL |     match (Sd { x: A, y: () }) {
    |           ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Sd` defined here
+  --> $DIR/issue-35609.rs:7:8
+   |
+LL | struct Sd { x: Enum, y: () }
+   |        ^^
    = note: the matched value is of type `Sd`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         Sd { x: A, y: _ } => {}
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
   --> $DIR/issue-35609.rs:39:11
@@ -73,8 +105,23 @@ error[E0004]: non-exhaustive patterns: `Some(B)`, `Some(C)`, `Some(D)` and 2 mor
 LL |     match Some(A) {
    |           ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Option<Enum>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+LL | | }
+   | |_^
    = note: the matched value is of type `Option<Enum>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         None => (),
+LL +         _ => todo!()
+   |
 
 error: aborting due to 8 previous errors
 
index 48ed14915084a5d607ae44e57b8a0cedcc4a6d3b..4e0adcc1ba2a538af4aaa509610a9deb3ce432d0 100644 (file)
@@ -4,8 +4,20 @@ error[E0004]: non-exhaustive patterns: `box _` not covered
 LL |         box NodeKind::Element(ed) => match ed.kind {
    |                                            ^^^^^^^ pattern `box _` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Box<ElementKind>` defined here
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+   |
+LL | / pub struct Box<
+LL | |     T: ?Sized,
+LL | |     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+LL | | >(Unique<T>, A);
+   | |________________^
    = note: the matched value is of type `Box<ElementKind>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~             box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }
+LL +             box _ => todo!()
+   |
 
 error: aborting due to previous error
 
index 8c162e55619e005b5e6aac41e9970f510d64c9ba..ca37af6fb809540f6e0e42f9f546332a72131154 100644 (file)
@@ -1,16 +1,22 @@
 error[E0004]: non-exhaustive patterns: `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
   --> $DIR/issue-39362.rs:10:11
    |
-LL | / enum Foo {
-LL | |     Bar { bar: Bar, id: usize }
-LL | | }
-   | |_- `Foo` defined here
-...
-LL |       match f {
-   |             ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
+LL |     match f {
+   |           ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+  --> $DIR/issue-39362.rs:2:5
+   |
+LL | enum Foo {
+   |      ---
+LL |     Bar { bar: Bar, id: usize }
+   |     ^^^ not covered
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         Foo::Bar { bar: Bar::B, .. } => (),
+LL ~         _ => todo!(),
+   |
 
 error: aborting due to previous error
 
index 98efe805a0b3491fde73c71445fa608e9119296a..c477e435335043274051e4ee041245a421b1ef44 100644 (file)
@@ -1,17 +1,22 @@
 error[E0004]: non-exhaustive patterns: `C(QA)` not covered
   --> $DIR/issue-40221.rs:11:11
    |
-LL | / enum P {
-LL | |     C(PC),
-   | |     - not covered
-LL | | }
-   | |_- `P` defined here
-...
-LL |       match proto {
-   |             ^^^^^ pattern `C(QA)` not covered
+LL |     match proto {
+   |           ^^^^^ pattern `C(QA)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `P` defined here
+  --> $DIR/issue-40221.rs:2:5
+   |
+LL | enum P {
+   |      -
+LL |     C(PC),
+   |     ^ not covered
    = note: the matched value is of type `P`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         P::C(PC::Q) => (),
+LL ~         C(QA) => todo!(),
+   |
 
 error: aborting due to previous error
 
index 1e8852556b161690c46dfb8ba5fdff3346c278d4..293273174101686bc4fd8e254d3009705eb56c9c 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(true, false)` not covered
 LL |     println!("foo {:}", match tup {
    |                               ^^^ pattern `(true, false)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(bool, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         (true, true) => "baz",
+LL +         (true, false) => todo!()
+   |
 
 error: aborting due to previous error
 
index d378b6e8efe370a84ac92491ae3ceb4853ad9b55..2bdbecabbbea092375cf58da0bf79a7f3ae079ec 100644 (file)
@@ -1,14 +1,20 @@
 error[E0004]: non-exhaustive patterns: `Tag(Exif, _)` not covered
   --> $DIR/issue-50900.rs:15:11
    |
-LL | pub struct Tag(pub Context, pub u16);
-   | ------------------------------------- `Tag` defined here
-...
 LL |     match Tag::ExifIFDPointer {
    |           ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Exif, _)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Tag` defined here
+  --> $DIR/issue-50900.rs:2:12
+   |
+LL | pub struct Tag(pub Context, pub u16);
+   |            ^^^
    = note: the matched value is of type `Tag`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Tag::ExifIFDPointer => {}
+LL +         Tag(Exif, _) => todo!()
+   |
 
 error: aborting due to previous error
 
index 6a231b868c8c457f045c5d8a6d03f6290b3e105b..f6261001c5e0903f455ec3da533bff1cda3cc995 100644 (file)
@@ -1,21 +1,26 @@
 error[E0004]: non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered
   --> $DIR/issue-56379.rs:8:11
    |
-LL | / enum Foo {
-LL | |     A(bool),
-   | |     - not covered
-LL | |     B(bool),
-   | |     - not covered
-LL | |     C(bool),
-   | |     - not covered
-LL | | }
-   | |_- `Foo` defined here
-...
-LL |       match Foo::A(true) {
-   |             ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered
+LL |     match Foo::A(true) {
+   |           ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+  --> $DIR/issue-56379.rs:2:5
+   |
+LL | enum Foo {
+   |      ---
+LL |     A(bool),
+   |     ^ not covered
+LL |     B(bool),
+   |     ^ not covered
+LL |     C(bool),
+   |     ^ not covered
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         Foo::C(true) => {}
+LL +         A(false) | B(false) | C(false) => todo!()
+   |
 
 error: aborting due to previous error
 
index b4a68333967b36b97d5ebf7c8284916c486c6d7b..20f002dd3db15c66d276335c80d09ea60844c7a6 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(A, Some(A))`, `(A, Some(B))`, `(B, Some
 LL |     match (x, y) {
    |           ^^^^^^ patterns `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(X, Option<X>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         (X::A, Some(X::C)) | (X::C, Some(X::A)) => false,
+LL ~         _ => todo!(),
+   |
 
 error: aborting due to previous error
 
index 6c5a331b4b564ebdc5e372b72e38242c75ccf53a..cbfcf0eafd4901032ddf5b67f6825592d3b9ed70 100644 (file)
@@ -1,5 +1,6 @@
 enum A {}
     //~^ NOTE `A` defined here
+    //~| NOTE
 
 fn f(a: &A) {
     match a {}
index e992632a91faf3dfdcac41901824f2dd4842400b..bf05d616d6ed1c2865ed46ccf21e3fa76c169e13 100644 (file)
@@ -1,15 +1,22 @@
 error[E0004]: non-exhaustive patterns: type `&A` is non-empty
-  --> $DIR/issue-78123-non-exhaustive-reference.rs:5:11
+  --> $DIR/issue-78123-non-exhaustive-reference.rs:6:11
    |
-LL | enum A {}
-   | --------- `A` defined here
-...
 LL |     match a {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `A` defined here
+  --> $DIR/issue-78123-non-exhaustive-reference.rs:1:6
+   |
+LL | enum A {}
+   |      ^
    = note: the matched value is of type `&A`
    = note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match a {
+LL +         _ => todo!(),
+LL +     }
+   |
 
 error: aborting due to previous error
 
index 4a987cb6c0311c94dfb1e7e7887fd22052b897e0..3326e6b85a471734c11bd6e3930a368be393202c 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `(true, false)` not covered
 LL |     match (true, false) {
    |           ^^^^^^^^^^^^^ pattern `(true, false)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(bool, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         (false, true) => (),
+LL +         (true, false) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Some(Some(West))` not covered
   --> $DIR/match-arm-statics-2.rs:29:11
@@ -13,31 +17,45 @@ error[E0004]: non-exhaustive patterns: `Some(Some(West))` not covered
 LL |     match Some(Some(North)) {
    |           ^^^^^^^^^^^^^^^^^ pattern `Some(Some(West))` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<Option<Direction>>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   | |     ^^^^
+   | |     |
+   | |     not covered
+   | |     not covered
+LL | | }
+   | |_-
+   = note: the matched value is of type `Option<Option<Direction>>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     ----
-   |     |
-   |     not covered
-   |     not covered
+LL ~         None => (),
+LL +         Some(Some(West)) => todo!()
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Option<Option<Direction>>`
 
 error[E0004]: non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` not covered
   --> $DIR/match-arm-statics-2.rs:48:11
    |
-LL | / struct Foo {
-LL | |     bar: Option<Direction>,
-LL | |     baz: NewBool
-LL | | }
-   | |_- `Foo` defined here
-...
-LL |       match (Foo { bar: Some(North), baz: NewBool(true) }) {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered
+LL |     match (Foo { bar: Some(North), baz: NewBool(true) }) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered
+   |
+note: `Foo` defined here
+  --> $DIR/match-arm-statics-2.rs:40:8
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | struct Foo {
+   |        ^^^
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo { bar: Some(EAST), .. } => (),
+LL +         Foo { bar: Some(North), baz: NewBool(true) } => todo!()
+   |
 
 error: aborting due to 3 previous errors
 
index ffc8433403fd59d96de8e2caa10fe9750c066106..a90f32f7aebf34e3bd99ba18d36dc5ded1077df7 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..
 LL |     match buf {
    |           ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8; 4]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         b"AAAA" => {}
+LL +         &[0_u8..=64_u8, _, _, _] | &[66_u8..=u8::MAX, _, _, _] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
   --> $DIR/match-byte-array-patterns-2.rs:10:11
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not c
 LL |     match buf {
    |           ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         b"AAAA" => {}
+LL +         _ => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
index a35d61e4b710be63198d39488c98c71420218f0b..08dde523a15fb524e3aaa7367452432fc642a6bf 100644 (file)
@@ -4,8 +4,11 @@ error[E0004]: non-exhaustive patterns: `i32::MIN..=0_i32` and `2_i32..=i32::MAX`
 LL |     match 0 { 1 => () }
    |           ^ patterns `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL |     match 0 { 1 => (), i32::MIN..=0_i32 | 2_i32..=i32::MAX => todo!() }
+   |                      ++++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/match-non-exhaustive.rs:3:11
@@ -13,8 +16,11 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match 0 { 0 if false => () }
    |           ^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |     match 0 { 0 if false => (), _ => todo!() }
+   |                               ++++++++++++++
 
 error: aborting due to 2 previous errors
 
index 4efb41978a241c08b722efe30c4c0e2d647664b3..88178d6429197eac5850ce0b9cc5c5d098ef3631 100644 (file)
@@ -4,13 +4,24 @@ error[E0004]: non-exhaustive patterns: `Some(Private { misc: true, .. })` not co
 LL |     match private::DATA {
    |           ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<Private>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
    |
-LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     ---- not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   | |     ^^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `Option<Private>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         }) => {}
+LL +         Some(Private { misc: true, .. }) => todo!()
+   |
 
 error: aborting due to previous error
 
index 88f27be0412aa550cd0be285a0da65f208788045..961dd5901196149b004bc627c8a01647beacf62d 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `&[_, Some(_), .., None, _]` not covered
 LL |     match list {
    |           ^^^^ pattern `&[_, Some(_), .., None, _]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[Option<()>]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         &[.., Some(_), _] => {}
+LL ~         &[_, Some(_), .., None, _] => todo!(),
+   |
 
 error: aborting due to previous error
 
index 6f009acbdfe1818ac9984720917a2a5146f3e0d2..2e15bc2d2a5f534fbab024f30bcd94f0039345fa 100644 (file)
@@ -4,20 +4,26 @@
 
 #[derive(Clone)]
 enum E {
-//~^ `E` defined here
-//~| `E` defined here
-//~| `E` defined here
-//~| `E` defined here
-//~| `E` defined here
-//~| `E` defined here
+    //~^ NOTE
+    //~| NOTE
+    //~| NOTE
+    //~| NOTE
+    //~| NOTE
+    //~| NOTE
     A,
     B,
-    //~^ not covered
-    //~| not covered
-    //~| not covered
-    //~| not covered
-    //~| not covered
-    //~| not covered
+    //~^ NOTE `E` defined here
+    //~| NOTE `E` defined here
+    //~| NOTE `E` defined here
+    //~| NOTE `E` defined here
+    //~| NOTE `E` defined here
+    //~| NOTE `E` defined here
+    //~| NOTE  not covered
+    //~| NOTE  not covered
+    //~| NOTE  not covered
+    //~| NOTE  not covered
+    //~| NOTE  not covered
+    //~| NOTE  not covered
     C
     //~^ not covered
     //~| not covered
@@ -30,43 +36,70 @@ enum E {
 fn by_val(e: E) {
     let e1 = e.clone();
     match e1 { //~ ERROR non-exhaustive patterns: `B` and `C` not covered
+        //~^ NOTE patterns `B` and `C` not covered
+        //~| NOTE the matched value is of type `E`
         E::A => {}
     }
 
     let E::A = e; //~ ERROR refutable pattern in local binding: `B` and `C` not covered
+    //~^ NOTE patterns `B` and `C` not covered
+    //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+    //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+    //~| NOTE the matched value is of type `E`
 }
 
 fn by_ref_once(e: &E) {
     match e { //~ ERROR non-exhaustive patterns: `&B` and `&C` not covered
+    //~^ NOTE patterns `&B` and `&C` not covered
+    //~| NOTE the matched value is of type `&E`
         E::A => {}
     }
 
     let E::A = e; //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
+    //~^ NOTE patterns `&B` and `&C` not covered
+    //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+    //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+    //~| NOTE the matched value is of type `&E`
 }
 
 fn by_ref_thrice(e: & &mut &E) {
     match e { //~ ERROR non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
+    //~^ NOTE patterns `&&mut &B` and `&&mut &C` not covered
+    //~| NOTE the matched value is of type `&&mut &E`
         E::A => {}
     }
 
     let E::A = e;
     //~^ ERROR refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
+    //~| NOTE patterns `&&mut &B` and `&&mut &C` not covered
+    //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+    //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+    //~| NOTE the matched value is of type `&&mut &E`
 }
 
 enum Opt {
-//~^ `Opt` defined here
-//~| `Opt` defined here
+    //~^ NOTE
+    //~| NOTE
     Some(u8),
     None,
-    //~^ not covered
+    //~^ NOTE `Opt` defined here
+    //~| NOTE `Opt` defined here
+    //~| NOTE not covered
+    //~| NOTE not covered
 }
 
 fn ref_pat(e: Opt) {
     match e {//~ ERROR non-exhaustive patterns: `None` not covered
+        //~^ NOTE pattern `None` not covered
+        //~| NOTE the matched value is of type `Opt`
         Opt::Some(ref _x) => {}
     }
 
     let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `None` not covered
+    //~^ NOTE the matched value is of type `Opt`
+    //~| NOTE pattern `None` not covered
+    //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+    //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 }
 
 fn main() {}
index 02eff28015d178bd6f2152619d3dae40deaf1cf8..0f06c31c468b148035cb1d88313079cd27b00bba 100644 (file)
 error[E0004]: non-exhaustive patterns: `B` and `C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:32:11
-   |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     B,
-   | |     - not covered
-...  |
-LL | |     C
-   | |     - not covered
-...  |
-LL | |
-LL | | }
-   | |_- `E` defined here
-...
-LL |       match e1 {
-   |             ^^ patterns `B` and `C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:38:11
+   |
+LL |     match e1 {
+   |           ^^ patterns `B` and `C` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:14:5
+   |
+LL | enum E {
+   |      -
+...
+LL |     B,
+   |     ^ not covered
+...
+LL |     C
+   |     ^ not covered
    = note: the matched value is of type `E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         E::A => {}
+LL +         B | C => todo!()
+   |
 
 error[E0005]: refutable pattern in local binding: `B` and `C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:36:9
-   |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     B,
-   | |     - not covered
-...  |
-LL | |     C
-   | |     - not covered
-...  |
-LL | |
-LL | | }
-   | |_- `E` defined here
-...
-LL |       let E::A = e;
-   |           ^^^^ patterns `B` and `C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:44:9
+   |
+LL |     let E::A = e;
+   |         ^^^^ patterns `B` and `C` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `E` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:14:5
+   |
+LL | enum E {
+   |      -
+...
+LL |     B,
+   |     ^ not covered
+...
+LL |     C
+   |     ^ not covered
    = note: the matched value is of type `E`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let E::A = e { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     if let E::A = e { todo!() }
+   |     ++              ~~~~~~~~~~~
 
 error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:40:11
-   |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     B,
-   | |     - not covered
-...  |
-LL | |     C
-   | |     - not covered
-...  |
-LL | |
-LL | | }
-   | |_- `E` defined here
-...
-LL |       match e {
-   |             ^ patterns `&B` and `&C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:52:11
+   |
+LL |     match e {
+   |           ^ patterns `&B` and `&C` not covered
+   |
+note: `E` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:14:5
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum E {
+   |      -
+...
+LL |     B,
+   |     ^ not covered
+...
+LL |     C
+   |     ^ not covered
    = note: the matched value is of type `&E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         E::A => {}
+LL +         &B | &C => todo!()
+   |
 
 error[E0005]: refutable pattern in local binding: `&B` and `&C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:44:9
+  --> $DIR/non-exhaustive-defined-here.rs:58:9
    |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     B,
-   | |     - not covered
-...  |
-LL | |     C
-   | |     - not covered
-...  |
-LL | |
-LL | | }
-   | |_- `E` defined here
-...
-LL |       let E::A = e;
-   |           ^^^^ patterns `&B` and `&C` not covered
+LL |     let E::A = e;
+   |         ^^^^ patterns `&B` and `&C` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `E` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:14:5
+   |
+LL | enum E {
+   |      -
+...
+LL |     B,
+   |     ^ not covered
+...
+LL |     C
+   |     ^ not covered
    = note: the matched value is of type `&E`
-help: you might want to use `if let` to ignore the variant that isn't matched
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
-LL |     if let E::A = e { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     if let E::A = e { todo!() }
+   |     ++              ~~~~~~~~~~~
 
 error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:48:11
-   |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     B,
-   | |     - not covered
-...  |
-LL | |     C
-   | |     - not covered
-...  |
-LL | |
-LL | | }
-   | |_- `E` defined here
-...
-LL |       match e {
-   |             ^ patterns `&&mut &B` and `&&mut &C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:66:11
+   |
+LL |     match e {
+   |           ^ patterns `&&mut &B` and `&&mut &C` not covered
+   |
+note: `E` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:14:5
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum E {
+   |      -
+...
+LL |     B,
+   |     ^ not covered
+...
+LL |     C
+   |     ^ not covered
    = note: the matched value is of type `&&mut &E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         E::A => {}
+LL +         &&mut &B | &&mut &C => todo!()
+   |
 
 error[E0005]: refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:52:9
-   |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     B,
-   | |     - not covered
-...  |
-LL | |     C
-   | |     - not covered
-...  |
-LL | |
-LL | | }
-   | |_- `E` defined here
-...
-LL |       let E::A = e;
-   |           ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:72:9
+   |
+LL |     let E::A = e;
+   |         ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `&&mut &E`
-help: you might want to use `if let` to ignore the variant that isn't matched
+note: `E` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:14:5
    |
-LL |     if let E::A = e { /* */ }
+LL | enum E {
+   |      -
+...
+LL |     B,
+   |     ^ not covered
+...
+LL |     C
+   |     ^ not covered
+   = note: the matched value is of type `&&mut &E`
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
+LL |     if let E::A = e { todo!() }
+   |     ++              ~~~~~~~~~~~
 
 error[E0004]: non-exhaustive patterns: `None` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:65:11
-   |
-LL | / enum Opt {
-LL | |
-LL | |
-LL | |     Some(u8),
-LL | |     None,
-   | |     ---- not covered
-LL | |
-LL | | }
-   | |_- `Opt` defined here
-...
-LL |       match e {
-   |             ^ pattern `None` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:92:11
+   |
+LL |     match e {
+   |           ^ pattern `None` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Opt` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:84:5
+   |
+LL | enum Opt {
+   |      ---
+...
+LL |     None,
+   |     ^^^^ not covered
    = note: the matched value is of type `Opt`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Opt::Some(ref _x) => {}
+LL +         None => todo!()
+   |
 
 error[E0005]: refutable pattern in local binding: `None` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:69:9
-   |
-LL | / enum Opt {
-LL | |
-LL | |
-LL | |     Some(u8),
-LL | |     None,
-   | |     ---- not covered
-LL | |
-LL | | }
-   | |_- `Opt` defined here
-...
-LL |       let Opt::Some(ref _x) = e;
-   |           ^^^^^^^^^^^^^^^^^ pattern `None` not covered
+  --> $DIR/non-exhaustive-defined-here.rs:98:9
+   |
+LL |     let Opt::Some(ref _x) = e;
+   |         ^^^^^^^^^^^^^^^^^ pattern `None` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Opt` defined here
+  --> $DIR/non-exhaustive-defined-here.rs:84:5
+   |
+LL | enum Opt {
+   |      ---
+...
+LL |     None,
+   |     ^^^^ not covered
    = note: the matched value is of type `Opt`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Opt::Some(ref _x) = e { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() };
+   |     +++++++++++                           +++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+   |
+LL |     let Opt::Some(ref _x) = e else { todo!() };
+   |                               ++++++++++++++++
 
 error: aborting due to 8 previous errors
 
index 928e9068266cd5cc7e9c9847ce34e68fea1a2476..cbbd544f943ba1f0f3488868e0dbcfe68bbc5004 100644 (file)
@@ -4,23 +4,30 @@ error[E0004]: non-exhaustive patterns: `(Some(&[]), Err(_))` not covered
 LL |     match (l1, l2) {
    |           ^^^^^^^^ pattern `(Some(&[]), Err(_))` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Option<&[T]>, Result<&[T], ()>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)",
+LL +         (Some(&[]), Err(_)) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `A(C)` not covered
   --> $DIR/non-exhaustive-match-nested.rs:15:11
    |
-LL | enum T { A(U), B }
-   | ------------------
-   | |        |
-   | |        not covered
-   | `T` defined here
-...
 LL |     match x {
    |           ^ pattern `A(C)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `T` defined here
+  --> $DIR/non-exhaustive-match-nested.rs:1:10
+   |
+LL | enum T { A(U), B }
+   |      -   ^ not covered
    = note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         T::B => { panic!("goodbye"); }
+LL +         A(C) => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
index 1ca0a33bf37d90e03c7804d2fe53f4c067de86f1..e7fa6a7814f85358f8b7a7c59358eec5aac730a5 100644 (file)
@@ -1,17 +1,19 @@
 error[E0004]: non-exhaustive patterns: `A` not covered
   --> $DIR/non-exhaustive-match.rs:7:11
    |
-LL | enum T { A, B }
-   | ---------------
-   | |        |
-   | |        not covered
-   | `T` defined here
-...
 LL |     match x { T::B => { } }
    |           ^ pattern `A` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `T` defined here
+  --> $DIR/non-exhaustive-match.rs:3:10
+   |
+LL | enum T { A, B }
+   |      -   ^ not covered
    = note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |     match x { T::B => { } A => todo!() }
+   |                           ++++++++++++
 
 error[E0004]: non-exhaustive patterns: `false` not covered
   --> $DIR/non-exhaustive-match.rs:8:11
@@ -19,8 +21,12 @@ error[E0004]: non-exhaustive patterns: `false` not covered
 LL |     match true {
    |           ^^^^ pattern `false` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `bool`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~       true => {}
+LL +       false => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
   --> $DIR/non-exhaustive-match.rs:11:11
@@ -28,13 +34,24 @@ error[E0004]: non-exhaustive patterns: `Some(_)` not covered
 LL |     match Some(10) {
    |           ^^^^^^^^ pattern `Some(_)` not covered
    |
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<i32>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL | / pub enum Option<T> {
+LL | |     /// No value.
+LL | |     #[lang = "None"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   | |     ^^^^ not covered
+LL | | }
+   | |_-
+   = note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     ---- not covered
+LL ~       None => {}
+LL +       Some(_) => todo!()
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Option<i32>`
 
 error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
   --> $DIR/non-exhaustive-match.rs:14:11
@@ -42,8 +59,12 @@ error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_
 LL |     match (2, 3, 4) {
    |           ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(i32, i32, i32)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~       (_, _, 4) => {}
+LL +       (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
   --> $DIR/non-exhaustive-match.rs:18:11
@@ -51,23 +72,30 @@ error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
 LL |     match (T::A, T::A) {
    |           ^^^^^^^^^^^^ patterns `(A, A)` and `(B, B)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(T, T)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~       (T::B, T::A) => {}
+LL +       (A, A) | (B, B) => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `B` not covered
   --> $DIR/non-exhaustive-match.rs:22:11
    |
-LL | enum T { A, B }
-   | ---------------
-   | |           |
-   | |           not covered
-   | `T` defined here
-...
 LL |     match T::A {
    |           ^^^^ pattern `B` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `T` defined here
+  --> $DIR/non-exhaustive-match.rs:3:13
+   |
+LL | enum T { A, B }
+   |      -      ^ not covered
    = note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~       T::A => {}
+LL +       B => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
   --> $DIR/non-exhaustive-match.rs:33:11
@@ -75,8 +103,12 @@ error[E0004]: non-exhaustive patterns: `[]` not covered
 LL |     match *vec {
    |           ^^^^ pattern `[]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `[Option<isize>]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [None] => {}
+LL +         [] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
   --> $DIR/non-exhaustive-match.rs:46:11
@@ -84,8 +116,12 @@ error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
 LL |     match *vec {
    |           ^^^^ pattern `[_, _, _, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `[f32]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [] => (),
+LL +         [_, _, _, _, ..] => todo!()
+   |
 
 error: aborting due to 8 previous errors
 
index c9ed12aae5fbc128c202799fe0c14d6950f30f6e..b0cfd631fb07ebd28c493bafa38dd3722d1fee3c 100644 (file)
 error[E0004]: non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:7:11
    |
-LL | / struct Foo {
-LL | |     first: bool,
-LL | |     second: Option<[usize; 4]>
-LL | | }
-   | |_- `Foo` defined here
-...
-LL |       match (Foo { first: true, second: None }) {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+LL |     match (Foo { first: true, second: None }) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+   |
+note: `Foo` defined here
+  --> $DIR/non-exhaustive-pattern-witness.rs:1:8
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | struct Foo {
+   |        ^^^
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo { first: false, second: Some([1, 2, 3, 4]) } => (),
+LL +         Foo { first: false, second: Some([_, _, _, _]) } => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Red` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:23:11
    |
-LL | / enum Color {
-LL | |     Red,
-   | |     --- not covered
-LL | |     Green,
-LL | |     CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
-LL | | }
-   | |_- `Color` defined here
-...
-LL |       match Color::Red {
-   |             ^^^^^^^^^^ pattern `Red` not covered
+LL |     match Color::Red {
+   |           ^^^^^^^^^^ pattern `Red` not covered
+   |
+note: `Color` defined here
+  --> $DIR/non-exhaustive-pattern-witness.rs:17:5
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum Color {
+   |      -----
+LL |     Red,
+   |     ^^^ not covered
    = note: the matched value is of type `Color`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Color::Green => (),
+LL +         Red => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `East`, `South` and `West` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:35:11
    |
-LL | / enum Direction {
-LL | |     North, East, South, West
-   | |            ----  -----  ---- not covered
-   | |            |     |
-   | |            |     not covered
-   | |            not covered
-LL | | }
-   | |_- `Direction` defined here
-...
-LL |       match Direction::North {
-   |             ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered
+LL |     match Direction::North {
+   |           ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered
+   |
+note: `Direction` defined here
+  --> $DIR/non-exhaustive-pattern-witness.rs:31:12
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum Direction {
+   |      ---------
+LL |     North, East, South, West
+   |            ^^^^  ^^^^^  ^^^^ not covered
+   |            |     |
+   |            |     not covered
+   |            not covered
    = note: the matched value is of type `Direction`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         Direction::North => (),
+LL +         East | South | West => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `Second`, `Third`, `Fourth` and 8 more not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:46:11
    |
-LL | / enum ExcessiveEnum {
-LL | |     First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth
-LL | | }
-   | |_- `ExcessiveEnum` defined here
-...
-LL |       match ExcessiveEnum::First {
-   |             ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered
+LL |     match ExcessiveEnum::First {
+   |           ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `ExcessiveEnum` defined here
+  --> $DIR/non-exhaustive-pattern-witness.rs:41:6
+   |
+LL | enum ExcessiveEnum {
+   |      ^^^^^^^^^^^^^
    = note: the matched value is of type `ExcessiveEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         ExcessiveEnum::First => (),
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `CustomRGBA { a: true, .. }` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:54:11
    |
-LL | / enum Color {
-LL | |     Red,
-LL | |     Green,
-LL | |     CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
-   | |     ---------- not covered
-LL | | }
-   | |_- `Color` defined here
-...
-LL |       match Color::Red {
-   |             ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered
+LL |     match Color::Red {
+   |           ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered
+   |
+note: `Color` defined here
+  --> $DIR/non-exhaustive-pattern-witness.rs:19:5
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum Color {
+   |      -----
+...
+LL |     CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
+   |     ^^^^^^^^^^ not covered
    = note: the matched value is of type `Color`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Color::CustomRGBA { a: false, r: _, g: _, b: _ } => (),
+LL +         CustomRGBA { a: true, .. } => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `[Second(true), Second(false)]` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:70:11
@@ -85,8 +104,12 @@ error[E0004]: non-exhaustive patterns: `[Second(true), Second(false)]` not cover
 LL |     match *x {
    |           ^^ pattern `[Second(true), Second(false)]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `[Enum]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [_, _, ref tail @ .., _] => (),
+LL +         [Second(true), Second(false)] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `((), false)` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:83:11
@@ -94,8 +117,12 @@ error[E0004]: non-exhaustive patterns: `((), false)` not covered
 LL |     match ((), false) {
    |           ^^^^^^^^^^^ pattern `((), false)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `((), bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         ((), true) => (),
+LL +         ((), false) => todo!()
+   |
 
 error: aborting due to 7 previous errors
 
index 74ec646e31cca27b5507217ca02b197c51fc2d0d..d1dacc822e942e49856d95c4bad4d01e48c3a99e 100644 (file)
@@ -15,10 +15,10 @@ LL |     let (1, (Some(1), 2..=3)) = (1, (None, 2));
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `(i32, (Option<i32>, i32))`
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |     if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { /* */ }
+help: you might want to use `if let` to ignore the variants that aren't matched
    |
+LL |     if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { todo!() }
+   |     ++                                            ~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
index e34770fb912e79437a0b98a901590bc3eaecacb8..5d1e170ae6c2b5739f4396f09cd1e09c2d55cb53 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `&[false, _]` not covered
 LL |     match s2 {
    |           ^^ pattern `&[false, _]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool; 2]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [true, .., true] => {}
+LL +         &[false, _] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:12:11
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
 LL |     match s3 {
    |           ^^ pattern `&[false, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool; 3]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [true, .., true] => {}
+LL +         &[false, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:16:11
@@ -22,8 +30,12 @@ error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
 LL |     match s10 {
    |           ^^^ pattern `&[false, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool; 10]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [true, .., true] => {}
+LL +         &[false, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, true]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:25:11
@@ -31,8 +43,12 @@ error[E0004]: non-exhaustive patterns: `&[false, true]` not covered
 LL |     match s2 {
    |           ^^ pattern `&[false, true]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool; 2]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [.., false] => {}
+LL +         &[false, true] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:30:11
@@ -40,8 +56,12 @@ error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
 LL |     match s3 {
    |           ^^ pattern `&[false, .., true]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool; 3]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [.., false] => {}
+LL +         &[false, .., true] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:35:11
@@ -49,8 +69,12 @@ error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
 LL |     match s {
    |           ^ pattern `&[false, .., true]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [.., false] => {}
+LL +         &[false, .., true] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:42:11
@@ -58,8 +82,12 @@ error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
 LL |     match s {
    |           ^ pattern `&[_, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [] => {}
+LL +         &[_, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:46:11
@@ -67,8 +95,12 @@ error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
 LL |     match s {
    |           ^ pattern `&[_, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [_] => {}
+LL +         &[_, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:51:11
@@ -76,8 +108,12 @@ error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
 LL |     match s {
    |           ^ pattern `&[false, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [true, ..] => {}
+LL +         &[false, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:56:11
@@ -85,8 +121,12 @@ error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered
 LL |     match s {
    |           ^ pattern `&[false, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [true, ..] => {}
+LL +         &[false, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:62:11
@@ -94,8 +134,12 @@ error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered
 LL |     match s {
    |           ^ pattern `&[_, .., false]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [.., true] => {}
+LL +         &[_, .., false] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:69:11
@@ -103,8 +147,12 @@ error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered
 LL |     match s {
    |           ^ pattern `&[_, _, .., true]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [.., false] => {}
+LL +         &[_, _, .., true] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:76:11
@@ -112,8 +160,12 @@ error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered
 LL |     match s {
    |           ^ pattern `&[true, _, .., _]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [false, .., false] => {}
+LL +         &[true, _, .., _] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:85:11
@@ -121,8 +173,12 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         &[true] => {}
+LL +         &[] | &[_, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:89:11
@@ -130,8 +186,12 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         CONST => {}
+LL +         &[] | &[_, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:93:11
@@ -139,8 +199,12 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         &[false] => {}
+LL +         &[] | &[_, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:98:11
@@ -148,8 +212,12 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         CONST => {}
+LL +         &[] | &[_, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:103:11
@@ -157,8 +225,12 @@ error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
 LL |     match s {
    |           ^ pattern `&[_, _, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         CONST => {}
+LL +         &[_, _, ..] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:108:11
@@ -166,8 +238,12 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered
 LL |     match s {
    |           ^ pattern `&[false]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         &[_, _, ..] => {}
+LL +         &[false] => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `&[false]` not covered
   --> $DIR/slice-patterns-exhaustiveness.rs:121:11
@@ -175,8 +251,12 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered
 LL |     match s1 {
    |           ^^ pattern `&[false]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[bool; 1]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         CONST1 => {}
+LL +         &[false] => todo!()
+   |
 
 error: aborting due to 20 previous errors
 
index 9b42565ac7342b96512ae368cd6315325b59a3c3..696ef9d8de9362d2ef539a56217077ec87403782 100644 (file)
@@ -4,13 +4,25 @@ error[E0004]: non-exhaustive patterns: `Stable2` and `_` not covered
 LL |     match Foo::Stable {
    |           ^^^^^^^^^^^ patterns `Stable2` and `_` not covered
    |
-  ::: $DIR/auxiliary/unstable.rs:9:5
+note: `Foo` defined here
+  --> $DIR/auxiliary/unstable.rs:9:5
    |
-LL |     Stable2,
-   |     ------- not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Foo {
+LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | |     Stable,
+LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | |     Stable2,
+   | |     ^^^^^^^ not covered
+LL | |     #[unstable(feature = "unstable_test_feature", issue = "none")]
+LL | |     Unstable,
+LL | | }
+   | |_-
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~         Foo::Stable => {}
+LL +         Stable2 | _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/stable-gated-patterns.rs:13:11
@@ -18,8 +30,23 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match Foo::Stable {
    |           ^^^^^^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+  --> $DIR/auxiliary/unstable.rs:5:1
+   |
+LL | / pub enum Foo {
+LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | |     Stable,
+LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
+...  |
+LL | |     Unstable,
+LL | | }
+   | |_^
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo::Stable2 => {}
+LL +         _ => todo!()
+   |
 
 error: aborting due to 2 previous errors
 
index 23ff6c626f759c63e078f810a4b0dfb1040de1b0..6127fad3f7d54410d144a5d218c6e100cf043366 100644 (file)
@@ -1,18 +1,22 @@
 error[E0004]: non-exhaustive patterns: `B { x: Some(_) }` not covered
   --> $DIR/struct-like-enum-nonexhaustive.rs:8:11
    |
-LL | / enum A {
-LL | |     B { x: Option<isize> },
-   | |     - not covered
-LL | |     C
-LL | | }
-   | |_- `A` defined here
-...
-LL |       match x {
-   |             ^ pattern `B { x: Some(_) }` not covered
+LL |     match x {
+   |           ^ pattern `B { x: Some(_) }` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `A` defined here
+  --> $DIR/struct-like-enum-nonexhaustive.rs:2:5
+   |
+LL | enum A {
+   |      -
+LL |     B { x: Option<isize> },
+   |     ^ not covered
    = note: the matched value is of type `A`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         A::B { x: None } => {}
+LL +         B { x: Some(_) } => todo!()
+   |
 
 error: aborting due to previous error
 
index ca8f67f3c8df2d88c0de7448da6b4207dc035bdd..fc0430d06fa1c03354a6875b6040d6793548f9b2 100644 (file)
@@ -1,14 +1,20 @@
 error[E0004]: non-exhaustive patterns: `Foo(_, _)` not covered
   --> $DIR/tuple-struct-nonexhaustive.rs:5:11
    |
-LL | struct Foo(isize, isize);
-   | ------------------------- `Foo` defined here
-...
 LL |     match x {
    |           ^ pattern `Foo(_, _)` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+  --> $DIR/tuple-struct-nonexhaustive.rs:1:8
+   |
+LL | struct Foo(isize, isize);
+   |        ^^^
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo(2, b) => println!("{}", b)
+LL +         Foo(_, _) => todo!()
+   |
 
 error: aborting due to previous error
 
index 6ce53a4f21ea21ed1402d490fdb54b34fef3ab8a..acae605dae3a870f60e58cb3ccbea349d8eb0441 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
 LL |     match data {
    |           ^^^^ pattern `&[_, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         b"" => 1,
+LL ~         &[_, ..] => todo!(),
+   |
 
 error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
   --> $DIR/type_polymorphic_byte_str_literals.rs:23:11
@@ -13,8 +17,12 @@ error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not c
 LL |     match data {
    |           ^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~         [_, _, _] => 1,
+LL ~         _ => todo!(),
+   |
 
 error: aborting due to 2 previous errors
 
index f9c0196b76598163c84e49234590bc0b09ff27c4..8487c9725da8332f6935291b7ec28b33454786a0 100644 (file)
@@ -4,13 +4,24 @@ error[E0004]: non-exhaustive patterns: `Unstable` not covered
 LL |     match Foo::Stable {
    |           ^^^^^^^^^^^ pattern `Unstable` not covered
    |
-  ::: $DIR/auxiliary/unstable.rs:11:5
+note: `Foo` defined here
+  --> $DIR/auxiliary/unstable.rs:11:5
    |
-LL |     Unstable,
-   |     -------- not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Foo {
+LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | |     Stable,
+LL | |     #[stable(feature = "stable_test_feature", since = "1.0.0")]
+...  |
+LL | |     Unstable,
+   | |     ^^^^^^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo::Stable2 => {}
+LL +         Unstable => todo!()
+   |
 
 error: aborting due to previous error
 
index f904a0ecd11cd135d94fafd7afdb0e71086add7f..a9159562d9d512858354816138493869f75349e5 100644 (file)
@@ -4,18 +4,29 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
 LL |     let Ok(x) = res;
    |         ^^^^^ pattern `Err(_)` not covered
    |
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
-   |     --- not covered
-   |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Result<u32, &R>` defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | / pub enum Result<T, E> {
+LL | |     /// Contains the success value
+LL | |     #[lang = "Ok"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+   | |     ^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `Result<u32, &R>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Ok(x) = res { /* */ }
+LL |     let x = if let Ok(x) = res { x } else { todo!() };
+   |     ++++++++++                 ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
    |
+LL |     let Ok(x) = res else { todo!() };
+   |                     ++++++++++++++++
 
 error: aborting due to previous error
 
index 18d8f5481c9fbf39aa7274b2587e524488ae71bc..60c1f5420f62c29322de982b95fc63ad28cdf9d8 100644 (file)
@@ -4,8 +4,12 @@ error[E0004]: non-exhaustive patterns: `&[]` not covered
 LL |     match sl {
    |           ^^ pattern `&[]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         [first, remainder @ ..] => {}
+LL ~         &[] => todo!(),
+   |
 
 error: aborting due to previous error
 
index cd9ded81e6a09e72c701039230308050a8293ba9..5ef078c20057df6faeb2dd592a53b16358fb7f21 100644 (file)
@@ -4,8 +4,18 @@ error[E0004]: non-exhaustive patterns: type `EmptyNonExhaustiveEnum` is non-empt
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `EmptyNonExhaustiveEnum` defined here
+  --> $DIR/auxiliary/enums.rs:18:1
+   |
+LL | pub enum EmptyNonExhaustiveEnum {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `EmptyNonExhaustiveEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/enum.rs:16:11
@@ -13,8 +23,21 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match enum_unit {
    |           ^^^^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonExhaustiveEnum` defined here
+  --> $DIR/auxiliary/enums.rs:4:1
+   |
+LL | / pub enum NonExhaustiveEnum {
+LL | |     Unit,
+LL | |     Tuple(u32),
+LL | |     Struct { field: u32 },
+LL | | }
+   | |_^
    = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         NonExhaustiveEnum::Struct { .. } => "third",
+LL +         _ => todo!()
+   |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
   --> $DIR/enum.rs:23:11
@@ -22,8 +45,22 @@ error[E0004]: non-exhaustive patterns: `_` not covered
 LL |     match enum_unit {};
    |           ^^^^^^^^^ pattern `_` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonExhaustiveEnum` defined here
+  --> $DIR/auxiliary/enums.rs:4:1
+   |
+LL | / pub enum NonExhaustiveEnum {
+LL | |     Unit,
+LL | |     Tuple(u32),
+LL | |     Struct { field: u32 },
+LL | | }
+   | |_^
    = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~     match enum_unit {
+LL +         _ => todo!(),
+LL ~     };
+   |
 
 error: aborting due to 3 previous errors
 
index 966f3a2e414857f3e87aad7af9de953104b033d6..1f20904483fe755649f29eec70edd5d371ce43ce 100644 (file)
@@ -13,46 +13,56 @@ LL | #![deny(unreachable_patterns)]
 error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/enum_same_crate_empty_match.rs:33:11
    |
-LL | / pub enum NonExhaustiveEnum {
-LL | |     Unit,
-   | |     ---- not covered
-LL | |
-LL | |     Tuple(u32),
-   | |     ----- not covered
-LL | |
-LL | |     Struct { field: u32 }
-   | |     ------ not covered
-LL | |
-LL | | }
-   | |_- `NonExhaustiveEnum` defined here
-...
-LL |       match NonExhaustiveEnum::Unit {}
-   |             ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match NonExhaustiveEnum::Unit {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+   |
+note: `NonExhaustiveEnum` defined here
+  --> $DIR/enum_same_crate_empty_match.rs:5:5
+   |
+LL | pub enum NonExhaustiveEnum {
+   |          -----------------
+LL |     Unit,
+   |     ^^^^ not covered
+LL |
+LL |     Tuple(u32),
+   |     ^^^^^ not covered
+LL |
+LL |     Struct { field: u32 }
+   |     ^^^^^^ not covered
    = note: the matched value is of type `NonExhaustiveEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~     match NonExhaustiveEnum::Unit {
+LL +         Unit | Tuple(_) | Struct { .. } => todo!(),
+LL +     }
+   |
 
 error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/enum_same_crate_empty_match.rs:35:11
    |
-LL | / pub enum NormalEnum {
-LL | |     Unit,
-   | |     ---- not covered
-LL | |
-LL | |     Tuple(u32),
-   | |     ----- not covered
-LL | |
-LL | |     Struct { field: u32 }
-   | |     ------ not covered
-LL | |
-LL | | }
-   | |_- `NormalEnum` defined here
-...
-LL |       match NormalEnum::Unit {}
-   |             ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match NormalEnum::Unit {}
+   |           ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+   |
+note: `NormalEnum` defined here
+  --> $DIR/enum_same_crate_empty_match.rs:14:5
+   |
+LL | pub enum NormalEnum {
+   |          ----------
+LL |     Unit,
+   |     ^^^^ not covered
+LL |
+LL |     Tuple(u32),
+   |     ^^^^^ not covered
+LL |
+LL |     Struct { field: u32 }
+   |     ^^^^^^ not covered
    = note: the matched value is of type `NormalEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~     match NormalEnum::Unit {
+LL +         Unit | Tuple(_) | Struct { .. } => todo!(),
+LL +     }
+   |
 
 error: aborting due to 3 previous errors
 
index c461302a366bdf2fe254f8bd5e093f20d1b85cf1..2dc4eabb8630a141b551cc9cb65cae9e40e399f7 100644 (file)
@@ -4,8 +4,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-emp
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedEnum` defined here
+  --> $DIR/auxiliary/uninhabited.rs:26:1
+   |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
   --> $DIR/indirect_match.rs:23:11
@@ -13,8 +23,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-e
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:28:1
+   |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
   --> $DIR/indirect_match.rs:27:11
@@ -22,8 +42,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedTupleStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:30:1
+   |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
   --> $DIR/indirect_match.rs:33:11
@@ -31,8 +61,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedVariants` defined here
+  --> $DIR/auxiliary/uninhabited.rs:32:1
+   |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error: aborting due to 4 previous errors
 
index 42bf67c0a45dfd06b8f63f7df373528074791033..c1219054140353175cb8cc802b1ec64366ba3850 100644 (file)
@@ -1,50 +1,78 @@
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty
   --> $DIR/indirect_match_same_crate.rs:34:11
    |
-LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
-   | ---------------------------------------------------- `IndirectUninhabitedEnum` defined here
-...
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedEnum` defined here
+  --> $DIR/indirect_match_same_crate.rs:20:12
+   |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
   --> $DIR/indirect_match_same_crate.rs:38:11
    |
-LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
-   | -------------------------------------------------------- `IndirectUninhabitedStruct` defined here
-...
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedStruct` defined here
+  --> $DIR/indirect_match_same_crate.rs:22:12
+   |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
   --> $DIR/indirect_match_same_crate.rs:42:11
    |
-LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
-   | ------------------------------------------------------------------ `IndirectUninhabitedTupleStruct` defined here
-...
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedTupleStruct` defined here
+  --> $DIR/indirect_match_same_crate.rs:24:12
+   |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
   --> $DIR/indirect_match_same_crate.rs:48:11
    |
-LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
-   | ------------------------------------------------------------ `IndirectUninhabitedVariants` defined here
-...
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedVariants` defined here
+  --> $DIR/indirect_match_same_crate.rs:26:12
+   |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error: aborting due to 4 previous errors
 
index c397158c02495c1a2b0eb6b8202d745a1a5066a8..f0cb13de3f799b9043fd0aea3ba3afdfd46c1208 100644 (file)
@@ -4,8 +4,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-emp
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedEnum` defined here
+  --> $DIR/auxiliary/uninhabited.rs:26:1
+   |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
   --> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11
@@ -13,8 +23,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-e
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:28:1
+   |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
   --> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11
@@ -22,8 +42,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedTupleStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:30:1
+   |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
   --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11
@@ -31,8 +61,18 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedVariants` defined here
+  --> $DIR/auxiliary/uninhabited.rs:32:1
+   |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `IndirectUninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error: aborting due to 4 previous errors
 
index d21a94a0d6498ff76bf84681859c290aacfda54f..49febd9241dc6e9cceb1e5dd6511c8910b6afbae 100644 (file)
@@ -4,8 +4,19 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedEnum` defined here
+  --> $DIR/auxiliary/uninhabited.rs:5:1
+   |
+LL | / pub enum UninhabitedEnum {
+LL | | }
+   | |_^
    = note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
   --> $DIR/match.rs:23:11
@@ -13,8 +24,20 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:9:1
+   |
+LL | / pub struct UninhabitedStruct {
+LL | |     _priv: !,
+LL | | }
+   | |_^
    = note: the matched value is of type `UninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
   --> $DIR/match.rs:27:11
@@ -22,8 +45,18 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empt
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedTupleStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:14:1
+   |
+LL | pub struct UninhabitedTupleStruct(!);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `UninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/match.rs:31:11
@@ -31,15 +64,23 @@ error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covere
 LL |     match x {}
    |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
    |
-  ::: $DIR/auxiliary/uninhabited.rs:17:23
+note: `UninhabitedVariants` defined here
+  --> $DIR/auxiliary/uninhabited.rs:17:23
    |
-LL |     #[non_exhaustive] Tuple(!),
-   |                       ----- not covered
-LL |     #[non_exhaustive] Struct { x: ! }
-   |                       ------ not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum UninhabitedVariants {
+LL | |     #[non_exhaustive] Tuple(!),
+   | |                       ^^^^^ not covered
+LL | |     #[non_exhaustive] Struct { x: ! }
+   | |                       ^^^^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~     match x {
+LL +         Tuple(_) | Struct { .. } => todo!(),
+LL ~     }
+   |
 
 error: aborting due to 4 previous errors
 
index e4d0c7022f3b41c9a86d9bec898cb2e65e1c6d7a..c89c70ae6cc1f9acc1272dff64396311eb669aba 100644 (file)
@@ -1,45 +1,63 @@
 error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
   --> $DIR/match_same_crate.rs:30:11
    |
-LL | / pub struct UninhabitedStruct {
-LL | |     _priv: !,
-LL | | }
-   | |_- `UninhabitedStruct` defined here
-...
-LL |       match x {}
-   |             ^
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match x {}
+   |           ^
+   |
+note: `UninhabitedStruct` defined here
+  --> $DIR/match_same_crate.rs:8:12
+   |
+LL | pub struct UninhabitedStruct {
+   |            ^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `UninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
   --> $DIR/match_same_crate.rs:34:11
    |
-LL | pub struct UninhabitedTupleStruct(!);
-   | ------------------------------------- `UninhabitedTupleStruct` defined here
-...
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedTupleStruct` defined here
+  --> $DIR/match_same_crate.rs:13:12
+   |
+LL | pub struct UninhabitedTupleStruct(!);
+   |            ^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `UninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/match_same_crate.rs:38:11
    |
-LL | / pub enum UninhabitedVariants {
-LL | |     #[non_exhaustive] Tuple(!),
-   | |                       ----- not covered
-LL | |     #[non_exhaustive] Struct { x: ! }
-   | |                       ------ not covered
-LL | | }
-   | |_- `UninhabitedVariants` defined here
-...
-LL |       match x {}
-   |             ^ patterns `Tuple(_)` and `Struct { .. }` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL |     match x {}
+   |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
+   |
+note: `UninhabitedVariants` defined here
+  --> $DIR/match_same_crate.rs:16:23
+   |
+LL | pub enum UninhabitedVariants {
+   |          -------------------
+LL |     #[non_exhaustive] Tuple(!),
+   |                       ^^^^^ not covered
+LL |     #[non_exhaustive] Struct { x: ! }
+   |                       ^^^^^^ not covered
    = note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~     match x {
+LL +         Tuple(_) | Struct { .. } => todo!(),
+LL ~     }
+   |
 
 error: aborting due to 3 previous errors
 
index cc3dc6c29b90461fad6f236e9c09b3261a5ecca4..e18c2678d323c2f4d60498067b71fc817171f02c 100644 (file)
@@ -4,8 +4,19 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedEnum` defined here
+  --> $DIR/auxiliary/uninhabited.rs:5:1
+   |
+LL | / pub enum UninhabitedEnum {
+LL | | }
+   | |_^
    = note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
   --> $DIR/match_with_exhaustive_patterns.rs:26:11
@@ -13,8 +24,20 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:9:1
+   |
+LL | / pub struct UninhabitedStruct {
+LL | |     _priv: !,
+LL | | }
+   | |_^
    = note: the matched value is of type `UninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
   --> $DIR/match_with_exhaustive_patterns.rs:30:11
@@ -22,8 +45,18 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empt
 LL |     match x {}
    |           ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedTupleStruct` defined here
+  --> $DIR/auxiliary/uninhabited.rs:14:1
+   |
+LL | pub struct UninhabitedTupleStruct(!);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: the matched value is of type `UninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match x {
+LL +         _ => todo!(),
+LL ~     }
+   |
 
 error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
   --> $DIR/match_with_exhaustive_patterns.rs:34:11
@@ -31,15 +64,23 @@ error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covere
 LL |     match x {}
    |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
    |
-  ::: $DIR/auxiliary/uninhabited.rs:17:23
+note: `UninhabitedVariants` defined here
+  --> $DIR/auxiliary/uninhabited.rs:17:23
    |
-LL |     #[non_exhaustive] Tuple(!),
-   |                       ----- not covered
-LL |     #[non_exhaustive] Struct { x: ! }
-   |                       ------ not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum UninhabitedVariants {
+LL | |     #[non_exhaustive] Tuple(!),
+   | |                       ^^^^^ not covered
+LL | |     #[non_exhaustive] Struct { x: ! }
+   | |                       ^^^^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~     match x {
+LL +         Tuple(_) | Struct { .. } => todo!(),
+LL ~     }
+   |
 
 error: aborting due to 4 previous errors
 
index 0291a52633358eeef277f3d4b32e06adf875a758..cf8ca57714c29e5b7ee68115a578ae3e32ed8a11 100644 (file)
@@ -1,27 +1,10 @@
 warning: skipping const checks
    |
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:9
-   |
-LL |     let ptr: fn() -> L = attributed;
-   |         ^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5
-   |
-LL |     ptr()
-   |     ^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:26
-   |
-LL |     let ptr: fn() -> L = attributed;
-   |                          ^^^^^^^^^^
 help: skipping check that does not even have a feature gate
   --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5
    |
 LL |     ptr()
    |     ^^^^^
 
-error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
-
-error: aborting due to previous error; 1 warning emitted
+warning: 1 warning emitted
 
index 897de54a7bf8cde5dbbc205c5026e8d3699200f1..dd090a3a5483df430da3edf6161f092f0353c6c1 100644 (file)
@@ -15,7 +15,7 @@ error: `let` expressions are not supported here
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -24,7 +24,7 @@ error: `let` expressions are not supported here
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -33,7 +33,7 @@ error: `let` expressions are not supported here
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -42,7 +42,7 @@ error: `let` expressions are not supported here
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -51,7 +51,7 @@ error: `let` expressions are not supported here
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -60,8 +60,13 @@ error: `let` expressions are not supported here
 LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:47:13
+   |
+LL |     if true || let 0 = 0 {}
+   |             ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:48:17
@@ -69,8 +74,13 @@ error: `let` expressions are not supported here
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:48:14
+   |
+LL |     if (true || let 0 = 0) {}
+   |              ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:49:25
@@ -78,8 +88,13 @@ error: `let` expressions are not supported here
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:49:22
+   |
+LL |     if true && (true || let 0 = 0) {}
+   |                      ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:50:25
@@ -87,8 +102,13 @@ error: `let` expressions are not supported here
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:50:13
+   |
+LL |     if true || (true && let 0 = 0) {}
+   |             ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:53:12
@@ -96,7 +116,7 @@ error: `let` expressions are not supported here
 LL |     if x = let 0 = 0 {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -105,7 +125,7 @@ error: `let` expressions are not supported here
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -114,7 +134,7 @@ error: `let` expressions are not supported here
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -123,7 +143,7 @@ error: `let` expressions are not supported here
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -132,7 +152,7 @@ error: `let` expressions are not supported here
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -141,7 +161,7 @@ error: `let` expressions are not supported here
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -150,7 +170,7 @@ error: `let` expressions are not supported here
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -159,7 +179,7 @@ error: `let` expressions are not supported here
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -168,7 +188,7 @@ error: `let` expressions are not supported here
 LL |     if let true = let true = true {}
    |                   ^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -177,7 +197,7 @@ error: `let` expressions are not supported here
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -186,7 +206,7 @@ error: `let` expressions are not supported here
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -195,7 +215,7 @@ error: `let` expressions are not supported here
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -204,7 +224,7 @@ error: `let` expressions are not supported here
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -213,7 +233,7 @@ error: `let` expressions are not supported here
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -222,8 +242,13 @@ error: `let` expressions are not supported here
 LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:111:16
+   |
+LL |     while true || let 0 = 0 {}
+   |                ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:112:20
@@ -231,8 +256,13 @@ error: `let` expressions are not supported here
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:112:17
+   |
+LL |     while (true || let 0 = 0) {}
+   |                 ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:113:28
@@ -240,8 +270,13 @@ error: `let` expressions are not supported here
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:113:25
+   |
+LL |     while true && (true || let 0 = 0) {}
+   |                         ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:114:28
@@ -249,8 +284,13 @@ error: `let` expressions are not supported here
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:114:16
+   |
+LL |     while true || (true && let 0 = 0) {}
+   |                ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:117:15
@@ -258,7 +298,7 @@ error: `let` expressions are not supported here
 LL |     while x = let 0 = 0 {}
    |               ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -267,7 +307,7 @@ error: `let` expressions are not supported here
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -276,7 +316,7 @@ error: `let` expressions are not supported here
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -285,7 +325,7 @@ error: `let` expressions are not supported here
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -294,7 +334,7 @@ error: `let` expressions are not supported here
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -303,7 +343,7 @@ error: `let` expressions are not supported here
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -312,7 +352,7 @@ error: `let` expressions are not supported here
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -321,7 +361,7 @@ error: `let` expressions are not supported here
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -330,7 +370,7 @@ error: `let` expressions are not supported here
 LL |     while let true = let true = true {}
    |                      ^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -339,7 +379,7 @@ error: `let` expressions are not supported here
 LL |     &let 0 = 0;
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -348,7 +388,7 @@ error: `let` expressions are not supported here
 LL |     !let 0 = 0;
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -357,7 +397,7 @@ error: `let` expressions are not supported here
 LL |     *let 0 = 0;
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -366,7 +406,7 @@ error: `let` expressions are not supported here
 LL |     -let 0 = 0;
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -375,7 +415,7 @@ error: `let` expressions are not supported here
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -384,8 +424,13 @@ error: `let` expressions are not supported here
 LL |     true || let 0 = 0;
    |             ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:184:10
+   |
+LL |     true || let 0 = 0;
+   |          ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:185:14
@@ -393,8 +438,13 @@ error: `let` expressions are not supported here
 LL |     (true || let 0 = 0);
    |              ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:185:11
+   |
+LL |     (true || let 0 = 0);
+   |           ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:186:22
@@ -402,8 +452,13 @@ error: `let` expressions are not supported here
 LL |     true && (true || let 0 = 0);
    |                      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
+note: `||` operators are not allowed in let chain expressions
+  --> $DIR/disallowed-positions.rs:186:19
+   |
+LL |     true && (true || let 0 = 0);
+   |                   ^^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:189:9
@@ -411,7 +466,7 @@ error: `let` expressions are not supported here
 LL |     x = let 0 = 0;
    |         ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -420,7 +475,7 @@ error: `let` expressions are not supported here
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -429,7 +484,7 @@ error: `let` expressions are not supported here
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -438,7 +493,7 @@ error: `let` expressions are not supported here
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -447,7 +502,7 @@ error: `let` expressions are not supported here
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -456,7 +511,7 @@ error: `let` expressions are not supported here
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -465,7 +520,7 @@ error: `let` expressions are not supported here
 LL |     &let 0 = 0
    |      ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -474,7 +529,7 @@ error: `let` expressions are not supported here
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -483,7 +538,7 @@ error: `let` expressions are not supported here
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -492,7 +547,7 @@ error: `let` expressions are not supported here
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
@@ -501,7 +556,7 @@ error: `let` expressions are not supported here
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
-   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: only supported directly in conditions of `if` and `while` expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error[E0308]: mismatched types
index 2d049277d7fcf44e1950d2e0fd9804e98f20f1c4..34934d1e01dbd430c097ad50bce6a212e4fdea86 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 pub trait MyTrait {
index 4b706a190e65e5985a7a3e3048ff0c1fa90e9426..89dc47aad3dd7a47f38cf5b32aa9221abaf38b6b 100644 (file)
@@ -1,5 +1,4 @@
 // check-pass
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 trait MyPartialEq {
index adf8d4f9ea565a208c3d92cd57416df8eb54b968..b00ff1f2fac2a0b8872e3a64b901d43a786b6b9b 100644 (file)
@@ -3,7 +3,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 struct S;
 
index cc24dbd96d2532ebc82c59a2e9fc4a7514891d86..c8ded0fa7ea32a4a6d5715663494d4df111a8683 100644 (file)
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 struct S;
 
index e81e0d1e571c32283e6ad127683f2c8fb97d363c..8df68225d44cd34c1b448fbfb39e0ea2c2ec5ff1 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
index 3963f64ad32b3b90b59cb9f2b9ae9b7588012b38..cf114334cc39187dbbbe1cbc5461cb8fa40bbd55 100644 (file)
@@ -1,17 +1,17 @@
 error[E0277]: can't compare `T` with `T` in const contexts
-  --> $DIR/call-generic-method-fail.rs:5:5
+  --> $DIR/call-generic-method-fail.rs:4:5
    |
 LL |     *t == *t
    |     ^^^^^^^^ no implementation for `T == T`
    |
 note: the trait `PartialEq` is implemented for `T`, but that implementation is not `const`
-  --> $DIR/call-generic-method-fail.rs:5:5
+  --> $DIR/call-generic-method-fail.rs:4:5
    |
 LL |     *t == *t
    |     ^^^^^^^^
 
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/call-generic-method-fail.rs:5:5
+  --> $DIR/call-generic-method-fail.rs:4:5
    |
 LL |     *t == *t
    |     ^^^^^^^^
index 585b65988f390ade606315e687ef8895e48fad73..e197c8b73c535e43484fa5da23579abbf7ff225a 100644 (file)
@@ -1,7 +1,5 @@
 // check-pass
 
-#![feature(const_fn_trait_bound)]
-
 struct S;
 
 impl PartialEq for S {
index 6881db0aa02c3cec75158117a2e856de518efd82..d3e14a53a2fc316e61632ed5cc9365f6995d2e09 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 struct S;
 
index 35b7fe8e401c3162b674e93169a3c6b9d3566ee5..b0af45acda1edc9a15fbf02bbfd1452ea7ef93c5 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: can't compare `S` with `S` in const contexts
-  --> $DIR/call-generic-method-nonconst.rs:19:34
+  --> $DIR/call-generic-method-nonconst.rs:18:34
    |
 LL | pub const EQ: bool = equals_self(&S);
    |                      ----------- ^^ no implementation for `S == S`
@@ -8,12 +8,12 @@ LL | pub const EQ: bool = equals_self(&S);
    |
    = help: the trait `~const PartialEq` is not implemented for `S`
 note: the trait `PartialEq` is implemented for `S`, but that implementation is not `const`
-  --> $DIR/call-generic-method-nonconst.rs:19:34
+  --> $DIR/call-generic-method-nonconst.rs:18:34
    |
 LL | pub const EQ: bool = equals_self(&S);
    |                                  ^^
 note: required by a bound in `equals_self`
-  --> $DIR/call-generic-method-nonconst.rs:12:25
+  --> $DIR/call-generic-method-nonconst.rs:11:25
    |
 LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
    |                         ^^^^^^^^^^^^^^^^ required by this bound in `equals_self`
index aa9bd4d824e1704aba419008433985d59c7f7727..40565d1b76a9c1cfd21fef07e53f18c7eef52073 100644 (file)
@@ -3,7 +3,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 struct S;
 
index 99e608797ff650c2c2b943c83d04d4acdb8084f0..755d853983949fa8bc69b254198338edd7366f5a 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 const fn answer_p1<F>(f: &F) -> u8
     where
index 3e87787a09195aedbdbc0fe420f33aad50a95663..3c82fe1ad6c77f589fa5304c53a6f93d592a065d 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)] // FIXME is this needed?
 
 trait ConstDefaultFn: Sized {
     fn b(self);
index 948830d6def58f7388ccf8d5859f74fe410947cd..fe788b43a5416b4330279af3a43c805930b8dfa9 100644 (file)
@@ -1,17 +1,17 @@
 error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
-  --> $DIR/const-default-method-bodies.rs:25:18
+  --> $DIR/const-default-method-bodies.rs:24:18
    |
 LL |     NonConstImpl.a();
    |                  ^^^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl`
    |
 note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const`
-  --> $DIR/const-default-method-bodies.rs:25:18
+  --> $DIR/const-default-method-bodies.rs:24:18
    |
 LL |     NonConstImpl.a();
    |                  ^^^
 
 error[E0015]: cannot call non-const fn `<NonConstImpl as ConstDefaultFn>::a` in constant functions
-  --> $DIR/const-default-method-bodies.rs:25:18
+  --> $DIR/const-default-method-bodies.rs:24:18
    |
 LL |     NonConstImpl.a();
    |                  ^^^
index 83fa32bf092bb9140c8404d06cf893e5f0e75bd9..a1cfee6b6e7827a0af36f3ec6d9f08502835caa8 100644 (file)
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 #![feature(const_precise_live_drops)]
 
 const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Drop {
index d280cd2556f06f6c0eeed84d923930f512e3b6a1..d88bcdc89ad2b617f760178abff15364983a7b90 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied
-  --> $DIR/const-drop-fail.rs:44:5
+  --> $DIR/const-drop-fail.rs:43:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
@@ -8,7 +8,7 @@ LL |     NonTrivialDrop,
    |     ^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+  --> $DIR/const-drop-fail.rs:34:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
@@ -20,7 +20,7 @@ LL |     &mut NonTrivialDrop,
    |     ++++
 
 error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied in `ConstImplWithDropGlue`
-  --> $DIR/const-drop-fail.rs:46:5
+  --> $DIR/const-drop-fail.rs:45:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
@@ -29,23 +29,23 @@ LL |     ConstImplWithDropGlue(NonTrivialDrop),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop`
    |
 note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const`
-  --> $DIR/const-drop-fail.rs:46:5
+  --> $DIR/const-drop-fail.rs:45:5
    |
 LL |     ConstImplWithDropGlue(NonTrivialDrop),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required because it appears within the type `ConstImplWithDropGlue`
-  --> $DIR/const-drop-fail.rs:17:8
+  --> $DIR/const-drop-fail.rs:16:8
    |
 LL | struct ConstImplWithDropGlue(NonTrivialDrop);
    |        ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+  --> $DIR/const-drop-fail.rs:34:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
 
 error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Drop` is not satisfied
-  --> $DIR/const-drop-fail.rs:48:5
+  --> $DIR/const-drop-fail.rs:47:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
@@ -54,12 +54,12 @@ LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |
 note: required because of the requirements on the impl of `~const Drop` for `ConstDropImplWithBounds<NonTrivialDrop>`
-  --> $DIR/const-drop-fail.rs:29:25
+  --> $DIR/const-drop-fail.rs:28:25
    |
 LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
    |                         ^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+  --> $DIR/const-drop-fail.rs:34:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
index 4622723c1891e7da872d12cb091b82ce4f82b612..49968b47dbeb0df4307e0fb94668077c1069bae5 100644 (file)
@@ -1,7 +1,6 @@
 // revisions: stock precise
 #![feature(const_trait_impl)]
 #![feature(const_mut_refs)]
-#![feature(const_fn_trait_bound)]
 #![cfg_attr(precise, feature(const_precise_live_drops))]
 
 use std::marker::PhantomData;
index d280cd2556f06f6c0eeed84d923930f512e3b6a1..d88bcdc89ad2b617f760178abff15364983a7b90 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied
-  --> $DIR/const-drop-fail.rs:44:5
+  --> $DIR/const-drop-fail.rs:43:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
@@ -8,7 +8,7 @@ LL |     NonTrivialDrop,
    |     ^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+  --> $DIR/const-drop-fail.rs:34:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
@@ -20,7 +20,7 @@ LL |     &mut NonTrivialDrop,
    |     ++++
 
 error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied in `ConstImplWithDropGlue`
-  --> $DIR/const-drop-fail.rs:46:5
+  --> $DIR/const-drop-fail.rs:45:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
@@ -29,23 +29,23 @@ LL |     ConstImplWithDropGlue(NonTrivialDrop),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop`
    |
 note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const`
-  --> $DIR/const-drop-fail.rs:46:5
+  --> $DIR/const-drop-fail.rs:45:5
    |
 LL |     ConstImplWithDropGlue(NonTrivialDrop),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required because it appears within the type `ConstImplWithDropGlue`
-  --> $DIR/const-drop-fail.rs:17:8
+  --> $DIR/const-drop-fail.rs:16:8
    |
 LL | struct ConstImplWithDropGlue(NonTrivialDrop);
    |        ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+  --> $DIR/const-drop-fail.rs:34:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
 
 error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Drop` is not satisfied
-  --> $DIR/const-drop-fail.rs:48:5
+  --> $DIR/const-drop-fail.rs:47:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
@@ -54,12 +54,12 @@ LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |
 note: required because of the requirements on the impl of `~const Drop` for `ConstDropImplWithBounds<NonTrivialDrop>`
-  --> $DIR/const-drop-fail.rs:29:25
+  --> $DIR/const-drop-fail.rs:28:25
    |
 LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
    |                         ^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:35:19
+  --> $DIR/const-drop-fail.rs:34:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
index 13363c506d54e573dbaed08a99f8604f85e680e6..20b9d7721472cb4cb29054785fb795f434c9fc24 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 // revisions: stock precise
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 #![feature(const_mut_refs)]
 #![feature(never_type)]
 #![cfg_attr(precise, feature(const_precise_live_drops))]
index bc807507fd6683fbf8deda4b6db4cc9aea466547..668e166c29897c2dd47e82b4b49ed6f7de638755 100644 (file)
@@ -1,16 +1,16 @@
 error[E0277]: the trait bound `(): ~const Tr` is not satisfied
-  --> $DIR/default-method-body-is-const-body-checking.rs:12:15
+  --> $DIR/default-method-body-is-const-body-checking.rs:11:15
    |
 LL |         foo::<()>();
    |               ^^ the trait `~const Tr` is not implemented for `()`
    |
 note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
-  --> $DIR/default-method-body-is-const-body-checking.rs:12:15
+  --> $DIR/default-method-body-is-const-body-checking.rs:11:15
    |
 LL |         foo::<()>();
    |               ^^
 note: required by a bound in `foo`
-  --> $DIR/default-method-body-is-const-body-checking.rs:7:28
+  --> $DIR/default-method-body-is-const-body-checking.rs:6:28
    |
 LL | const fn foo<T>() where T: ~const Tr {}
    |                            ^^^^^^^^^ required by this bound in `foo`
index db4d61f88ab2f08a85e66bae320e31da06633aa5..cf357971951df5aeef4d4276a4f19ec31927f513 100644 (file)
@@ -1,17 +1,17 @@
 error[E0277]: the trait bound `(): ~const Tr` is not satisfied
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
    |
 LL |         ().a()
    |            ^^^ the trait `~const Tr` is not implemented for `()`
    |
 note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
    |
 LL |         ().a()
    |            ^^^
 
 error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
    |
 LL |         ().a()
    |            ^^^
index d5b1a9073acea92b177c663d134bb5e154401f1b..7f6d86d337582fc6c860435eac518717c48336dc 100644 (file)
@@ -7,7 +7,6 @@
 
 #![feature(staged_api)]
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 #![stable(since = "1", feature = "foo")]
 
 trait Tr {
index 91c3d2d5920bc6675b625f86ace4209f335d169a..5495b531cff56c85978b8870ee0a4960f1a0afdc 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 use std::marker::PhantomData;
 
index 8eefb375b8c1b9346b1520f9a7c7abeb6c6996bd..eba8b665ceb0ec10299f7a9791dcfb84af1173d1 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 trait Tr {
     fn req(&self);
index a0916797041114b373ce94bbf1a541db340269fb..4ec6f929ffcd9a1bd99e6f6d479789bc395afc3e 100644 (file)
@@ -1,5 +1,5 @@
 error: const trait implementations may not use non-const default functions
-  --> $DIR/impl-with-default-fn-fail.rs:18:1
+  --> $DIR/impl-with-default-fn-fail.rs:17:1
    |
 LL | / impl const Tr for S {
 LL | |     fn req(&self) {}
@@ -9,7 +9,7 @@ LL | | }
    = note: `prov` not implemented
 
 error: const trait implementations may not use non-const default functions
-  --> $DIR/impl-with-default-fn-fail.rs:28:1
+  --> $DIR/impl-with-default-fn-fail.rs:27:1
    |
 LL | / impl const Tr for u32 {
 LL | |     fn req(&self) {}
@@ -20,7 +20,7 @@ LL | | }
    = note: `prov` not implemented
 
 error[E0046]: not all trait items implemented, missing: `req`
-  --> $DIR/impl-with-default-fn-fail.rs:22:1
+  --> $DIR/impl-with-default-fn-fail.rs:21:1
    |
 LL |     fn req(&self);
    |     -------------- `req` from trait
index ba3fec0882b02e306b3fd9919cfb1ca83d477a71..2e4664714a70ab8e74f9c6595488cba1ec276c37 100644 (file)
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 trait Tr {
     fn req(&self);
index fe1015b3bf7ee0549f7471612b01cc74f290a936..2cef803a90e0764ed7e96596643c7b230e7df38c 100644 (file)
@@ -1,6 +1,5 @@
 // check-pass
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 struct S;
 
index cbe3fe0ce5f3f461be5606e7687de5ef0ce92459..b132c395ac7b4f208bc6cdfc3a6b468d81f6e1d1 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 pub trait A {
index 931c0b3658fd9d4f0d26e30a29ca46fbc36b0256..955923505200a136397ba3a03bcfbde7da7dc3e6 100644 (file)
@@ -1,17 +1,17 @@
 error[E0277]: the trait bound `T: ~const A` is not satisfied
-  --> $DIR/issue-88155.rs:9:5
+  --> $DIR/issue-88155.rs:8:5
    |
 LL |     T::assoc()
    |     ^^^^^^^^^^ the trait `~const A` is not implemented for `T`
    |
 note: the trait `A` is implemented for `T`, but that implementation is not `const`
-  --> $DIR/issue-88155.rs:9:5
+  --> $DIR/issue-88155.rs:8:5
    |
 LL |     T::assoc()
    |     ^^^^^^^^^^
 
 error[E0015]: cannot call non-const fn `<T as A>::assoc` in constant functions
-  --> $DIR/issue-88155.rs:9:5
+  --> $DIR/issue-88155.rs:8:5
    |
 LL |     T::assoc()
    |     ^^^^^^^^^^
index 9bf0886084f912e577c0fe980560a5f1ed213ed9..da7147acdd7e9afe9b9fe45ac62357f18e56892b 100644 (file)
@@ -10,7 +10,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 pub trait Tr {}
 
index 158c628c3e0cb1638cdc4f62924fd163fc882cc3..97c27ce1a1cfa05cc1b783d150aa4583aa3238f0 100644 (file)
@@ -2,7 +2,6 @@
 //
 // check-pass
 
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 pub trait Super {}
index ef74ef8e426201133e055af0b4015ab3a80943c3..defef9e04098e55b43153e1389d4a2418ddd40a7 100644 (file)
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 trait Convert<T> {
     fn to(self) -> T;
index cbfdf89b7bd191817c4080cd2cce8b6bc7c9cfac..f4a5d0133ce89666af369f11b9ec9fe4f9d781db 100644 (file)
@@ -2,7 +2,6 @@
 
 #![feature(staged_api)]
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 #![feature(const_t_try)]
 #![feature(const_try)]
 #![feature(try_trait_v2)]
index 0cde5b6f84218951370ff4b47730b7659be77ef8..e47c5c7bd6665b1168d5a9aab997d3791f7926f5 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 trait Bar {
     fn bar() -> u8;
index ae9ab26cdc04ad708706007e9bc19e9dc742f512..acea58eaecb9ae9dc6725144e1b6086c9d5ce83d 100644 (file)
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
 
 trait Foo {
     fn bar() where Self: ~const Foo;
index d64822d7ce8af77a4d5296a668dfffe0c8551f5d..d37ed3bb8dd9a640ac9907f49e082772f653a9de 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 
 trait Bar {}
index f9b5d81c63b85a420c3c591456a1e8cc60fe8655..d5b2d269730967bdbcef68fce42a968058c8508e 100644 (file)
@@ -1,16 +1,16 @@
 error[E0277]: the trait bound `T: ~const Bar` is not satisfied
-  --> $DIR/trait-where-clause.rs:14:5
+  --> $DIR/trait-where-clause.rs:13:5
    |
 LL |     T::b();
    |     ^^^^ the trait `~const Bar` is not implemented for `T`
    |
 note: the trait `Bar` is implemented for `T`, but that implementation is not `const`
-  --> $DIR/trait-where-clause.rs:14:5
+  --> $DIR/trait-where-clause.rs:13:5
    |
 LL |     T::b();
    |     ^^^^
 note: required by a bound in `Foo::b`
-  --> $DIR/trait-where-clause.rs:8:24
+  --> $DIR/trait-where-clause.rs:7:24
    |
 LL |     fn b() where Self: ~const Bar;
    |                        ^^^^^^^^^^ required by this bound in `Foo::b`
@@ -20,18 +20,18 @@ LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() {
    |                                    ++++++++++++
 
 error[E0277]: the trait bound `T: ~const Bar` is not satisfied
-  --> $DIR/trait-where-clause.rs:16:5
+  --> $DIR/trait-where-clause.rs:15:5
    |
 LL |     T::c::<T>();
    |     ^^^^^^^^^ the trait `~const Bar` is not implemented for `T`
    |
 note: the trait `Bar` is implemented for `T`, but that implementation is not `const`
-  --> $DIR/trait-where-clause.rs:16:5
+  --> $DIR/trait-where-clause.rs:15:5
    |
 LL |     T::c::<T>();
    |     ^^^^^^^^^
 note: required by a bound in `Foo::c`
-  --> $DIR/trait-where-clause.rs:9:13
+  --> $DIR/trait-where-clause.rs:8:13
    |
 LL |     fn c<T: ~const Bar>();
    |             ^^^^^^^^^^ required by this bound in `Foo::c`
@@ -41,13 +41,13 @@ LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() {
    |                                    ++++++++++++
 
 error[E0277]: the trait bound `T: Bar` is not satisfied
-  --> $DIR/trait-where-clause.rs:28:5
+  --> $DIR/trait-where-clause.rs:27:5
    |
 LL |     T::b();
    |     ^^^^ the trait `Bar` is not implemented for `T`
    |
 note: required by a bound in `Foo::b`
-  --> $DIR/trait-where-clause.rs:8:24
+  --> $DIR/trait-where-clause.rs:7:24
    |
 LL |     fn b() where Self: ~const Bar;
    |                        ^^^^^^^^^^ required by this bound in `Foo::b`
@@ -57,13 +57,13 @@ LL | fn test3<T: Foo + Bar>() {
    |                 +++++
 
 error[E0277]: the trait bound `T: Bar` is not satisfied
-  --> $DIR/trait-where-clause.rs:30:5
+  --> $DIR/trait-where-clause.rs:29:5
    |
 LL |     T::c::<T>();
    |     ^^^^^^^^^ the trait `Bar` is not implemented for `T`
    |
 note: required by a bound in `Foo::c`
-  --> $DIR/trait-where-clause.rs:9:13
+  --> $DIR/trait-where-clause.rs:8:13
    |
 LL |     fn c<T: ~const Bar>();
    |             ^^^^^^^^^^ required by this bound in `Foo::c`
index de4058887cffd786bc2f9eb9cc09bf1673bcb94a..99c29dcdda6777f28e7d8d43438caf2a5881fdfc 100644 (file)
@@ -5,21 +5,21 @@
 #![stable(feature = "lint_stability", since = "1.0.0")]
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated() {}
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated_text() {}
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "99.99.99", reason = "text")]
+#[deprecated(since = "99.99.99", note = "text")]
 pub fn deprecated_future() {}
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated_unstable() {}
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub fn deprecated_unstable_text() {}
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -37,17 +37,17 @@ pub fn stable_text() {}
 
 impl MethodTester {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated(&self) {}
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated_unstable(&self) {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     pub fn method_deprecated_unstable_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -64,17 +64,17 @@ pub fn method_stable_text(&self) {}
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub trait Trait {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated(&self) {}
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated_unstable(&self) {}
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     fn trait_deprecated_unstable_text(&self) {}
 
     #[unstable(feature = "unstable_test_feature", issue = "none")]
@@ -93,7 +93,7 @@ pub trait TraitWithAssociatedTypes {
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     type TypeUnstable = u8;
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     type TypeDeprecated = u8;
 }
 
@@ -104,18 +104,18 @@ impl Trait for MethodTester {}
 pub trait UnstableTrait { fn dummy(&self) { } }
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub trait DeprecatedTrait {
     #[stable(feature = "stable_test_feature", since = "1.0.0")] fn dummy(&self) { }
 }
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedStruct {
     #[stable(feature = "stable_test_feature", since = "1.0.0")] pub i: isize
 }
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnstableStruct {
     #[stable(feature = "stable_test_feature", since = "1.0.0")] pub i: isize
 }
@@ -133,10 +133,10 @@ pub enum UnstableEnum {}
 pub enum StableEnum {}
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnitStruct;
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnstableUnitStruct;
 #[unstable(feature = "unstable_test_feature", issue = "none")]
 pub struct UnstableUnitStruct;
@@ -146,10 +146,10 @@ pub enum StableEnum {}
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub enum Enum {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     DeprecatedVariant,
     #[unstable(feature = "unstable_test_feature", issue = "none")]
-    #[rustc_deprecated(since = "1.0.0", reason = "text")]
+    #[deprecated(since = "1.0.0", note = "text")]
     DeprecatedUnstableVariant,
     #[unstable(feature = "unstable_test_feature", issue = "none")]
     UnstableVariant,
@@ -159,10 +159,10 @@ pub enum Enum {
 }
 
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
 #[unstable(feature = "unstable_test_feature", issue = "none")]
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
 #[unstable(feature = "unstable_test_feature", issue = "none")]
 pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
index 231ab966558f995ad4e7c5148ad04f123a1bce2c..1d6a6bd4e13fcbabaf21e3e8e636743d5ca1a2ec 100644 (file)
@@ -40,14 +40,14 @@ pub struct Struct3<A = isize, #[unstable(feature = "unstable_default", issue = "
     pub field2: B,
 }
 
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub struct Struct4<A = usize> {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
     pub field: A,
 }
 
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub struct Struct5<#[unstable(feature = "unstable_default", issue = "none")] A = usize> {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
@@ -99,7 +99,7 @@ pub enum Enum3<T = isize, #[unstable(feature = "unstable_default", issue = "none
     Err(#[stable(feature = "stable_test_feature", since = "1.0.0")] E),
 }
 
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub enum Enum4<T = usize> {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
@@ -108,7 +108,7 @@ pub enum Enum4<T = usize> {
     None,
 }
 
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub enum Enum5<#[unstable(feature = "unstable_default", issue = "none")] T = usize> {
     #[stable(feature = "stable_test_feature", since = "1.0.0")]
@@ -152,11 +152,11 @@ pub enum Enum6<#[unstable(feature = "unstable_default6", issue = "none")] T = us
 pub type Alias3<T = isize, #[unstable(feature = "unstable_default", issue = "none")] E = usize> =
     Result<T, E>;
 
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub type Alias4<T = usize> = Option<T>;
 
-#[rustc_deprecated(since = "1.1.0", reason = "test")]
+#[deprecated(since = "1.1.0", note = "test")]
 #[stable(feature = "stable_test_feature", since = "1.0.0")]
 pub type Alias5<#[unstable(feature = "unstable_default", issue = "none")] T = usize> = Option<T>;
 
index 1627d1d3f9f19312f3a125ae42cd996414d21b4f..f61acc8aac5db919b6376e1f9fafb188e9f24cc3 100644 (file)
@@ -2,6 +2,4 @@
 
 #[unstable()] //~ ERROR: stability attributes may not be used
 #[stable()] //~ ERROR: stability attributes may not be used
-#[rustc_deprecated()] //~ ERROR: stability attributes may not be used
-//~^ ERROR missing 'since'
 fn main() {}
index a2b2d3cbe595196388c8bf8ac4c470638e2082e0..45d965ea0a069a0d29c8ea062217c489820c8880 100644 (file)
@@ -10,19 +10,6 @@ error[E0734]: stability attributes may not be used outside of the standard libra
 LL | #[stable()]
    | ^^^^^^^^^^^
 
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/stability-attribute-non-staged-force-unstable.rs:5:1
-   |
-LL | #[rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/stability-attribute-non-staged-force-unstable.rs:5:1
-   |
-LL | #[rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0542, E0734.
-For more information about an error, try `rustc --explain E0542`.
+For more information about this error, try `rustc --explain E0734`.
index dfbd9ea5ebf2e5150c4a91a90dd2d0200f1674a0..4015f2f971e696f25ce21e9e0469c14217f5db73 100644 (file)
@@ -1,5 +1,3 @@
 #[unstable()] //~ ERROR: stability attributes may not be used
 #[stable()] //~ ERROR: stability attributes may not be used
-#[rustc_deprecated()] //~ ERROR: stability attributes may not be used
-//~^ ERROR missing 'since'
 fn main() {}
index 9af8d1df4ea040bb390700f56b4dd78d033f4ac9..391f3c2744d3cb77478e79bccdf3a96d1ecbdccb 100644 (file)
@@ -10,19 +10,6 @@ error[E0734]: stability attributes may not be used outside of the standard libra
 LL | #[stable()]
    | ^^^^^^^^^^^
 
-error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/stability-attribute-non-staged.rs:3:1
-   |
-LL | #[rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0542]: missing 'since'
-  --> $DIR/stability-attribute-non-staged.rs:3:1
-   |
-LL | #[rustc_deprecated()]
-   | ^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0542, E0734.
-For more information about an error, try `rustc --explain E0542`.
+For more information about this error, try `rustc --explain E0734`.
index b85f9342045a01cf9a1a5448a123bc462dca5e2b..64f996352196a8406dfb034623dcf954de8df536 100644 (file)
@@ -18,13 +18,11 @@ fn f3() { }
     fn f4() { }
 
     #[stable(feature = "a", since = "b")]
-    #[rustc_deprecated] //~ ERROR malformed `rustc_deprecated` attribute
-                        //~^ ERROR missing 'since'
+    #[deprecated] //~ ERROR missing 'since'
     fn f5() { }
 
     #[stable(feature = "a", since = "b")]
-    #[rustc_deprecated = "a"] //~ ERROR malformed `rustc_deprecated` attribute
-                              //~^ ERROR missing 'since'
+    #[deprecated = "a"] //~ ERROR missing 'since'
     fn f6() { }
 }
 
index 651f293ff519e31e92b6a37258a132bf6f00ba45..a76f5be1e3d7c428f312e286d35f030ae8a127d2 100644 (file)
@@ -22,30 +22,18 @@ error: malformed `stable` attribute input
 LL |     #[stable = "a"]
    |     ^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]`
 
-error: malformed `rustc_deprecated` attribute input
-  --> $DIR/stability-attribute-sanity-4.rs:21:5
-   |
-LL |     #[rustc_deprecated]
-   |     ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_deprecated(since = "version", reason = "...")]`
-
-error: malformed `rustc_deprecated` attribute input
-  --> $DIR/stability-attribute-sanity-4.rs:26:5
-   |
-LL |     #[rustc_deprecated = "a"]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_deprecated(since = "version", reason = "...")]`
-
 error[E0542]: missing 'since'
   --> $DIR/stability-attribute-sanity-4.rs:21:5
    |
-LL |     #[rustc_deprecated]
-   |     ^^^^^^^^^^^^^^^^^^^
+LL |     #[deprecated]
+   |     ^^^^^^^^^^^^^
 
 error[E0542]: missing 'since'
-  --> $DIR/stability-attribute-sanity-4.rs:26:5
+  --> $DIR/stability-attribute-sanity-4.rs:25:5
    |
-LL |     #[rustc_deprecated = "a"]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[deprecated = "a"]
+   |     ^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0542`.
index fe8079dbc3701d5c7c2a708c93b1fb4afa6e4f33..f37a8f328a75ae3e839ac8a18195191597d5223e 100644 (file)
@@ -37,11 +37,11 @@ mod missing_version {
     fn f1() { }
 
     #[stable(feature = "a", since = "b")]
-    #[rustc_deprecated(reason = "a")] //~ ERROR missing 'since' [E0542]
+    #[deprecated(note = "a")] //~ ERROR missing 'since' [E0542]
     fn f2() { }
 
     #[stable(feature = "a", since = "b")]
-    #[rustc_deprecated(since = "a")] //~ ERROR missing 'reason' [E0543]
+    #[deprecated(since = "a")] //~ ERROR missing 'note' [E0543]
     fn f3() { }
 }
 
@@ -58,19 +58,19 @@ fn multiple2() { }
 fn multiple3() { }
 
 #[stable(feature = "a", since = "b")] //~ ERROR invalid stability version found
-#[rustc_deprecated(since = "b", reason = "text")]
-#[rustc_deprecated(since = "b", reason = "text")] //~ ERROR multiple deprecated attributes
+#[deprecated(since = "b", note = "text")]
+#[deprecated(since = "b", note = "text")] //~ ERROR multiple deprecated attributes
 #[rustc_const_unstable(feature = "c", issue = "none")]
 #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels
 pub const fn multiple4() { }
 
 #[stable(feature = "a", since = "1.0.0")] //~ ERROR invalid deprecation version found
 //~^ ERROR feature `a` is declared stable since 1.0.0
-#[rustc_deprecated(since = "invalid", reason = "text")]
+#[deprecated(since = "invalid", note = "text")]
 fn invalid_deprecation_version() {}
 
-#[rustc_deprecated(since = "a", reason = "text")]
+#[deprecated(since = "a", note = "text")]
 fn deprecated_without_unstable_or_stable() { }
-//~^^ ERROR rustc_deprecated attribute must be paired with either stable or unstable attribute
+//~^^ ERROR deprecated attribute must be paired with either stable or unstable attribute
 
 fn main() { }
index b4e8fc78815497d2b5e5eb63d98b2946b97fd35f..9e2d9f2708489c57489fd1c8265c36723f53215b 100644 (file)
@@ -55,14 +55,14 @@ LL |     #[stable(feature = "a")]
 error[E0542]: missing 'since'
   --> $DIR/stability-attribute-sanity.rs:40:5
    |
-LL |     #[rustc_deprecated(reason = "a")]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[deprecated(note = "a")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0543]: missing 'reason'
+error[E0543]: missing 'note'
   --> $DIR/stability-attribute-sanity.rs:44:5
    |
-LL |     #[rustc_deprecated(since = "a")]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[deprecated(since = "a")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0544]: multiple stability levels
   --> $DIR/stability-attribute-sanity.rs:49:1
@@ -85,10 +85,10 @@ LL | #[stable(feature = "a", since = "b")]
 error[E0550]: multiple deprecated attributes
   --> $DIR/stability-attribute-sanity.rs:62:1
    |
-LL | #[rustc_deprecated(since = "b", reason = "text")]
-   | ------------------------------------------------- first deprecation attribute
-LL | #[rustc_deprecated(since = "b", reason = "text")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ repeated deprecation attribute
+LL | #[deprecated(since = "b", note = "text")]
+   | ----------------------------------------- first deprecation attribute
+LL | #[deprecated(since = "b", note = "text")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ repeated deprecation attribute
 
 error[E0544]: multiple stability levels
   --> $DIR/stability-attribute-sanity.rs:64:1
@@ -114,11 +114,11 @@ LL | #[stable(feature = "a", since = "1.0.0")]
 LL | fn invalid_deprecation_version() {}
    | ----------------------------------- the stability attribute annotates this item
 
-error[E0549]: rustc_deprecated attribute must be paired with either stable or unstable attribute
+error[E0549]: deprecated attribute must be paired with either stable or unstable attribute
   --> $DIR/stability-attribute-sanity.rs:72:1
    |
-LL | #[rustc_deprecated(since = "a", reason = "text")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[deprecated(since = "a", note = "text")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0711]: feature `a` is declared stable since 1.0.0, but was previously declared stable since b
   --> $DIR/stability-attribute-sanity.rs:67:1
index 9c3c3646139dc2ec955f70a2570e08d08a621b91..9ab409bbdcdf8e9282935b145a6973064fea4979 100644 (file)
@@ -23,8 +23,8 @@ LL |     let _ = s.get(4);
 note: required by a bound in `core::str::<impl str>::get`
   --> $SRC_DIR/core/src/str/mod.rs:LL:COL
    |
-LL |     pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
-   |                   ^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get`
+LL |     pub const fn get<I: ~const SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
+   |                         ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get`
 
 error[E0277]: the type `str` cannot be indexed by `{integer}`
   --> $DIR/str-idx.rs:5:29
@@ -40,8 +40,8 @@ LL |     let _ = s.get_unchecked(4);
 note: required by a bound in `core::str::<impl str>::get_unchecked`
   --> $SRC_DIR/core/src/str/mod.rs:LL:COL
    |
-LL |     pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
-   |                                    ^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked`
+LL |     pub const unsafe fn get_unchecked<I: ~const SliceIndex<str>>(&self, i: I) -> &I::Output {
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked`
 
 error[E0277]: the type `str` cannot be indexed by `char`
   --> $DIR/str-idx.rs:6:17
index 2559ee9eb49b25f3ff0ad8c8ed4a7c12f9aff049..5956e363b0c09b2bb5a7a7da21888b296786f246 100644 (file)
@@ -47,8 +47,8 @@ LL |     s.get_mut(1);
 note: required by a bound in `core::str::<impl str>::get_mut`
   --> $SRC_DIR/core/src/str/mod.rs:LL:COL
    |
-LL |     pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
-   |                       ^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_mut`
+LL |     pub const fn get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
+   |                             ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_mut`
 
 error[E0277]: the type `str` cannot be indexed by `{integer}`
   --> $DIR/str-mut-idx.rs:11:25
@@ -64,8 +64,8 @@ LL |     s.get_unchecked_mut(1);
 note: required by a bound in `core::str::<impl str>::get_unchecked_mut`
   --> $SRC_DIR/core/src/str/mod.rs:LL:COL
    |
-LL |     pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
-   |                                        ^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked_mut`
+LL |     pub const unsafe fn get_unchecked_mut<I: ~const SliceIndex<str>>(
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::<impl str>::get_unchecked_mut`
 
 error[E0277]: the type `str` cannot be indexed by `char`
   --> $DIR/str-mut-idx.rs:13:5
index 28c319b659765ccbf1bef51cde2b85e12017a248..1059e3d1525aa779fc659c3ad4dbb991fe0f376e 100644 (file)
@@ -13,16 +13,17 @@ LL |     let a = vec![1, 2, 3];
    |         - move occurs because `a` has type `Vec<i32>`, which does not implement the `Copy` trait
 LL |     for i in &a {
 LL |         for j in a {
-   |                  ^
-   |                  |
-   |                  `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
-   |                  help: consider borrowing to avoid moving into the for loop: `&a`
+   |                  ^ `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
    |
 note: this function takes ownership of the receiver `self`, which moves `a`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider iterating over a slice of the `Vec<i32>`'s content to avoid moving into the `for` loop
+   |
+LL |         for j in &a {
+   |                  +
 
 error: aborting due to 2 previous errors
 
index c39363f762bdd8ee26aab0d62fd8e5e94f905446..88be9e30a764125261b822c14a6e7c761d4d26a2 100644 (file)
@@ -2,9 +2,17 @@ error[E0507]: cannot move out of `self.v` which is behind a shared reference
   --> $DIR/for-i-in-vec.rs:11:18
    |
 LL |         for _ in self.v {
-   |                  ^^^^^^ move occurs because `self.v` has type `Vec<u32>`, which does not implement the `Copy` trait
+   |                  ^^^^^^
+   |                  |
+   |                  `self.v` moved due to this implicit call to `.into_iter()`
+   |                  move occurs because `self.v` has type `Vec<u32>`, which does not implement the `Copy` trait
    |
-help: consider iterating over a slice of the `Vec<u32>`'s content
+note: this function takes ownership of the receiver `self`, which moves `self.v`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
+help: consider iterating over a slice of the `Vec<u32>`'s content to avoid moving into the `for` loop
    |
 LL |         for _ in &self.v {
    |                  +
@@ -13,9 +21,12 @@ error[E0507]: cannot move out of `self.h` which is behind a shared reference
   --> $DIR/for-i-in-vec.rs:13:18
    |
 LL |         for _ in self.h {
-   |                  ^^^^^^ move occurs because `self.h` has type `HashMap<i32, i32>`, which does not implement the `Copy` trait
+   |                  ^^^^^^
+   |                  |
+   |                  `self.h` moved due to this implicit call to `.into_iter()`
+   |                  move occurs because `self.h` has type `HashMap<i32, i32>`, which does not implement the `Copy` trait
    |
-help: consider iterating over a slice of the `HashMap<i32, i32>`'s content
+help: consider iterating over a slice of the `HashMap<i32, i32>`'s content to avoid moving into the `for` loop
    |
 LL |         for _ in &self.h {
    |                  +
@@ -24,9 +35,17 @@ error[E0507]: cannot move out of a shared reference
   --> $DIR/for-i-in-vec.rs:21:19
    |
 LL |     for loader in *LOADERS {
-   |                   ^^^^^^^^ move occurs because value has type `Vec<&u8>`, which does not implement the `Copy` trait
+   |                   ^^^^^^^^
+   |                   |
+   |                   value moved due to this implicit call to `.into_iter()`
+   |                   move occurs because value has type `Vec<&u8>`, which does not implement the `Copy` trait
+   |
+note: this function takes ownership of the receiver `self`, which moves value
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
-help: consider iterating over a slice of the `Vec<&u8>`'s content
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
+help: consider iterating over a slice of the `Vec<&u8>`'s content to avoid moving into the `for` loop
    |
 LL |     for loader in &*LOADERS {
    |                   +
index a0ce7d05b4d48efecc2aa29787f701d344254ba9..16cbbaba512a4e0c0fe58b505ebc1f872f5bb2bb 100644 (file)
@@ -12,8 +12,8 @@ LL | |
 LL | |             var = Some(NotCopyable);
    | |             ---
    | |             |
+   | |             variable moved due to use in closure
    | |             move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait
-   | |             move occurs due to use in closure
 LL | |         }
 LL | |     });
    | |_____- captured by this `FnMut` closure
diff --git a/src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.rs b/src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.rs
new file mode 100644 (file)
index 0000000..56aed77
--- /dev/null
@@ -0,0 +1,30 @@
+struct Wrapper<T>(T);
+
+fn foo<T>(foo: Wrapper<T>)
+//~^ ERROR the size for values of type `T` cannot be known at compilation time
+where
+    T
+    :
+    ?
+    Sized
+{
+    //
+}
+
+fn bar<T>(foo: Wrapper<T>)
+//~^ ERROR the size for values of type `T` cannot be known at compilation time
+where T: ?Sized
+{
+    //
+}
+
+fn qux<T>(foo: Wrapper<T>)
+//~^ ERROR the size for values of type `T` cannot be known at compilation time
+where
+    T: ?Sized
+{
+    //
+}
+
+
+fn main() {}
diff --git a/src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.stderr b/src/test/ui/suggestions/removal-of-multiline-trait-bound-in-where-clause.stderr
new file mode 100644 (file)
index 0000000..3df1705
--- /dev/null
@@ -0,0 +1,83 @@
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:3:16
+   |
+LL | fn foo<T>(foo: Wrapper<T>)
+   |        -       ^^^^^^^^^^ doesn't have a size known at compile-time
+   |        |
+   |        this type parameter needs to be `std::marker::Sized`
+   |
+note: required by a bound in `Wrapper`
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+   |
+LL | struct Wrapper<T>(T);
+   |                ^ required by this bound in `Wrapper`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+   |
+LL | struct Wrapper<T>(T);
+   |                ^  - ...if indirection were used here: `Box<T>`
+   |                |
+   |                this could be changed to `T: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - where
+LL -     T
+LL -     :
+LL -     ?
+LL -     Sized
+   | 
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:14:16
+   |
+LL | fn bar<T>(foo: Wrapper<T>)
+   |        -       ^^^^^^^^^^ doesn't have a size known at compile-time
+   |        |
+   |        this type parameter needs to be `std::marker::Sized`
+   |
+note: required by a bound in `Wrapper`
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+   |
+LL | struct Wrapper<T>(T);
+   |                ^ required by this bound in `Wrapper`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+   |
+LL | struct Wrapper<T>(T);
+   |                ^  - ...if indirection were used here: `Box<T>`
+   |                |
+   |                this could be changed to `T: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - where T: ?Sized
+   | 
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:21:16
+   |
+LL | fn qux<T>(foo: Wrapper<T>)
+   |        -       ^^^^^^^^^^ doesn't have a size known at compile-time
+   |        |
+   |        this type parameter needs to be `std::marker::Sized`
+   |
+note: required by a bound in `Wrapper`
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+   |
+LL | struct Wrapper<T>(T);
+   |                ^ required by this bound in `Wrapper`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:1:16
+   |
+LL | struct Wrapper<T>(T);
+   |                ^  - ...if indirection were used here: `Box<T>`
+   |                |
+   |                this could be changed to `T: ?Sized`...
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - where
+LL -     T: ?Sized
+   | 
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/tuple/wrong_argument_ice-4.rs b/src/test/ui/tuple/wrong_argument_ice-4.rs
new file mode 100644 (file)
index 0000000..479bd0d
--- /dev/null
@@ -0,0 +1,6 @@
+fn main() {
+    (|| {})(|| {
+        //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+        let b = 1;
+    });
+}
diff --git a/src/test/ui/tuple/wrong_argument_ice-4.stderr b/src/test/ui/tuple/wrong_argument_ice-4.stderr
new file mode 100644 (file)
index 0000000..fef5dca
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0057]: this function takes 0 arguments but 1 argument was supplied
+  --> $DIR/wrong_argument_ice-4.rs:2:5
+   |
+LL |       (|| {})(|| {
+   |  _____^^^^^^^_-
+   | |     |
+   | |     expected 0 arguments
+LL | |
+LL | |         let b = 1;
+LL | |     });
+   | |_____- supplied 1 argument
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0057`.
index 747081933172b50aca38ca1e5efeaca93a347e5b..4baf198b12fae9251139cd00db67c64a0fec14d5 100644 (file)
@@ -5,7 +5,7 @@
 fn main() {}
 
 type Two<A, B> = impl Debug;
-//~^ ERROR the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
+//~^ ERROR the trait bound `A: Foo` is not satisfied
 //~| ERROR `A` doesn't implement `Debug`
 //~| ERROR `B` doesn't implement `Debug`
 
index a8eb53a50e38bb33d99f2256d7c3d58739878055..43471f980b2afe545f3eba8392b8e5d8bc54a044 100644 (file)
@@ -10,13 +10,12 @@ note: previous use here
 LL | fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0277]: the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
+error[E0277]: the trait bound `A: Foo` is not satisfied
   --> $DIR/generic_duplicate_param_use9.rs:7:18
    |
 LL | type Two<A, B> = impl Debug;
-   |                  ^^^^^^^^^^ within `(A, B, <A as Foo>::Bar)`, the trait `Foo` is not implemented for `A`
+   |                  ^^^^^^^^^^ the trait `Foo` is not implemented for `A`
    |
-   = note: required because it appears within the type `(A, B, <A as Foo>::Bar)`
 help: consider restricting type parameter `A`
    |
 LL | type Two<A: Foo, B> = impl Debug;
@@ -28,7 +27,7 @@ error[E0277]: `A` doesn't implement `Debug`
 LL | type Two<A, B> = impl Debug;
    |                  ^^^^^^^^^^ `A` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
-   = note: required because of the requirements on the impl of `Debug` for `(A, B, <A as Foo>::Bar)`
+   = note: required because of the requirements on the impl of `Debug` for `(A, B, _)`
 help: consider restricting type parameter `A`
    |
 LL | type Two<A: std::fmt::Debug, B> = impl Debug;
@@ -40,7 +39,7 @@ error[E0277]: `B` doesn't implement `Debug`
 LL | type Two<A, B> = impl Debug;
    |                  ^^^^^^^^^^ `B` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
-   = note: required because of the requirements on the impl of `Debug` for `(A, B, <A as Foo>::Bar)`
+   = note: required because of the requirements on the impl of `Debug` for `(A, B, _)`
 help: consider restricting type parameter `B`
    |
 LL | type Two<A, B: std::fmt::Debug> = impl Debug;
index 792bd16527be83bde6ac9a00826a3c3ee037e6fc..007dcf3bcb6800d466d3f466909c0a1a7437e7bc 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(const_impl_trait, const_fn_fn_ptr_basics, rustc_attrs)]
+#![feature(rustc_attrs)]
 #![feature(type_alias_impl_trait)]
 
 type Foo = impl Fn() -> usize;
index 176118200e5eda77159ddc43e42ed367e3934fb7..a3f126d56cf204c6cc704a636b389d85d73ef99f 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(const_impl_trait, generators, generator_trait, rustc_attrs)]
+#![feature(generators, generator_trait, rustc_attrs)]
 #![feature(type_alias_impl_trait)]
 
 use std::ops::Generator;
index 5878b26fddbc78453ae0dde1501c75a310f9a9d3..f058653dde3389a2a75a3889993d068b74e01939 100644 (file)
@@ -5,8 +5,7 @@
 use std::future::Future;
 
 type G<'a, T> = impl Future<Output = ()>;
-//~^ ERROR: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
-//~| ERROR: the trait bound `T: Trait` is not satisfied
+//~^ ERROR: the trait bound `T: Trait` is not satisfied
 
 trait Trait {
     type F: Future<Output = ()>;
index 19ed9a7476c1b872bded84d1f988665a2067bfca..0df5a809ebb4748908995fc6e66da8039fef9b91 100644 (file)
@@ -1,22 +1,3 @@
-error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
-  --> $DIR/issue-89686.rs:7:17
-   |
-LL | type G<'a, T> = impl Future<Output = ()>;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
-...
-LL |         async move { self.f().await }
-   |                    ------------------ the found `async` block
-   |
-  ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
-   |
-LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
-   |                                           ------------------------------- the found opaque type
-   |
-   = note:    expected unit type `()`
-           found associated type `<impl Future<Output = [async output]> as Future>::Output`
-   = help: consider constraining the associated type `<impl Future<Output = [async output]> as Future>::Output` to `()`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
 error[E0277]: the trait bound `T: Trait` is not satisfied
   --> $DIR/issue-89686.rs:7:17
    |
@@ -28,7 +9,6 @@ help: consider restricting type parameter `T`
 LL | type G<'a, T: Trait> = impl Future<Output = ()>;
    |             +++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0277.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0277`.
index 51a7b6454c35ef3189deb551f1a578b3e16d2dda..219837aa04baba2ff3ac12c8a835792215660ce9 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(const_impl_trait)]
 #![feature(type_alias_impl_trait)]
 
 type Bar = impl Send;
index 7e41b374452a3c2a9f99a40c9096e3e9cd51f1a5..889c4fd4b040556184b8dca4d8019f5486144b22 100644 (file)
@@ -1,5 +1,5 @@
 error: `impl Send` cannot be used in patterns
-  --> $DIR/structural-match-no-leak.rs:15:9
+  --> $DIR/structural-match-no-leak.rs:14:9
    |
 LL |         LEAK_FREE => (),
    |         ^^^^^^^^^
index 73558d39ad56163a69a0fa30840a9f31885d8414..c9e669cad603a963639d3b22ae96924fffa4c0b5 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(const_impl_trait)]
 #![feature(type_alias_impl_trait)]
 
 type Foo = impl Send;
index b43f2148dea5ec84c4abe5e24a08a38325286aa8..262fd0726137e63c9547b43ea4977c99070bd147 100644 (file)
@@ -1,5 +1,5 @@
 error: `impl Send` cannot be used in patterns
-  --> $DIR/structural-match.rs:16:9
+  --> $DIR/structural-match.rs:15:9
    |
 LL |         VALUE => (),
    |         ^^^^^
index 5c82a56e77e141731ded61892979bc2829a5f485..ea1edf7d45073bba79f19dc573111079c4eb6aab 100644 (file)
@@ -1,3 +1,5 @@
+// check-pass
+
 #![feature(unboxed_closures)]
 
 trait Lt<'a> {
@@ -10,6 +12,5 @@ impl<'a> Lt<'a> for () {
 fn main() {
     let v: <() as Lt<'_>>::T = ();
     let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {};
-    //~^ ERROR: the size for values of type `<() as Lt<'_>>::T` cannot be known
     f(v);
 }
diff --git a/src/test/ui/unboxed-closures/issue-53448.stderr b/src/test/ui/unboxed-closures/issue-53448.stderr
deleted file mode 100644 (file)
index 8f9d918..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0277]: the size for values of type `<() as Lt<'_>>::T` cannot be known at compilation time
-  --> $DIR/issue-53448.rs:12:54
-   |
-LL |     let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {};
-   |                                                      ^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `<() as Lt<'_>>::T`
-   = help: unsized fn params are gated as an unstable feature
-help: consider further restricting the associated type
-   |
-LL | fn main() where <() as Lt<'_>>::T: Sized {
-   |           ++++++++++++++++++++++++++++++
-help: function arguments must have a statically known size, borrowed types always have a known size
-   |
-LL |     let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: &<() as Lt<'_>>::T| {};
-   |                                                         +
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
index 48cd92719b49ab51198e56727c30abd90b39ed79..661b5486adc122ca9cfe4f19d17ee0625f654304 100644 (file)
@@ -19,10 +19,10 @@ enum Foo {
     A(foo::SecretlyEmpty),
     B(foo::NotSoSecretlyEmpty),
     C(NotSoSecretlyEmpty),
-    D(u32),
+    D(u32, u32),
 }
 
 fn main() {
-    let x: Foo = Foo::D(123);
-    let Foo::D(_y) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
+    let x: Foo = Foo::D(123, 456);
+    let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
 }
index 3cb9955674800e3d095cfc39649925a873394205..c571e17a7b372516a801b64476dec81bfae86fde 100644 (file)
@@ -1,25 +1,27 @@
 error[E0005]: refutable pattern in local binding: `A(_)` not covered
   --> $DIR/uninhabited-irrefutable.rs:27:9
    |
-LL | / enum Foo {
-LL | |     A(foo::SecretlyEmpty),
-   | |     - not covered
-LL | |     B(foo::NotSoSecretlyEmpty),
-LL | |     C(NotSoSecretlyEmpty),
-LL | |     D(u32),
-LL | | }
-   | |_- `Foo` defined here
-...
-LL |       let Foo::D(_y) = x;
-   |           ^^^^^^^^^^ pattern `A(_)` not covered
+LL |     let Foo::D(_y, _z) = x;
+   |         ^^^^^^^^^^^^^^ pattern `A(_)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Foo` defined here
+  --> $DIR/uninhabited-irrefutable.rs:19:5
+   |
+LL | enum Foo {
+   |      ---
+LL |     A(foo::SecretlyEmpty),
+   |     ^ not covered
    = note: the matched value is of type `Foo`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Foo::D(_y) = x { /* */ }
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     let (_y, _z) = if let Foo::D(_y, _z) = x { (_y, _z) } else { todo!() };
+   |     +++++++++++++++++                        +++++++++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+   |
+LL |     let Foo::D(_y, _z) = x else { todo!() };
+   |                            ++++++++++++++++
 
 error: aborting due to previous error
 
index b92ceb479bd3b3b2c15a05fbb0698b12c02348a1..74216d265d03416e218903443c3a6c5d46a9ef0c 100644 (file)
@@ -4,26 +4,44 @@ error[E0004]: non-exhaustive patterns: `Err(_)` not covered
 LL |     let _ = match x {
    |                   ^ pattern `Err(_)` not covered
    |
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+note: `Result<u32, &Void>` defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | / pub enum Result<T, E> {
+LL | |     /// Contains the success value
+LL | |     #[lang = "Ok"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+   | |     ^^^ not covered
+LL | | }
+   | |_-
+   = note: the matched value is of type `Result<u32, &Void>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
-   |     --- not covered
+LL ~         Ok(n) => n,
+LL ~         Err(_) => todo!(),
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Result<u32, &Void>`
 
 error[E0004]: non-exhaustive patterns: type `&Void` is non-empty
   --> $DIR/uninhabited-matches-feature-gated.rs:15:19
    |
-LL | enum Void {}
-   | ------------ `Void` defined here
-...
 LL |     let _ = match x {};
    |                   ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Void` defined here
+  --> $DIR/uninhabited-matches-feature-gated.rs:2:6
+   |
+LL | enum Void {}
+   |      ^^^^
    = note: the matched value is of type `&Void`
    = note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     let _ = match x {
+LL +         _ => todo!(),
+LL ~     };
+   |
 
 error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty
   --> $DIR/uninhabited-matches-feature-gated.rs:18:19
@@ -31,8 +49,13 @@ error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty
 LL |     let _ = match x {};
    |                   ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(Void,)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     let _ = match x {
+LL +         _ => todo!(),
+LL ~     };
+   |
 
 error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty
   --> $DIR/uninhabited-matches-feature-gated.rs:21:19
@@ -40,8 +63,13 @@ error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty
 LL |     let _ = match x {};
    |                   ^
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `[Void; 1]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     let _ = match x {
+LL +         _ => todo!(),
+LL ~     };
+   |
 
 error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
   --> $DIR/uninhabited-matches-feature-gated.rs:24:19
@@ -49,8 +77,12 @@ error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
 LL |     let _ = match x {
    |                   ^ pattern `&[_, ..]` not covered
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[Void]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         &[] => (),
+LL ~         &[_, ..] => todo!(),
+   |
 
 error[E0004]: non-exhaustive patterns: `Err(_)` not covered
   --> $DIR/uninhabited-matches-feature-gated.rs:32:19
@@ -58,13 +90,24 @@ error[E0004]: non-exhaustive patterns: `Err(_)` not covered
 LL |     let _ = match x {
    |                   ^ pattern `Err(_)` not covered
    |
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
+note: `Result<u32, Void>` defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | / pub enum Result<T, E> {
+LL | |     /// Contains the success value
+LL | |     #[lang = "Ok"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+   | |     ^^^ not covered
+LL | | }
+   | |_-
+   = note: the matched value is of type `Result<u32, Void>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
-   |     --- not covered
+LL ~         Ok(x) => x,
+LL ~         Err(_) => todo!(),
    |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `Result<u32, Void>`
 
 error[E0005]: refutable pattern in local binding: `Err(_)` not covered
   --> $DIR/uninhabited-matches-feature-gated.rs:37:9
@@ -72,18 +115,29 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
 LL |     let Ok(x) = x;
    |         ^^^^^ pattern `Err(_)` not covered
    |
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
-   |     --- not covered
-   |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Result<u32, Void>` defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL | / pub enum Result<T, E> {
+LL | |     /// Contains the success value
+LL | |     #[lang = "Ok"]
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+...  |
+LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+   | |     ^^^ not covered
+LL | | }
+   | |_-
    = note: the matched value is of type `Result<u32, Void>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
-LL |     if let Ok(x) = x { /* */ }
+LL |     let x = if let Ok(x) = x { x } else { todo!() };
+   |     ++++++++++               ++++++++++++++++++++++
+help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
    |
+LL |     let Ok(x) = x else { todo!() };
+   |                   ++++++++++++++++
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs
new file mode 100644 (file)
index 0000000..80e30f2
--- /dev/null
@@ -0,0 +1,4 @@
+// check-pass
+// compile-flags: -Aunknown_lints -Atest_unstable_lint
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs
new file mode 100644 (file)
index 0000000..992472c
--- /dev/null
@@ -0,0 +1,5 @@
+// check-pass
+
+#![allow(unknown_lints, test_unstable_lint)]
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs
new file mode 100644 (file)
index 0000000..dcc0685
--- /dev/null
@@ -0,0 +1,6 @@
+// check-fail
+// compile-flags: -Dunknown_lints -Atest_unstable_lint
+// error-pattern: unknown lint: `test_unstable_lint`
+// error-pattern: the `test_unstable_lint` lint is unstable
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr
new file mode 100644 (file)
index 0000000..7e6885b
--- /dev/null
@@ -0,0 +1,18 @@
+error: unknown lint: `test_unstable_lint`
+   |
+   = note: requested on the command line with `-D unknown-lints`
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs
new file mode 100644 (file)
index 0000000..c6c60b1
--- /dev/null
@@ -0,0 +1,9 @@
+// check-fail
+
+#![deny(unknown_lints)]
+#![allow(test_unstable_lint)]
+//~^ ERROR unknown lint: `test_unstable_lint`
+//~| ERROR unknown lint: `test_unstable_lint`
+//~| ERROR unknown lint: `test_unstable_lint`
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr
new file mode 100644 (file)
index 0000000..2d1027d
--- /dev/null
@@ -0,0 +1,34 @@
+error: unknown lint: `test_unstable_lint`
+  --> $DIR/deny-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/deny-unstable-lint-inline.rs:3:9
+   |
+LL | #![deny(unknown_lints)]
+   |         ^^^^^^^^^^^^^
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+  --> $DIR/deny-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+  --> $DIR/deny-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs
new file mode 100644 (file)
index 0000000..3778291
--- /dev/null
@@ -0,0 +1,6 @@
+// check-pass
+// compile-flags: -Wunknown_lints -Atest_unstable_lint
+// error-pattern: unknown lint: `test_unstable_lint`
+// error-pattern: the `test_unstable_lint` lint is unstable
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr
new file mode 100644 (file)
index 0000000..799d740
--- /dev/null
@@ -0,0 +1,18 @@
+warning: unknown lint: `test_unstable_lint`
+   |
+   = note: requested on the command line with `-W unknown-lints`
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: 3 warnings emitted
+
diff --git a/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs
new file mode 100644 (file)
index 0000000..f4247e4
--- /dev/null
@@ -0,0 +1,9 @@
+// check-pass
+
+#![warn(unknown_lints)]
+#![allow(test_unstable_lint)]
+//~^ WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr
new file mode 100644 (file)
index 0000000..142558b
--- /dev/null
@@ -0,0 +1,34 @@
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/warn-unknown-unstable-lint-inline.rs:3:9
+   |
+LL | #![warn(unknown_lints)]
+   |         ^^^^^^^^^^^^^
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: 3 warnings emitted
+
index 3d6970d50e30e797b8e26b2b9b1bdf92dc381f34..65c82664263feddc5fe2d424be0993c28d46377a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3d6970d50e30e797b8e26b2b9b1bdf92dc381f34
+Subproject commit 65c82664263feddc5fe2d424be0993c28d46377a
index 5cc5530f874dd63e275f54d8832bf33ffd003e44..d4ca9480bec6231158a5e6eceab4503dbb42512e 100644 (file)
@@ -43,7 +43,7 @@ rustc-workspace-hack = "1.0"
 clippy_utils = { path = "clippy_utils" }
 derive-new = "0.5"
 if_chain = "1.0"
-itertools = "0.10"
+itertools = "0.10.1"
 quote = "1.0"
 serde = { version = "1.0", features = ["derive"] }
 syn = { version = "1.0", features = ["full"] }
index d350d9a001827e899b183fc19bcf5952eb43bb29..d133e8cddabc729b96ec2d2617401a771883660a 100644 (file)
@@ -7,7 +7,7 @@ edition = "2021"
 bytecount = "0.6"
 clap = "2.33"
 indoc = "1.0"
-itertools = "0.10"
+itertools = "0.10.1"
 opener = "0.5"
 regex = "1.5"
 shell-escape = "0.1"
index 40d7dd702628f77c47475290ad312c3e5b0160d1..66e61660d313aa150e1fcbb9106fce4d83bc7ffe 100644 (file)
@@ -12,7 +12,7 @@ edition = "2021"
 cargo_metadata = "0.14"
 clippy_utils = { path = "../clippy_utils" }
 if_chain = "1.0"
-itertools = "0.10"
+itertools = "0.10.1"
 pulldown-cmark = { version = "0.9", default-features = false }
 quine-mc_cluskey = "0.2"
 regex-syntax = "0.6"
index bad9e0be82e61e026a25b715d2b20e50d18c960a..ecc9acf4445d03681bfc1a0e28ce1257abf99974 100644 (file)
@@ -3,6 +3,7 @@
 use clippy_utils::ty::has_drop;
 use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method};
 use rustc_hir as hir;
+use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
@@ -131,6 +132,18 @@ fn check_fn(
             FnKind::Closure => return,
         }
 
+        // Const fns are not allowed as methods in a trait.
+        {
+            let parent = cx.tcx.hir().get_parent_item(hir_id);
+            if parent != CRATE_DEF_ID {
+                if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent) {
+                    if let hir::ItemKind::Trait(..) = &item.kind {
+                        return;
+                    }
+                }
+            }
+        }
+
         let mir = cx.tcx.optimized_mir(def_id);
 
         if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv.as_ref()) {
index b3988973256c4c16cad3c8306c6e43cf4916b062..1f134be2cbc886339c47584cb5bf471eabdeb10e 100644 (file)
@@ -543,10 +543,10 @@ fn into_map(
                 continue;
             }
 
-            let borrowers = self.possible_borrower.reachable_from(&row);
+            let borrowers = self.possible_borrower.reachable_from(row);
             if !borrowers.is_empty() {
                 let mut bs = HybridBitSet::new_empty(self.body.local_decls.len());
-                for &c in borrowers {
+                for c in borrowers {
                     if c != mir::Local::from_usize(0) {
                         bs.insert(c);
                     }
@@ -663,10 +663,10 @@ fn into_map(self, cx: &LateContext<'tcx>) -> FxHashMap<mir::Local, HybridBitSet<
                 continue;
             }
 
-            let borrowers = self.possible_origin.reachable_from(&row);
+            let borrowers = self.possible_origin.reachable_from(row);
             if !borrowers.is_empty() {
                 let mut bs = HybridBitSet::new_empty(self.body.local_decls.len());
-                for &c in borrowers {
+                for c in borrowers {
                     if c != mir::Local::from_usize(0) {
                         bs.insert(c);
                     }
index 05eadab3e6ccdcc500f881b62668bbc1a53a2a08..81076776ed3d333ad00dc1271fa17ff199a6fc70 100644 (file)
@@ -326,7 +326,7 @@ fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty);
         if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
         then {
-            layout.layout.size.bytes() == 0
+            layout.layout.size().bytes() == 0
         } else {
             false
         }
index d40583c47dd7074a8c069c0656652fdcf4652509..42b9e692d3ff4cbcf5198ffd29f3a8ef49805ca4 100644 (file)
@@ -593,7 +593,7 @@ pub fn miri_to_const(result: ty::Const<'_>) -> Option<Constant> {
         ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty().kind() {
             ty::Ref(_, tam, _) => match tam.kind() {
                 ty::Str => String::from_utf8(
-                    data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
+                    data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end)
                         .to_owned(),
                 )
                 .ok()
@@ -605,7 +605,7 @@ pub fn miri_to_const(result: ty::Const<'_>) -> Option<Constant> {
         ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty().kind() {
             ty::Array(sub_type, len) => match sub_type.kind() {
                 ty::Float(FloatTy::F32) => match miri_to_const(*len) {
-                    Some(Constant::Int(len)) => alloc
+                    Some(Constant::Int(len)) => alloc.inner()
                         .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
                         .to_owned()
                         .chunks(4)
@@ -619,7 +619,7 @@ pub fn miri_to_const(result: ty::Const<'_>) -> Option<Constant> {
                     _ => None,
                 },
                 ty::Float(FloatTy::F64) => match miri_to_const(*len) {
-                    Some(Constant::Int(len)) => alloc
+                    Some(Constant::Int(len)) => alloc.inner()
                         .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
                         .to_owned()
                         .chunks(8)
index 397783e309e85b135e5c1d4c25b25e86e1b34219..8c14f0dd761a20be5e0dd7a318aa53085a8911fe 100644 (file)
@@ -489,7 +489,8 @@ fn find_primitive(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
     fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
         tcx.crates(())
             .iter()
-            .find(|&&num| tcx.crate_name(num).as_str() == name)
+            .copied()
+            .find(|&num| tcx.crate_name(num).as_str() == name)
             .map(CrateNum::as_def_id)
     }
 
index c039fec955db9d2641fc86e43ce772da69f04021..891531951c1a03c0f6f5a3947544a04297151fcf 100644 (file)
@@ -32,32 +32,12 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv:
                 | ty::PredicateKind::Projection(_)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::Trait(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
                 ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
                 ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
                 ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
                 ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate),
-                ty::PredicateKind::Trait(pred) => {
-                    if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
-                        continue;
-                    }
-                    match pred.self_ty().kind() {
-                        ty::Param(ref p) => {
-                            let generics = tcx.generics_of(current);
-                            let def = generics.type_param(p, tcx);
-                            let span = tcx.def_span(def.def_id);
-                            return Err((
-                                span,
-                                "trait bounds other than `Sized` \
-                                 on const fn parameters are unstable"
-                                    .into(),
-                            ));
-                        },
-                        // other kinds of bounds are either tautologies
-                        // or cause errors in other passes
-                        _ => continue,
-                    }
-                },
             }
         }
         match predicates.parent {
index baa7eec05462ebad8baea0762ed76b51ae7dfa2d..88f6935d224aec502122cc5ebf5e06d8b70a0a7f 100644 (file)
@@ -49,8 +49,6 @@ fn sub(x: u32) -> usize {
     unsafe { transmute(&x) }
 }
 
-// NOTE: This is currently not yet allowed to be const
-// Once implemented, Clippy should be able to suggest this as const, too.
 fn generic_arr<T: Copy>(t: [T; 1]) -> T {
     t[0]
 }
index b89cc6451bb592c5f3f6fbbab1daa194953d5101..3eb52b6827475d1b52f189cb0f876c68e6dc8191 100644 (file)
@@ -58,7 +58,15 @@ LL | | }
    | |_^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:67:9
+  --> $DIR/could_be_const.rs:52:1
+   |
+LL | / fn generic_arr<T: Copy>(t: [T; 1]) -> T {
+LL | |     t[0]
+LL | | }
+   | |_^
+
+error: this could be a `const fn`
+  --> $DIR/could_be_const.rs:65:9
    |
 LL | /         pub fn b(self, a: &A) -> B {
 LL | |             B
@@ -66,12 +74,12 @@ LL | |         }
    | |_________^
 
 error: this could be a `const fn`
-  --> $DIR/could_be_const.rs:77:5
+  --> $DIR/could_be_const.rs:75:5
    |
 LL | /     fn const_fn_stabilized_before_msrv(byte: u8) {
 LL | |         byte.is_ascii_digit();
 LL | |     }
    | |_____^
 
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
 
index 46daaf42883f026a2e675247ae3fd3c4c6f79d12..c9b1649200d9cb2a8c7a21fd2983f5027f172cf8 100644 (file)
@@ -489,16 +489,22 @@ fn is_exception(file: &Path, link: &str) -> bool {
 /// If the given HTML file contents is an HTML redirect, this returns the
 /// destination path given in the redirect.
 fn maybe_redirect(source: &str) -> Option<String> {
-    const REDIRECT: &str = "<p>Redirecting to <a href=";
+    const REDIRECT_RUSTDOC: (usize, &str) = (7, "<p>Redirecting to <a href=");
+    const REDIRECT_MDBOOK: (usize, &str) = (8 - 7, "<p>Redirecting to... <a href=");
 
     let mut lines = source.lines();
-    let redirect_line = lines.nth(7)?;
 
-    redirect_line.find(REDIRECT).map(|i| {
-        let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
-        let pos_quote = rest.find('"').unwrap();
-        rest[..pos_quote].to_owned()
-    })
+    let mut find_redirect = |(line_rel, redirect_pattern): (usize, &str)| {
+        let redirect_line = lines.nth(line_rel)?;
+
+        redirect_line.find(redirect_pattern).map(|i| {
+            let rest = &redirect_line[(i + redirect_pattern.len() + 1)..];
+            let pos_quote = rest.find('"').unwrap();
+            rest[..pos_quote].to_owned()
+        })
+    };
+
+    find_redirect(REDIRECT_RUSTDOC).or_else(|| find_redirect(REDIRECT_MDBOOK))
 }
 
 fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(source: &str, attr: &str, mut f: F) {
index 54b14b7f0110133477e7459a327a0a5cbd18fd41..722475ccc143d2dbf9fad5891207dcb5576e3d17 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 54b14b7f0110133477e7459a327a0a5cbd18fd41
+Subproject commit 722475ccc143d2dbf9fad5891207dcb5576e3d17
index 4e72700e38421a12993fe5fa5c33d712652bc6c8..5fae65dd28b450a437ebc800a410164c3af1d516 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 4e72700e38421a12993fe5fa5c33d712652bc6c8
+Subproject commit 5fae65dd28b450a437ebc800a410164c3af1d516
index 32340ec7eecf2de70ce21723ea0ec2ade91c9e54..841c0f2b9395e1db1564020d74ac52f27b481eec 100644 (file)
@@ -138,7 +138,7 @@ async function main(argv) {
     try {
         // This is more convenient that setting fields one by one.
         let args = [
-            "--no-screenshot",
+            "--no-screenshot-comparison",
             "--variable", "DOC_PATH", opts["doc_folder"],
         ];
         if (opts["debug"]) {
index 8d9c4a7fb20cd93264f5459a7997cb9ca7cbc4df..764714638a9787c214227c4580ea4203442f071f 100644 (file)
@@ -33,7 +33,7 @@ rustfmt-format-diff = []
 generic-simd = ["bytecount/generic-simd"]
 
 [dependencies]
-itertools = "0.9"
+itertools = "0.10.1"
 toml = "0.5"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
index 1d5ec5c31c67ff326e35a48c86be0a5e335b5930..503df53704793f3d212af4b36ca5929ed8670300 100644 (file)
@@ -117,7 +117,7 @@ pub fn check(path: &Path, bad: &mut bool) {
                         .stderr(Stdio::null())
                         .output()
                         .unwrap_or_else(|e| {
-                            panic!("could not run git ls-files: {}", e);
+                            panic!("could not run git ls-files: {e}");
                         });
                     let path_bytes = rel_path.as_os_str().as_bytes();
                     if output.status.success() && output.stdout.starts_with(path_bytes) {
index 52429fee46150f9c4f1acea967a6d63794fde3f3..d6e36c2e7db402d049d49d4225ff4130de83d084 100644 (file)
@@ -340,8 +340,8 @@ fn check_exceptions(
                 }
                 Some(pkg_license) => {
                     if pkg_license.as_str() != *license {
-                        println!("dependency exception `{}` license has changed", name);
-                        println!("    previously `{}` now `{}`", license, pkg_license);
+                        println!("dependency exception `{name}` license has changed");
+                        println!("    previously `{license}` now `{pkg_license}`");
                         println!("    update EXCEPTIONS for the new license");
                         *bad = true;
                     }
@@ -418,7 +418,7 @@ fn check_dependencies(
     if !unapproved.is_empty() {
         tidy_error!(bad, "Dependencies not explicitly permitted:");
         for dep in unapproved {
-            println!("* {}", dep);
+            println!("* {dep}");
         }
     }
 }
@@ -501,7 +501,7 @@ fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package
         .nodes
         .iter()
         .find(|n| &n.id == pkg_id)
-        .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
+        .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
     node.deps
         .iter()
         .map(|dep| {
@@ -516,8 +516,8 @@ fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package
 fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
     let mut i = metadata.packages.iter().filter(|p| p.name == name);
     let result =
-        i.next().unwrap_or_else(|| panic!("could not find package `{}` in package list", name));
-    assert!(i.next().is_none(), "more than one package found for `{}`", name);
+        i.next().unwrap_or_else(|| panic!("could not find package `{name}` in package list"));
+    assert!(i.next().is_none(), "more than one package found for `{name}`");
     result
 }
 
@@ -545,7 +545,7 @@ fn normal_deps_of_r<'a>(
         .nodes
         .iter()
         .find(|n| &n.id == pkg_id)
-        .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
+        .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
     for dep in &node.deps {
         normal_deps_of_r(resolve, &dep.pkg, result);
     }
index f6be550283a21876c66f6cc8b8014650a9af9abc..281773b0569c531315e43e95f58a6b03bdeec6cf 100644 (file)
@@ -260,7 +260,7 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
 
         for (err_code, error_status) in &error_codes {
             if !error_status.has_test && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
-                errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
+                errors.push(format!("Error code {err_code} needs to have at least one UI test!"));
             } else if error_status.has_test && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
                 errors.push(format!(
                     "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
@@ -309,7 +309,7 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
     }
     errors.sort();
     for err in &errors {
-        eprintln!("{}", err);
+        eprintln!("{err}");
     }
     println!("Found {} error(s) in error codes", errors.len());
     if !errors.is_empty() {
index 9b6037c6a4ba7b0c5105f6f51d1346016dcca472..2f22c081a54b5a784de2a502c4dd8affa01f626d 100644 (file)
@@ -157,7 +157,7 @@ pub fn check(
         .collect::<Vec<_>>();
 
     for &(name, _) in gate_untested.iter() {
-        println!("Expected a gate test for the feature '{}'.", name);
+        println!("Expected a gate test for the feature '{name}'.");
         println!(
             "Hint: create a failing test file named 'feature-gate-{}.rs'\
                 \n      in the 'ui' test suite, with its failures due to\
@@ -186,7 +186,7 @@ pub fn check(
 
         lines.sort();
         for line in lines {
-            println!("* {}", line);
+            println!("* {line}");
         }
     } else {
         println!("* {} features", features.len());
@@ -221,7 +221,7 @@ fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
         "issue" => &*ISSUE,
         "feature" => &*FEATURE,
         "since" => &*SINCE,
-        _ => unimplemented!("{} not handled", attr),
+        _ => unimplemented!("{attr} not handled"),
     };
 
     r.captures(line).and_then(|c| c.get(1)).map(|m| m.as_str())
@@ -231,7 +231,7 @@ fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool {
     let prefix = "feature_gate_";
     if filen_underscore.starts_with(prefix) {
         for (n, f) in features.iter_mut() {
-            // Equivalent to filen_underscore == format!("feature_gate_{}", n)
+            // Equivalent to filen_underscore == format!("feature_gate_{n}")
             if &filen_underscore[prefix.len()..] == n {
                 f.has_gate_test = true;
                 return true;
index 8476650d9b5f726e0c2884add732f8667859cbdd..f3200e0afd71a88bd543fd8f9dd84b01dc0b313e 100644 (file)
@@ -8,10 +8,10 @@ pub fn check(library_path: &Path, bad: &mut bool) {
     let std_name = "std/src/primitive_docs.rs";
     let core_name = "core/src/primitive_docs.rs";
     let std_contents = std::fs::read_to_string(library_path.join(std_name))
-        .unwrap_or_else(|e| panic!("failed to read library/{}: {}", std_name, e));
+        .unwrap_or_else(|e| panic!("failed to read library/{std_name}: {e}"));
     let core_contents = std::fs::read_to_string(library_path.join(core_name))
-        .unwrap_or_else(|e| panic!("failed to read library/{}: {}", core_name, e));
+        .unwrap_or_else(|e| panic!("failed to read library/{core_name}: {e}"));
     if std_contents != core_contents {
-        tidy_error!(bad, "library/{} and library/{} have different contents", core_name, std_name);
+        tidy_error!(bad, "library/{core_name} and library/{std_name} have different contents");
     }
 }
index c197acd4828a143ee57fcd2b38e0578155abcb48..9861cba410df29cf4f01c1f4d1e2b6ae99aab2ce 100644 (file)
@@ -153,9 +153,9 @@ fn contains_ignore_directive(can_contain: bool, contents: &str, check: &str) ->
         return Directive::Deny;
     }
     // Update `can_contain` when changing this
-    if contents.contains(&format!("// ignore-tidy-{}", check))
-        || contents.contains(&format!("# ignore-tidy-{}", check))
-        || contents.contains(&format!("/* ignore-tidy-{} */", check))
+    if contents.contains(&format!("// ignore-tidy-{check}"))
+        || contents.contains(&format!("# ignore-tidy-{check}"))
+        || contents.contains(&format!("/* ignore-tidy-{check} */"))
     {
         Directive::Ignore(false)
     } else {
@@ -294,7 +294,7 @@ fn skip(path: &Path) -> bool {
                 suppressible_tidy_err!(
                     err,
                     skip_line_length,
-                    &format!("line longer than {} chars", max_columns)
+                    &format!("line longer than {max_columns} chars")
                 );
             }
             if !is_style_file && line.contains('\t') {
@@ -381,7 +381,7 @@ fn skip(path: &Path) -> bool {
             n => suppressible_tidy_err!(
                 err,
                 skip_trailing_newlines,
-                &format!("too many trailing newlines ({})", n)
+                &format!("too many trailing newlines ({n})")
             ),
         };
         if lines > LINES {
index 8e1749196d2ec5927675b98b072b4231b8e40ca5..723684bfa4cdafc9b75d9455d5e4fbacc66dced3 100644 (file)
@@ -20,7 +20,7 @@ fn iter_header<'a>(contents: &'a str, it: &mut dyn FnMut(Option<&'a str>, &'a st
                 let lncfg = &ln[open_brace + 1..close_brace];
                 it(Some(lncfg), ln[(close_brace + 1)..].trim_start());
             } else {
-                panic!("malformed condition directive: expected `//[foo]`, found `{}`", ln)
+                panic!("malformed condition directive: expected `//[foo]`, found `{ln}`")
             }
         } else if ln.starts_with(COMMENT) {
             it(None, ln[COMMENT.len()..].trim_start());
@@ -61,7 +61,7 @@ pub fn check(path: &Path, bad: &mut bool) {
                             let info = header_map.entry(cfg).or_insert(RevisionInfo::default());
                             info.target_arch.replace(arch);
                         } else {
-                            eprintln!("{}: seems to have a malformed --target value", file);
+                            eprintln!("{file}: seems to have a malformed --target value");
                             *bad = true;
                         }
                     }
index 218e9668df4ae60ce6ec08672aa6e2485f01344a..4720ee7020f89bf8a6b8f0c4bfb6dc9610442b68 100644 (file)
@@ -277,7 +277,7 @@ fn main() {
 
     for (name, contents) in modules {
         table_file.push_str("#[rustfmt::skip]\n");
-        table_file.push_str(&format!("pub mod {} {{\n", name));
+        table_file.push_str(&format!("pub mod {name} {{\n"));
         for line in contents.lines() {
             if !line.trim().is_empty() {
                 table_file.push_str("    ");
@@ -290,7 +290,7 @@ fn main() {
 
     std::fs::write(&write_location, format!("{}\n", table_file.trim_end())).unwrap();
 
-    println!("Total table sizes: {} bytes", total_bytes);
+    println!("Total table sizes: {total_bytes} bytes");
 }
 
 fn version() -> String {
@@ -308,7 +308,7 @@ fn version() -> String {
         readme[start..end].split('.').map(|v| v.parse::<u32>().expect(&v)).collect::<Vec<_>>();
     let [major, minor, micro] = [version[0], version[1], version[2]];
 
-    out.push_str(&format!("({}, {}, {});\n", major, minor, micro));
+    out.push_str(&format!("({major}, {minor}, {micro});\n"));
     out
 }
 
@@ -322,7 +322,7 @@ fn fmt_list<V: std::fmt::Debug>(values: impl IntoIterator<Item = V>) -> String {
         } else {
             out.push_str(line.trim_end());
             out.push('\n');
-            line = format!("    {}", piece);
+            line = format!("    {piece}");
         }
     }
     out.push_str(line.trim_end());
@@ -335,7 +335,7 @@ fn generate_tests(data_path: &str, ranges: &[(&str, Vec<Range<u32>>)]) -> String
     s.push_str("#![allow(incomplete_features, unused)]\n");
     s.push_str("#![feature(const_generics)]\n\n");
     s.push_str("\n#[allow(unused)]\nuse std::hint;\n");
-    s.push_str(&format!("#[path = \"{}\"]\n", data_path));
+    s.push_str(&format!("#[path = \"{data_path}\"]\n"));
     s.push_str("mod unicode_data;\n\n");
 
     s.push_str("\nfn main() {\n");
index fa57f650ac082706d11bbdd8bd3e6148b22ec3b1..9b2e0a25891c737480283ef1bd029b6f0129052e 100644 (file)
@@ -13,13 +13,12 @@ pub fn fetch_latest() {
     let directory = Path::new(UNICODE_DIRECTORY);
     if directory.exists() {
         eprintln!(
-            "Not refetching unicode data, already exists, please delete {:?} to regenerate",
-            directory
+            "Not refetching unicode data, already exists, please delete {directory:?} to regenerate",
         );
         return;
     }
     if let Err(e) = std::fs::create_dir_all(directory) {
-        panic!("Failed to create {:?}: {}", UNICODE_DIRECTORY, e);
+        panic!("Failed to create {UNICODE_DIRECTORY:?}: {e}");
     }
     let output = Command::new("curl").arg(URL_PREFIX.to_owned() + README).output().unwrap();
     if !output.status.success() {
index e10f72a47b2c427d73011f7024e0d8cd7fb33c01..5a0477b4b941e614c49dd3062703ae5a7a950bc1 100644 (file)
@@ -67,7 +67,7 @@ fn generate_unstable_book_files(src: &Path, out: &Path, features: &Features) {
     t!(fs::create_dir_all(&out));
     for feature_name in &unstable_features - &unstable_section_file_names {
         let feature_name_underscore = feature_name.replace('-', "_");
-        let file_name = format!("{}.md", feature_name);
+        let file_name = format!("{feature_name}.md");
         let out_file_path = out.join(&file_name);
         let feature = &features[&feature_name_underscore];
 
index 6c0311433d676a98a9771ae55011bdde04452c78..8c47559b36939e3e438ac1a67a7c0ee97e38ed95 100644 (file)
@@ -58,7 +58,7 @@ fn main() {
     let current = match env::current_dir() {
         Ok(dir) => dir,
         Err(err) => {
-            eprintln!("Failed to get current directory: {}", err);
+            eprintln!("Failed to get current directory: {err}");
             process::exit(1);
         }
     };
index 276587e7f13fb44357688411c4a2b3f3316bdcf7..f6f1b918f061f30a107e5c1ae71ea556f852d7c4 100644 (file)
@@ -73,6 +73,13 @@ Thanks! <3
 """
 label = "O-riscv"
 
+[ping.fuchsia]
+message = """\
+Hey friends of Fuchsia! This issue could use some guidance on how this should be
+resolved/implemented on Fuchsia. Could one of you weigh in?
+"""
+label = "O-fuchsia"
+
 [prioritize]
 label = "I-prioritize"