]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #101635 - jyn514:queries-new-derived, r=cjgillot
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>
Sat, 10 Sep 2022 13:26:10 +0000 (18:56 +0530)
committerGitHub <noreply@github.com>
Sat, 10 Sep 2022 13:26:10 +0000 (18:56 +0530)
Move `Queries::new` out of the macro

Split out from https://github.com/rust-lang/rust/pull/101178 to make sure it's not contributing to the perf impact.

r? `@cjgillot`

1331 files changed:
Cargo.lock
RELEASES.md
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/attr/mod.rs
compiler/rustc_ast_lowering/src/asm.rs
compiler/rustc_ast_lowering/src/block.rs
compiler/rustc_ast_lowering/src/errors.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_lowering/src/pat.rs
compiler/rustc_ast_lowering/src/path.rs
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_ast_passes/src/errors.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_borrowck/src/dataflow.rs
compiler/rustc_borrowck/src/diagnostics/region_name.rs
compiler/rustc_borrowck/src/invalidation.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_cranelift/src/discriminant.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_gcc/src/common.rs
compiler/rustc_codegen_llvm/src/abi.rs
compiler/rustc_codegen_llvm/src/common.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
compiler/rustc_codegen_llvm/src/llvm/ffi.rs
compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
compiler/rustc_codegen_ssa/src/mir/operand.rs
compiler/rustc_codegen_ssa/src/mir/place.rs
compiler/rustc_codegen_ssa/src/mir/rvalue.rs
compiler/rustc_codegen_ssa/src/mir/statement.rs
compiler/rustc_codegen_ssa/src/traits/consts.rs
compiler/rustc_const_eval/src/const_eval/machine.rs
compiler/rustc_const_eval/src/const_eval/valtrees.rs
compiler/rustc_const_eval/src/interpret/intrinsics.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/interpret/step.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/validate.rs
compiler/rustc_data_structures/src/obligation_forest/mod.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl
compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
compiler/rustc_error_messages/locales/en-US/infer.ftl
compiler/rustc_error_messages/locales/en-US/parser.ftl
compiler/rustc_error_messages/locales/en-US/session.ftl
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir/src/pat_util.rs
compiler/rustc_hir/src/target.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_infer/src/errors.rs [deleted file]
compiler/rustc_infer/src/errors/mod.rs [new file with mode: 0644]
compiler/rustc_infer/src/errors/note_and_explain.rs [new file with mode: 0644]
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/outlives/verify.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_lexer/src/lib.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/late.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint/src/passes.rs
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_metadata/src/native_libs.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_metadata/src/rmeta/table.rs
compiler/rustc_middle/src/arena.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/metadata.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/spanview.rs
compiler/rustc_middle/src/mir/syntax.rs
compiler/rustc_middle/src/mir/terminator.rs
compiler/rustc_middle/src/mir/visit.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/ty/assoc.rs
compiler/rustc_middle/src/ty/consts/kind.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/flags.rs
compiler/rustc_middle/src/ty/generics.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/parameterized.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_middle/src/ty/visit.rs
compiler/rustc_middle/src/ty/walk.rs
compiler/rustc_middle/src/values.rs [new file with mode: 0644]
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/thir/pattern/mod.rs
compiler/rustc_mir_dataflow/src/impls/liveness.rs
compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
compiler/rustc_mir_dataflow/src/move_paths/builder.rs
compiler/rustc_mir_transform/src/check_unsafety.rs
compiler/rustc_mir_transform/src/coverage/spans.rs
compiler/rustc_mir_transform/src/dead_store_elimination.rs
compiler/rustc_mir_transform/src/dest_prop.rs
compiler/rustc_mir_transform/src/generator.rs
compiler/rustc_mir_transform/src/lower_intrinsics.rs
compiler/rustc_mir_transform/src/pass_manager.rs
compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
compiler/rustc_mir_transform/src/separate_const_switch.rs
compiler/rustc_mir_transform/src/simplify.rs
compiler/rustc_monomorphize/src/lib.rs
compiler/rustc_monomorphize/src/polymorphize.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/hir_id_validator.rs
compiler/rustc_passes/src/hir_stats.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_impl/src/lib.rs
compiler/rustc_query_impl/src/plumbing.rs
compiler/rustc_query_impl/src/values.rs [deleted file]
compiler/rustc_query_system/Cargo.toml
compiler/rustc_query_system/src/error.rs
compiler/rustc_query_system/src/ich/impls_syntax.rs
compiler/rustc_query_system/src/lib.rs
compiler/rustc_query_system/src/query/config.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_query_system/src/values.rs [new file with mode: 0644]
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/ident.rs
compiler/rustc_resolve/src/imports.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_save_analysis/src/dump_visitor.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_save_analysis/src/sig.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/errors.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_target/src/spec/tests/tests_impl.rs
compiler/rustc_target/src/spec/uefi_msvc_base.rs
compiler/rustc_trait_selection/src/traits/auto_trait.rs
compiler/rustc_trait_selection/src/traits/codegen.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/normalize.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_ty_utils/src/implied_bounds.rs
compiler/rustc_ty_utils/src/instance.rs
compiler/rustc_type_ir/src/lib.rs
compiler/rustc_type_ir/src/sty.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/closure.rs
compiler/rustc_typeck/src/check/compare_method.rs
compiler/rustc_typeck/src/check/demand.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/intrinsic.rs
compiler/rustc_typeck/src/check/intrinsicck.rs
compiler/rustc_typeck/src/check/method/mod.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/mod.rs
compiler/rustc_typeck/src/check/op.rs
compiler/rustc_typeck/src/check/pat.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/item_bounds.rs
compiler/rustc_typeck/src/collect/type_of.rs
compiler/rustc_typeck/src/variance/constraints.rs
library/core/src/fmt/mod.rs
library/core/src/hint.rs
library/core/src/intrinsics.rs
library/core/src/num/int_macros.rs
library/core/src/ops/generator.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mut_ptr.rs
library/core/tests/lib.rs
library/core/tests/num/int_macros.rs
library/core/tests/num/uint_macros.rs
library/std/Cargo.toml
library/std/src/io/stdio.rs
library/std/src/macros.rs
library/std/src/sys/hermit/condvar.rs [deleted file]
library/std/src/sys/hermit/fs.rs
library/std/src/sys/hermit/futex.rs [new file with mode: 0644]
library/std/src/sys/hermit/mod.rs
library/std/src/sys/hermit/mutex.rs [deleted file]
library/std/src/sys/hermit/net.rs
library/std/src/sys/hermit/rwlock.rs [deleted file]
library/std/src/sys/windows/c.rs
library/std/src/sys/windows/fs.rs
library/std/src/sys/windows/path.rs
library/std/src/sys/windows/path/tests.rs
library/std/src/sys/windows/rand.rs
library/std/src/sys_common/thread_parker/mod.rs
library/std/src/thread/mod.rs
src/bootstrap/Cargo.toml
src/bootstrap/util.rs
src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
src/doc/rustc/src/platform-support.md
src/doc/rustc/src/platform-support/fuchsia.md
src/doc/unstable-book/src/language-features/raw-dylib.md
src/etc/check_missing_items.py
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/formats/item_type.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.css
src/librustdoc/html/static/css/themes/light.css
src/librustdoc/html/static/js/main.js
src/librustdoc/json/conversions.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/visit_ast.rs
src/rustdoc-json-types/lib.rs
src/rustdoc-json-types/tests.rs
src/test/codegen/abi-efiapi.rs
src/test/codegen/issue-98294-get-mut-copy-from-slice-opt.rs [new file with mode: 0644]
src/test/debuginfo/msvc-pretty-enums.rs
src/test/incremental/issue-100521-change-struct-name-assocty.rs [new file with mode: 0644]
src/test/mir-opt/array-index-is-temporary.rs
src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir [deleted file]
src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir [deleted file]
src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir [new file with mode: 0644]
src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
src/test/mir-opt/inline/inline-into-box-place.rs
src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff [deleted file]
src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff [deleted file]
src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff [new file with mode: 0644]
src/test/mir-opt/issue-41697.rs
src/test/mir-opt/issue-72181.rs
src/test/mir-opt/issue-73223.rs
src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir [deleted file]
src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir [deleted file]
src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir [new file with mode: 0644]
src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir [deleted file]
src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir [deleted file]
src/test/mir-opt/issue_72181.bar.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir [deleted file]
src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir [deleted file]
src/test/mir-opt/issue_72181.foo.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir [deleted file]
src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir [deleted file]
src/test/mir-opt/issue_72181.main.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff [deleted file]
src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff [deleted file]
src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff [new file with mode: 0644]
src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff [new file with mode: 0644]
src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff [new file with mode: 0644]
src/test/mir-opt/lower_intrinsics.rs
src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff [deleted file]
src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff [deleted file]
src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff [new file with mode: 0644]
src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff [deleted file]
src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff [deleted file]
src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff [new file with mode: 0644]
src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff [deleted file]
src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff [deleted file]
src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff [new file with mode: 0644]
src/test/mir-opt/matches_reduce_branches.rs
src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff [deleted file]
src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff [deleted file]
src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff [new file with mode: 0644]
src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff [deleted file]
src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff [deleted file]
src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff [new file with mode: 0644]
src/test/mir-opt/matches_u8.rs
src/test/mir-opt/packed-struct-drop-aligned.rs
src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir [deleted file]
src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir [deleted file]
src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir [new file with mode: 0644]
src/test/mir-opt/separate_const_switch.identity.ConstProp.diff [deleted file]
src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir [deleted file]
src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff [deleted file]
src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir [deleted file]
src/test/mir-opt/simple-match.rs
src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir [deleted file]
src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir [deleted file]
src/test/mir-opt/simple_match.match_bool.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs
src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff [deleted file]
src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff [deleted file]
src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff [new file with mode: 0644]
src/test/mir-opt/slice-drop-shim.rs
src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir [deleted file]
src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir [deleted file]
src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir [new file with mode: 0644]
src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
src/test/mir-opt/unusual-item-types.rs
src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir [deleted file]
src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir [deleted file]
src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir [deleted file]
src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir [deleted file]
src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir [deleted file]
src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir [deleted file]
src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir [new file with mode: 0644]
src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir [deleted file]
src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir [deleted file]
src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff [deleted file]
src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff [deleted file]
src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff [new file with mode: 0644]
src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir [deleted file]
src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir [deleted file]
src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/while_let_loops.rs
src/test/run-make/issue-71519/Makefile
src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
src/test/run-make/raw-dylib-link-ordinal/lib.rs
src/test/run-make/raw-dylib-stdcall-ordinal/lib.rs
src/test/run-make/track-pgo-dep-info/Makefile [new file with mode: 0644]
src/test/run-make/track-pgo-dep-info/main.rs [new file with mode: 0644]
src/test/rustdoc-gui/check_info_sign_position.goml
src/test/rustdoc-gui/code-tags.goml
src/test/rustdoc-gui/codeblock-tooltip.goml [new file with mode: 0644]
src/test/rustdoc-gui/overflow-tooltip-information.goml
src/test/rustdoc-gui/search-result-display.goml
src/test/rustdoc-gui/src/test_docs/lib.rs
src/test/rustdoc-json/assoc_items.rs
src/test/rustdoc-json/enums/variant_struct.rs
src/test/rustdoc-json/enums/variant_tuple_struct.rs
src/test/rustdoc-json/fns/generics.rs
src/test/rustdoc-json/impls/import_from_private.rs
src/test/rustdoc-json/intra-doc-links/non_page.rs [new file with mode: 0644]
src/test/rustdoc-json/intra-doc-links/user_written.rs [new file with mode: 0644]
src/test/rustdoc-json/nested.rs
src/test/rustdoc-json/primitives.rs
src/test/rustdoc-json/structs/plain_all_pub.rs [new file with mode: 0644]
src/test/rustdoc-json/structs/plain_doc_hidden.rs [new file with mode: 0644]
src/test/rustdoc-json/structs/plain_empty.rs
src/test/rustdoc-json/structs/plain_pub_priv.rs [new file with mode: 0644]
src/test/rustdoc-json/structs/tuple.rs
src/test/rustdoc-json/structs/tuple_empty.rs [new file with mode: 0644]
src/test/rustdoc-json/structs/tuple_pub_priv.rs [new file with mode: 0644]
src/test/rustdoc-json/structs/unit.rs
src/test/rustdoc-json/structs/with_generics.rs
src/test/rustdoc-json/structs/with_primitives.rs
src/test/rustdoc-json/traits/has_body.rs
src/test/rustdoc-json/type/dyn.rs
src/test/rustdoc-json/unions/impl.rs
src/test/rustdoc/glob-shadowing-const.rs [new file with mode: 0644]
src/test/rustdoc/glob-shadowing.rs [new file with mode: 0644]
src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs [new file with mode: 0644]
src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs [new file with mode: 0644]
src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs
src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs
src/test/ui/array-slice-vec/suggest-array-length.fixed
src/test/ui/array-slice-vec/suggest-array-length.rs
src/test/ui/array-slice-vec/suggest-array-length.stderr
src/test/ui/asm/aarch64/type-check-3.stderr
src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr
src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr
src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr
src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr
src/test/ui/asm/x86_64/type-check-3.stderr
src/test/ui/associated-types/issue-62200.rs
src/test/ui/associated-types/issue-62200.stderr
src/test/ui/async-await/async-trait-fn.rs
src/test/ui/async-await/async-trait-fn.stderr
src/test/ui/async-await/edition-deny-async-fns-2015.rs
src/test/ui/async-await/edition-deny-async-fns-2015.stderr
src/test/ui/async-await/issues/issue-95307.stderr
src/test/ui/binop/binary-op-on-double-ref.stderr
src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
src/test/ui/borrowck/borrowck-describe-lvalue.stderr
src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
src/test/ui/borrowck/borrowck-move-out-from-array.stderr
src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr
src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr
src/test/ui/closures/issue-52437.rs
src/test/ui/closures/issue-52437.stderr
src/test/ui/codegen/issue-101585-128bit-repeat.rs [new file with mode: 0644]
src/test/ui/const-generics/argument_order.stderr
src/test/ui/const-generics/const-param-before-other-params.rs
src/test/ui/const-generics/const-param-before-other-params.stderr
src/test/ui/const-generics/defaults/intermixed-lifetime.rs
src/test/ui/const-generics/defaults/intermixed-lifetime.stderr
src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs
src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr
src/test/ui/const-generics/issues/issue-83765.stderr
src/test/ui/consts/miri_unleashed/slice_eq.rs
src/test/ui/consts/ptr_comparisons.rs
src/test/ui/consts/ptr_comparisons.stderr
src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs
src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr
src/test/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs
src/test/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr
src/test/ui/feature-gates/feature-gate-raw-dylib.rs
src/test/ui/feature-gates/feature-gate-raw-dylib.stderr
src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/missing-bounds.fixed
src/test/ui/generic-associated-types/missing-bounds.stderr
src/test/ui/generics/issue-59508-1.rs
src/test/ui/generics/issue-59508-1.stderr
src/test/ui/generics/issue-59508.fixed
src/test/ui/generics/issue-59508.rs
src/test/ui/generics/issue-59508.stderr
src/test/ui/generics/issue-80512-param-reordering-with-defaults.rs
src/test/ui/generics/issue-80512-param-reordering-with-defaults.stderr
src/test/ui/generics/lifetime-before-type-params.rs
src/test/ui/generics/lifetime-before-type-params.stderr
src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr [new file with mode: 0644]
src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr [new file with mode: 0644]
src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/deep-match-works.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/deep-match.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/deep-match.stderr [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/doesnt-satisfy.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/doesnt-satisfy.stderr [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/nested-rpitit.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/opaque-in-impl.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/reveal.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/success.rs [new file with mode: 0644]
src/test/ui/impl-trait/where-allowed.stderr
src/test/ui/issues/issue-43988.stderr
src/test/ui/issues/issue-47511.stderr
src/test/ui/issues/issue-66706.rs
src/test/ui/issues/issue-66706.stderr
src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
src/test/ui/layout/zero-sized-array-enum-niche.stderr
src/test/ui/moves/move-out-of-array-ref.stderr
src/test/ui/moves/move-out-of-slice-2.stderr
src/test/ui/nll/issue-51244.stderr
src/test/ui/parser/do-not-suggest-semicolon-before-array.rs [new file with mode: 0644]
src/test/ui/parser/do-not-suggest-semicolon-before-array.stderr [new file with mode: 0644]
src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs [new file with mode: 0644]
src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr [new file with mode: 0644]
src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs [deleted file]
src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr [deleted file]
src/test/ui/parser/fn-header-semantic-fail.rs
src/test/ui/parser/fn-header-semantic-fail.stderr
src/test/ui/parser/issue-101477-enum.fixed [new file with mode: 0644]
src/test/ui/parser/issue-101477-enum.rs [new file with mode: 0644]
src/test/ui/parser/issue-101477-enum.stderr [new file with mode: 0644]
src/test/ui/parser/issue-101477-let.fixed [new file with mode: 0644]
src/test/ui/parser/issue-101477-let.rs [new file with mode: 0644]
src/test/ui/parser/issue-101477-let.stderr [new file with mode: 0644]
src/test/ui/parser/issues/issue-14303-enum.rs [deleted file]
src/test/ui/parser/issues/issue-14303-enum.stderr [deleted file]
src/test/ui/parser/issues/issue-14303-fn-def.rs [deleted file]
src/test/ui/parser/issues/issue-14303-fn-def.stderr [deleted file]
src/test/ui/parser/issues/issue-14303-impl.rs [deleted file]
src/test/ui/parser/issues/issue-14303-impl.stderr [deleted file]
src/test/ui/parser/issues/issue-14303-path.rs [deleted file]
src/test/ui/parser/issues/issue-14303-path.stderr [deleted file]
src/test/ui/parser/issues/issue-14303-struct.rs [deleted file]
src/test/ui/parser/issues/issue-14303-struct.stderr [deleted file]
src/test/ui/parser/issues/issue-14303-trait.rs [deleted file]
src/test/ui/parser/issues/issue-14303-trait.stderr [deleted file]
src/test/ui/parser/issues/issue-14303.rs [new file with mode: 0644]
src/test/ui/parser/issues/issue-14303.stderr [new file with mode: 0644]
src/test/ui/parser/suggest-semicolon-before-array.fixed [new file with mode: 0644]
src/test/ui/parser/suggest-semicolon-before-array.rs [new file with mode: 0644]
src/test/ui/parser/suggest-semicolon-before-array.stderr [new file with mode: 0644]
src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed [deleted file]
src/test/ui/parser/suggest-suggest-semicolon-before-array.rs [deleted file]
src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr [deleted file]
src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
src/test/ui/repr/invalid_repr_list_help.rs [new file with mode: 0644]
src/test/ui/repr/invalid_repr_list_help.stderr [new file with mode: 0644]
src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
src/test/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr
src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
src/test/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
src/test/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr
src/test/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs
src/test/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr
src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.rs
src/test/ui/rfc-2627-raw-dylib/import-name-type-x86-only.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs
src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
src/test/ui/rfc-2627-raw-dylib/unsupported-abi.rs
src/test/ui/rfc-2627-raw-dylib/unsupported-abi.stderr
src/test/ui/sanitize/memory-eager.rs [new file with mode: 0644]
src/test/ui/sanitize/memory.rs
src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs
src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr
src/test/ui/stats/hir-stats.rs
src/test/ui/stats/hir-stats.stderr
src/test/ui/structs-enums/type-sizes.rs
src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
src/test/ui/suggestions/issue-97677.fixed
src/test/ui/suggestions/issue-97677.stderr
src/test/ui/suggestions/restrict-type-not-param.rs [new file with mode: 0644]
src/test/ui/suggestions/restrict-type-not-param.stderr [new file with mode: 0644]
src/test/ui/suggestions/suggest-move-lifetimes.stderr
src/test/ui/suggestions/suggest-move-types.stderr
src/test/ui/traits/resolution-in-overloaded-op.stderr
src/test/ui/type-alias-impl-trait/constrain_inputs.rs
src/test/ui/type-alias-impl-trait/constrain_inputs.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.stderr [new file with mode: 0644]
src/test/ui/typeck/assign-non-lval-derefmut.stderr
src/test/ui/typeck/assign-non-lval-mut-ref.stderr
src/tools/clippy/CHANGELOG.md
src/tools/clippy/clippy_dev/src/new_lint.rs
src/tools/clippy/clippy_dev/src/update_lints.rs
src/tools/clippy/clippy_lints/src/async_yields_async.rs
src/tools/clippy/clippy_lints/src/attrs.rs
src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/default.rs
src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/derivable_impls.rs
src/tools/clippy/clippy_lints/src/derive.rs
src/tools/clippy/clippy_lints/src/doc.rs
src/tools/clippy/clippy_lints/src/equatable_if_let.rs
src/tools/clippy/clippy_lints/src/eta_reduction.rs
src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
src/tools/clippy/clippy_lints/src/functions/must_use.rs
src/tools/clippy/clippy_lints/src/functions/result.rs
src/tools/clippy/clippy_lints/src/implicit_return.rs
src/tools/clippy/clippy_lints/src/infinite_iter.rs
src/tools/clippy/clippy_lints/src/large_enum_variant.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/lib.register_all.rs
src/tools/clippy/clippy_lints/src/lib.register_lints.rs
src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
src/tools/clippy/clippy_lints/src/lib.register_style.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
src/tools/clippy/clippy_lints/src/manual_async_fn.rs
src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
src/tools/clippy/clippy_lints/src/matches/single_match.rs
src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
src/tools/clippy/clippy_lints/src/methods/filter_map.rs
src/tools/clippy/clippy_lints/src/methods/map_clone.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
src/tools/clippy/clippy_lints/src/methods/open_options.rs
src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs
src/tools/clippy/clippy_lints/src/minmax.rs
src/tools/clippy/clippy_lints/src/needless_for_each.rs
src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
src/tools/clippy/clippy_lints/src/operators/arithmetic.rs [deleted file]
src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/operators/mod.rs
src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
src/tools/clippy/clippy_lints/src/ptr.rs
src/tools/clippy/clippy_lints/src/question_mark.rs
src/tools/clippy/clippy_lints/src/ranges.rs
src/tools/clippy/clippy_lints/src/returns.rs
src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
src/tools/clippy/clippy_lints/src/unwrap.rs
src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
src/tools/clippy/clippy_lints/src/utils/author.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
src/tools/clippy/clippy_lints/src/write.rs
src/tools/clippy/clippy_utils/src/check_proc_macro.rs
src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
src/tools/clippy/clippy_utils/src/hir_utils.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/macros.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/clippy/clippy_utils/src/visitors.rs
src/tools/clippy/lintcheck/lintcheck_crates.toml
src/tools/clippy/rust-toolchain
src/tools/clippy/src/docs.rs [new file with mode: 0644]
src/tools/clippy/src/docs/absurd_extreme_comparisons.txt [new file with mode: 0644]
src/tools/clippy/src/docs/alloc_instead_of_core.txt [new file with mode: 0644]
src/tools/clippy/src/docs/allow_attributes_without_reason.txt [new file with mode: 0644]
src/tools/clippy/src/docs/almost_complete_letter_range.txt [new file with mode: 0644]
src/tools/clippy/src/docs/almost_swapped.txt [new file with mode: 0644]
src/tools/clippy/src/docs/approx_constant.txt [new file with mode: 0644]
src/tools/clippy/src/docs/arithmetic_side_effects.txt [new file with mode: 0644]
src/tools/clippy/src/docs/as_conversions.txt [new file with mode: 0644]
src/tools/clippy/src/docs/as_underscore.txt [new file with mode: 0644]
src/tools/clippy/src/docs/assertions_on_constants.txt [new file with mode: 0644]
src/tools/clippy/src/docs/assertions_on_result_states.txt [new file with mode: 0644]
src/tools/clippy/src/docs/assign_op_pattern.txt [new file with mode: 0644]
src/tools/clippy/src/docs/async_yields_async.txt [new file with mode: 0644]
src/tools/clippy/src/docs/await_holding_invalid_type.txt [new file with mode: 0644]
src/tools/clippy/src/docs/await_holding_lock.txt [new file with mode: 0644]
src/tools/clippy/src/docs/await_holding_refcell_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/bad_bit_mask.txt [new file with mode: 0644]
src/tools/clippy/src/docs/bind_instead_of_map.txt [new file with mode: 0644]
src/tools/clippy/src/docs/blanket_clippy_restriction_lints.txt [new file with mode: 0644]
src/tools/clippy/src/docs/blocks_in_if_conditions.txt [new file with mode: 0644]
src/tools/clippy/src/docs/bool_assert_comparison.txt [new file with mode: 0644]
src/tools/clippy/src/docs/bool_comparison.txt [new file with mode: 0644]
src/tools/clippy/src/docs/bool_to_int_with_if.txt [new file with mode: 0644]
src/tools/clippy/src/docs/borrow_as_ptr.txt [new file with mode: 0644]
src/tools/clippy/src/docs/borrow_deref_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/borrow_interior_mutable_const.txt [new file with mode: 0644]
src/tools/clippy/src/docs/borrowed_box.txt [new file with mode: 0644]
src/tools/clippy/src/docs/box_collection.txt [new file with mode: 0644]
src/tools/clippy/src/docs/boxed_local.txt [new file with mode: 0644]
src/tools/clippy/src/docs/branches_sharing_code.txt [new file with mode: 0644]
src/tools/clippy/src/docs/builtin_type_shadow.txt [new file with mode: 0644]
src/tools/clippy/src/docs/bytes_count_to_len.txt [new file with mode: 0644]
src/tools/clippy/src/docs/bytes_nth.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cargo_common_metadata.txt [new file with mode: 0644]
src/tools/clippy/src/docs/case_sensitive_file_extension_comparisons.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cast_abs_to_unsigned.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cast_enum_constructor.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cast_enum_truncation.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cast_lossless.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cast_possible_truncation.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cast_possible_wrap.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cast_precision_loss.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cast_ptr_alignment.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cast_ref_to_mut.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cast_sign_loss.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cast_slice_different_sizes.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cast_slice_from_raw_parts.txt [new file with mode: 0644]
src/tools/clippy/src/docs/char_lit_as_u8.txt [new file with mode: 0644]
src/tools/clippy/src/docs/chars_last_cmp.txt [new file with mode: 0644]
src/tools/clippy/src/docs/chars_next_cmp.txt [new file with mode: 0644]
src/tools/clippy/src/docs/checked_conversions.txt [new file with mode: 0644]
src/tools/clippy/src/docs/clone_double_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/clone_on_copy.txt [new file with mode: 0644]
src/tools/clippy/src/docs/clone_on_ref_ptr.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cloned_instead_of_copied.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cmp_nan.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cmp_null.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cmp_owned.txt [new file with mode: 0644]
src/tools/clippy/src/docs/cognitive_complexity.txt [new file with mode: 0644]
src/tools/clippy/src/docs/collapsible_else_if.txt [new file with mode: 0644]
src/tools/clippy/src/docs/collapsible_if.txt [new file with mode: 0644]
src/tools/clippy/src/docs/collapsible_match.txt [new file with mode: 0644]
src/tools/clippy/src/docs/collapsible_str_replace.txt [new file with mode: 0644]
src/tools/clippy/src/docs/comparison_chain.txt [new file with mode: 0644]
src/tools/clippy/src/docs/comparison_to_empty.txt [new file with mode: 0644]
src/tools/clippy/src/docs/copy_iterator.txt [new file with mode: 0644]
src/tools/clippy/src/docs/crate_in_macro_def.txt [new file with mode: 0644]
src/tools/clippy/src/docs/create_dir.txt [new file with mode: 0644]
src/tools/clippy/src/docs/crosspointer_transmute.txt [new file with mode: 0644]
src/tools/clippy/src/docs/dbg_macro.txt [new file with mode: 0644]
src/tools/clippy/src/docs/debug_assert_with_mut_call.txt [new file with mode: 0644]
src/tools/clippy/src/docs/decimal_literal_representation.txt [new file with mode: 0644]
src/tools/clippy/src/docs/declare_interior_mutable_const.txt [new file with mode: 0644]
src/tools/clippy/src/docs/default_instead_of_iter_empty.txt [new file with mode: 0644]
src/tools/clippy/src/docs/default_numeric_fallback.txt [new file with mode: 0644]
src/tools/clippy/src/docs/default_trait_access.txt [new file with mode: 0644]
src/tools/clippy/src/docs/default_union_representation.txt [new file with mode: 0644]
src/tools/clippy/src/docs/deprecated_cfg_attr.txt [new file with mode: 0644]
src/tools/clippy/src/docs/deprecated_semver.txt [new file with mode: 0644]
src/tools/clippy/src/docs/deref_addrof.txt [new file with mode: 0644]
src/tools/clippy/src/docs/deref_by_slicing.txt [new file with mode: 0644]
src/tools/clippy/src/docs/derivable_impls.txt [new file with mode: 0644]
src/tools/clippy/src/docs/derive_hash_xor_eq.txt [new file with mode: 0644]
src/tools/clippy/src/docs/derive_ord_xor_partial_ord.txt [new file with mode: 0644]
src/tools/clippy/src/docs/derive_partial_eq_without_eq.txt [new file with mode: 0644]
src/tools/clippy/src/docs/disallowed_methods.txt [new file with mode: 0644]
src/tools/clippy/src/docs/disallowed_names.txt [new file with mode: 0644]
src/tools/clippy/src/docs/disallowed_script_idents.txt [new file with mode: 0644]
src/tools/clippy/src/docs/disallowed_types.txt [new file with mode: 0644]
src/tools/clippy/src/docs/diverging_sub_expression.txt [new file with mode: 0644]
src/tools/clippy/src/docs/doc_link_with_quotes.txt [new file with mode: 0644]
src/tools/clippy/src/docs/doc_markdown.txt [new file with mode: 0644]
src/tools/clippy/src/docs/double_comparisons.txt [new file with mode: 0644]
src/tools/clippy/src/docs/double_must_use.txt [new file with mode: 0644]
src/tools/clippy/src/docs/double_neg.txt [new file with mode: 0644]
src/tools/clippy/src/docs/double_parens.txt [new file with mode: 0644]
src/tools/clippy/src/docs/drop_copy.txt [new file with mode: 0644]
src/tools/clippy/src/docs/drop_non_drop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/drop_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/duplicate_mod.txt [new file with mode: 0644]
src/tools/clippy/src/docs/duplicate_underscore_argument.txt [new file with mode: 0644]
src/tools/clippy/src/docs/duration_subsec.txt [new file with mode: 0644]
src/tools/clippy/src/docs/else_if_without_else.txt [new file with mode: 0644]
src/tools/clippy/src/docs/empty_drop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/empty_enum.txt [new file with mode: 0644]
src/tools/clippy/src/docs/empty_line_after_outer_attr.txt [new file with mode: 0644]
src/tools/clippy/src/docs/empty_loop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/empty_structs_with_brackets.txt [new file with mode: 0644]
src/tools/clippy/src/docs/enum_clike_unportable_variant.txt [new file with mode: 0644]
src/tools/clippy/src/docs/enum_glob_use.txt [new file with mode: 0644]
src/tools/clippy/src/docs/enum_variant_names.txt [new file with mode: 0644]
src/tools/clippy/src/docs/eq_op.txt [new file with mode: 0644]
src/tools/clippy/src/docs/equatable_if_let.txt [new file with mode: 0644]
src/tools/clippy/src/docs/erasing_op.txt [new file with mode: 0644]
src/tools/clippy/src/docs/err_expect.txt [new file with mode: 0644]
src/tools/clippy/src/docs/excessive_precision.txt [new file with mode: 0644]
src/tools/clippy/src/docs/exhaustive_enums.txt [new file with mode: 0644]
src/tools/clippy/src/docs/exhaustive_structs.txt [new file with mode: 0644]
src/tools/clippy/src/docs/exit.txt [new file with mode: 0644]
src/tools/clippy/src/docs/expect_fun_call.txt [new file with mode: 0644]
src/tools/clippy/src/docs/expect_used.txt [new file with mode: 0644]
src/tools/clippy/src/docs/expl_impl_clone_on_copy.txt [new file with mode: 0644]
src/tools/clippy/src/docs/explicit_auto_deref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/explicit_counter_loop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/explicit_deref_methods.txt [new file with mode: 0644]
src/tools/clippy/src/docs/explicit_into_iter_loop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/explicit_iter_loop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/explicit_write.txt [new file with mode: 0644]
src/tools/clippy/src/docs/extend_with_drain.txt [new file with mode: 0644]
src/tools/clippy/src/docs/extra_unused_lifetimes.txt [new file with mode: 0644]
src/tools/clippy/src/docs/fallible_impl_from.txt [new file with mode: 0644]
src/tools/clippy/src/docs/field_reassign_with_default.txt [new file with mode: 0644]
src/tools/clippy/src/docs/filetype_is_file.txt [new file with mode: 0644]
src/tools/clippy/src/docs/filter_map_identity.txt [new file with mode: 0644]
src/tools/clippy/src/docs/filter_map_next.txt [new file with mode: 0644]
src/tools/clippy/src/docs/filter_next.txt [new file with mode: 0644]
src/tools/clippy/src/docs/flat_map_identity.txt [new file with mode: 0644]
src/tools/clippy/src/docs/flat_map_option.txt [new file with mode: 0644]
src/tools/clippy/src/docs/float_arithmetic.txt [new file with mode: 0644]
src/tools/clippy/src/docs/float_cmp.txt [new file with mode: 0644]
src/tools/clippy/src/docs/float_cmp_const.txt [new file with mode: 0644]
src/tools/clippy/src/docs/float_equality_without_abs.txt [new file with mode: 0644]
src/tools/clippy/src/docs/fn_address_comparisons.txt [new file with mode: 0644]
src/tools/clippy/src/docs/fn_params_excessive_bools.txt [new file with mode: 0644]
src/tools/clippy/src/docs/fn_to_numeric_cast.txt [new file with mode: 0644]
src/tools/clippy/src/docs/fn_to_numeric_cast_any.txt [new file with mode: 0644]
src/tools/clippy/src/docs/fn_to_numeric_cast_with_truncation.txt [new file with mode: 0644]
src/tools/clippy/src/docs/for_kv_map.txt [new file with mode: 0644]
src/tools/clippy/src/docs/for_loops_over_fallibles.txt [new file with mode: 0644]
src/tools/clippy/src/docs/forget_copy.txt [new file with mode: 0644]
src/tools/clippy/src/docs/forget_non_drop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/forget_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/format_in_format_args.txt [new file with mode: 0644]
src/tools/clippy/src/docs/format_push_string.txt [new file with mode: 0644]
src/tools/clippy/src/docs/from_iter_instead_of_collect.txt [new file with mode: 0644]
src/tools/clippy/src/docs/from_over_into.txt [new file with mode: 0644]
src/tools/clippy/src/docs/from_str_radix_10.txt [new file with mode: 0644]
src/tools/clippy/src/docs/future_not_send.txt [new file with mode: 0644]
src/tools/clippy/src/docs/get_first.txt [new file with mode: 0644]
src/tools/clippy/src/docs/get_last_with_len.txt [new file with mode: 0644]
src/tools/clippy/src/docs/get_unwrap.txt [new file with mode: 0644]
src/tools/clippy/src/docs/identity_op.txt [new file with mode: 0644]
src/tools/clippy/src/docs/if_let_mutex.txt [new file with mode: 0644]
src/tools/clippy/src/docs/if_not_else.txt [new file with mode: 0644]
src/tools/clippy/src/docs/if_same_then_else.txt [new file with mode: 0644]
src/tools/clippy/src/docs/if_then_some_else_none.txt [new file with mode: 0644]
src/tools/clippy/src/docs/ifs_same_cond.txt [new file with mode: 0644]
src/tools/clippy/src/docs/implicit_clone.txt [new file with mode: 0644]
src/tools/clippy/src/docs/implicit_hasher.txt [new file with mode: 0644]
src/tools/clippy/src/docs/implicit_return.txt [new file with mode: 0644]
src/tools/clippy/src/docs/implicit_saturating_sub.txt [new file with mode: 0644]
src/tools/clippy/src/docs/imprecise_flops.txt [new file with mode: 0644]
src/tools/clippy/src/docs/inconsistent_digit_grouping.txt [new file with mode: 0644]
src/tools/clippy/src/docs/inconsistent_struct_constructor.txt [new file with mode: 0644]
src/tools/clippy/src/docs/index_refutable_slice.txt [new file with mode: 0644]
src/tools/clippy/src/docs/indexing_slicing.txt [new file with mode: 0644]
src/tools/clippy/src/docs/ineffective_bit_mask.txt [new file with mode: 0644]
src/tools/clippy/src/docs/inefficient_to_string.txt [new file with mode: 0644]
src/tools/clippy/src/docs/infallible_destructuring_match.txt [new file with mode: 0644]
src/tools/clippy/src/docs/infinite_iter.txt [new file with mode: 0644]
src/tools/clippy/src/docs/inherent_to_string.txt [new file with mode: 0644]
src/tools/clippy/src/docs/inherent_to_string_shadow_display.txt [new file with mode: 0644]
src/tools/clippy/src/docs/init_numbered_fields.txt [new file with mode: 0644]
src/tools/clippy/src/docs/inline_always.txt [new file with mode: 0644]
src/tools/clippy/src/docs/inline_asm_x86_att_syntax.txt [new file with mode: 0644]
src/tools/clippy/src/docs/inline_asm_x86_intel_syntax.txt [new file with mode: 0644]
src/tools/clippy/src/docs/inline_fn_without_body.txt [new file with mode: 0644]
src/tools/clippy/src/docs/inspect_for_each.txt [new file with mode: 0644]
src/tools/clippy/src/docs/int_plus_one.txt [new file with mode: 0644]
src/tools/clippy/src/docs/integer_arithmetic.txt [new file with mode: 0644]
src/tools/clippy/src/docs/integer_division.txt [new file with mode: 0644]
src/tools/clippy/src/docs/into_iter_on_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/invalid_null_ptr_usage.txt [new file with mode: 0644]
src/tools/clippy/src/docs/invalid_regex.txt [new file with mode: 0644]
src/tools/clippy/src/docs/invalid_upcast_comparisons.txt [new file with mode: 0644]
src/tools/clippy/src/docs/invalid_utf8_in_unchecked.txt [new file with mode: 0644]
src/tools/clippy/src/docs/invisible_characters.txt [new file with mode: 0644]
src/tools/clippy/src/docs/is_digit_ascii_radix.txt [new file with mode: 0644]
src/tools/clippy/src/docs/items_after_statements.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iter_cloned_collect.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iter_count.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iter_next_loop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iter_next_slice.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iter_not_returning_iterator.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iter_nth.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iter_nth_zero.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iter_on_empty_collections.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iter_on_single_items.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iter_overeager_cloned.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iter_skip_next.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iter_with_drain.txt [new file with mode: 0644]
src/tools/clippy/src/docs/iterator_step_by_zero.txt [new file with mode: 0644]
src/tools/clippy/src/docs/just_underscores_and_digits.txt [new file with mode: 0644]
src/tools/clippy/src/docs/large_const_arrays.txt [new file with mode: 0644]
src/tools/clippy/src/docs/large_digit_groups.txt [new file with mode: 0644]
src/tools/clippy/src/docs/large_enum_variant.txt [new file with mode: 0644]
src/tools/clippy/src/docs/large_include_file.txt [new file with mode: 0644]
src/tools/clippy/src/docs/large_stack_arrays.txt [new file with mode: 0644]
src/tools/clippy/src/docs/large_types_passed_by_value.txt [new file with mode: 0644]
src/tools/clippy/src/docs/len_without_is_empty.txt [new file with mode: 0644]
src/tools/clippy/src/docs/len_zero.txt [new file with mode: 0644]
src/tools/clippy/src/docs/let_and_return.txt [new file with mode: 0644]
src/tools/clippy/src/docs/let_underscore_drop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/let_underscore_lock.txt [new file with mode: 0644]
src/tools/clippy/src/docs/let_underscore_must_use.txt [new file with mode: 0644]
src/tools/clippy/src/docs/let_unit_value.txt [new file with mode: 0644]
src/tools/clippy/src/docs/linkedlist.txt [new file with mode: 0644]
src/tools/clippy/src/docs/lossy_float_literal.txt [new file with mode: 0644]
src/tools/clippy/src/docs/macro_use_imports.txt [new file with mode: 0644]
src/tools/clippy/src/docs/main_recursion.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_assert.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_async_fn.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_bits.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_filter_map.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_find.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_find_map.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_flatten.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_instant_elapsed.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_map.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_memcpy.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_non_exhaustive.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_ok_or.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_range_contains.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_rem_euclid.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_retain.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_saturating_arithmetic.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_split_once.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_str_repeat.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_string_new.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_strip.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_swap.txt [new file with mode: 0644]
src/tools/clippy/src/docs/manual_unwrap_or.txt [new file with mode: 0644]
src/tools/clippy/src/docs/many_single_char_names.txt [new file with mode: 0644]
src/tools/clippy/src/docs/map_clone.txt [new file with mode: 0644]
src/tools/clippy/src/docs/map_collect_result_unit.txt [new file with mode: 0644]
src/tools/clippy/src/docs/map_entry.txt [new file with mode: 0644]
src/tools/clippy/src/docs/map_err_ignore.txt [new file with mode: 0644]
src/tools/clippy/src/docs/map_flatten.txt [new file with mode: 0644]
src/tools/clippy/src/docs/map_identity.txt [new file with mode: 0644]
src/tools/clippy/src/docs/map_unwrap_or.txt [new file with mode: 0644]
src/tools/clippy/src/docs/match_as_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/match_bool.txt [new file with mode: 0644]
src/tools/clippy/src/docs/match_like_matches_macro.txt [new file with mode: 0644]
src/tools/clippy/src/docs/match_on_vec_items.txt [new file with mode: 0644]
src/tools/clippy/src/docs/match_overlapping_arm.txt [new file with mode: 0644]
src/tools/clippy/src/docs/match_ref_pats.txt [new file with mode: 0644]
src/tools/clippy/src/docs/match_result_ok.txt [new file with mode: 0644]
src/tools/clippy/src/docs/match_same_arms.txt [new file with mode: 0644]
src/tools/clippy/src/docs/match_single_binding.txt [new file with mode: 0644]
src/tools/clippy/src/docs/match_str_case_mismatch.txt [new file with mode: 0644]
src/tools/clippy/src/docs/match_wild_err_arm.txt [new file with mode: 0644]
src/tools/clippy/src/docs/match_wildcard_for_single_variants.txt [new file with mode: 0644]
src/tools/clippy/src/docs/maybe_infinite_iter.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mem_forget.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mem_replace_option_with_none.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mem_replace_with_default.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mem_replace_with_uninit.txt [new file with mode: 0644]
src/tools/clippy/src/docs/min_max.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mismatched_target_os.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mismatching_type_param_order.txt [new file with mode: 0644]
src/tools/clippy/src/docs/misrefactored_assign_op.txt [new file with mode: 0644]
src/tools/clippy/src/docs/missing_const_for_fn.txt [new file with mode: 0644]
src/tools/clippy/src/docs/missing_docs_in_private_items.txt [new file with mode: 0644]
src/tools/clippy/src/docs/missing_enforced_import_renames.txt [new file with mode: 0644]
src/tools/clippy/src/docs/missing_errors_doc.txt [new file with mode: 0644]
src/tools/clippy/src/docs/missing_inline_in_public_items.txt [new file with mode: 0644]
src/tools/clippy/src/docs/missing_panics_doc.txt [new file with mode: 0644]
src/tools/clippy/src/docs/missing_safety_doc.txt [new file with mode: 0644]
src/tools/clippy/src/docs/missing_spin_loop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mistyped_literal_suffixes.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mixed_case_hex_literals.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mixed_read_write_in_expression.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mod_module_files.txt [new file with mode: 0644]
src/tools/clippy/src/docs/module_inception.txt [new file with mode: 0644]
src/tools/clippy/src/docs/module_name_repetitions.txt [new file with mode: 0644]
src/tools/clippy/src/docs/modulo_arithmetic.txt [new file with mode: 0644]
src/tools/clippy/src/docs/modulo_one.txt [new file with mode: 0644]
src/tools/clippy/src/docs/multi_assignments.txt [new file with mode: 0644]
src/tools/clippy/src/docs/multiple_crate_versions.txt [new file with mode: 0644]
src/tools/clippy/src/docs/multiple_inherent_impl.txt [new file with mode: 0644]
src/tools/clippy/src/docs/must_use_candidate.txt [new file with mode: 0644]
src/tools/clippy/src/docs/must_use_unit.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mut_from_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mut_mut.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mut_mutex_lock.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mut_range_bound.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mutable_key_type.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mutex_atomic.txt [new file with mode: 0644]
src/tools/clippy/src/docs/mutex_integer.txt [new file with mode: 0644]
src/tools/clippy/src/docs/naive_bytecount.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_arbitrary_self_type.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_bitwise_bool.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_bool.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_borrow.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_borrowed_reference.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_collect.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_continue.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_doctest_main.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_for_each.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_late_init.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_lifetimes.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_match.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_option_as_deref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_option_take.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_parens_on_range_literals.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_pass_by_value.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_question_mark.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_range_loop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_return.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_splitn.txt [new file with mode: 0644]
src/tools/clippy/src/docs/needless_update.txt [new file with mode: 0644]
src/tools/clippy/src/docs/neg_cmp_op_on_partial_ord.txt [new file with mode: 0644]
src/tools/clippy/src/docs/neg_multiply.txt [new file with mode: 0644]
src/tools/clippy/src/docs/negative_feature_names.txt [new file with mode: 0644]
src/tools/clippy/src/docs/never_loop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/new_ret_no_self.txt [new file with mode: 0644]
src/tools/clippy/src/docs/new_without_default.txt [new file with mode: 0644]
src/tools/clippy/src/docs/no_effect.txt [new file with mode: 0644]
src/tools/clippy/src/docs/no_effect_replace.txt [new file with mode: 0644]
src/tools/clippy/src/docs/no_effect_underscore_binding.txt [new file with mode: 0644]
src/tools/clippy/src/docs/non_ascii_literal.txt [new file with mode: 0644]
src/tools/clippy/src/docs/non_octal_unix_permissions.txt [new file with mode: 0644]
src/tools/clippy/src/docs/non_send_fields_in_send_ty.txt [new file with mode: 0644]
src/tools/clippy/src/docs/nonminimal_bool.txt [new file with mode: 0644]
src/tools/clippy/src/docs/nonsensical_open_options.txt [new file with mode: 0644]
src/tools/clippy/src/docs/nonstandard_macro_braces.txt [new file with mode: 0644]
src/tools/clippy/src/docs/not_unsafe_ptr_arg_deref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/obfuscated_if_else.txt [new file with mode: 0644]
src/tools/clippy/src/docs/octal_escapes.txt [new file with mode: 0644]
src/tools/clippy/src/docs/ok_expect.txt [new file with mode: 0644]
src/tools/clippy/src/docs/only_used_in_recursion.txt [new file with mode: 0644]
src/tools/clippy/src/docs/op_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/option_as_ref_deref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/option_env_unwrap.txt [new file with mode: 0644]
src/tools/clippy/src/docs/option_filter_map.txt [new file with mode: 0644]
src/tools/clippy/src/docs/option_if_let_else.txt [new file with mode: 0644]
src/tools/clippy/src/docs/option_map_or_none.txt [new file with mode: 0644]
src/tools/clippy/src/docs/option_map_unit_fn.txt [new file with mode: 0644]
src/tools/clippy/src/docs/option_option.txt [new file with mode: 0644]
src/tools/clippy/src/docs/or_fun_call.txt [new file with mode: 0644]
src/tools/clippy/src/docs/or_then_unwrap.txt [new file with mode: 0644]
src/tools/clippy/src/docs/out_of_bounds_indexing.txt [new file with mode: 0644]
src/tools/clippy/src/docs/overflow_check_conditional.txt [new file with mode: 0644]
src/tools/clippy/src/docs/overly_complex_bool_expr.txt [new file with mode: 0644]
src/tools/clippy/src/docs/panic.txt [new file with mode: 0644]
src/tools/clippy/src/docs/panic_in_result_fn.txt [new file with mode: 0644]
src/tools/clippy/src/docs/panicking_unwrap.txt [new file with mode: 0644]
src/tools/clippy/src/docs/partialeq_ne_impl.txt [new file with mode: 0644]
src/tools/clippy/src/docs/partialeq_to_none.txt [new file with mode: 0644]
src/tools/clippy/src/docs/path_buf_push_overwrite.txt [new file with mode: 0644]
src/tools/clippy/src/docs/pattern_type_mismatch.txt [new file with mode: 0644]
src/tools/clippy/src/docs/positional_named_format_parameters.txt [new file with mode: 0644]
src/tools/clippy/src/docs/possible_missing_comma.txt [new file with mode: 0644]
src/tools/clippy/src/docs/precedence.txt [new file with mode: 0644]
src/tools/clippy/src/docs/print_in_format_impl.txt [new file with mode: 0644]
src/tools/clippy/src/docs/print_literal.txt [new file with mode: 0644]
src/tools/clippy/src/docs/print_stderr.txt [new file with mode: 0644]
src/tools/clippy/src/docs/print_stdout.txt [new file with mode: 0644]
src/tools/clippy/src/docs/print_with_newline.txt [new file with mode: 0644]
src/tools/clippy/src/docs/println_empty_string.txt [new file with mode: 0644]
src/tools/clippy/src/docs/ptr_arg.txt [new file with mode: 0644]
src/tools/clippy/src/docs/ptr_as_ptr.txt [new file with mode: 0644]
src/tools/clippy/src/docs/ptr_eq.txt [new file with mode: 0644]
src/tools/clippy/src/docs/ptr_offset_with_cast.txt [new file with mode: 0644]
src/tools/clippy/src/docs/pub_use.txt [new file with mode: 0644]
src/tools/clippy/src/docs/question_mark.txt [new file with mode: 0644]
src/tools/clippy/src/docs/range_minus_one.txt [new file with mode: 0644]
src/tools/clippy/src/docs/range_plus_one.txt [new file with mode: 0644]
src/tools/clippy/src/docs/range_zip_with_len.txt [new file with mode: 0644]
src/tools/clippy/src/docs/rc_buffer.txt [new file with mode: 0644]
src/tools/clippy/src/docs/rc_clone_in_vec_init.txt [new file with mode: 0644]
src/tools/clippy/src/docs/rc_mutex.txt [new file with mode: 0644]
src/tools/clippy/src/docs/read_zero_byte_vec.txt [new file with mode: 0644]
src/tools/clippy/src/docs/recursive_format_impl.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_allocation.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_clone.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_closure.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_closure_call.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_closure_for_method_calls.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_else.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_feature_names.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_field_names.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_pattern.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_pattern_matching.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_pub_crate.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_slicing.txt [new file with mode: 0644]
src/tools/clippy/src/docs/redundant_static_lifetimes.txt [new file with mode: 0644]
src/tools/clippy/src/docs/ref_binding_to_reference.txt [new file with mode: 0644]
src/tools/clippy/src/docs/ref_option_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/repeat_once.txt [new file with mode: 0644]
src/tools/clippy/src/docs/rest_pat_in_fully_bound_structs.txt [new file with mode: 0644]
src/tools/clippy/src/docs/result_large_err.txt [new file with mode: 0644]
src/tools/clippy/src/docs/result_map_or_into_option.txt [new file with mode: 0644]
src/tools/clippy/src/docs/result_map_unit_fn.txt [new file with mode: 0644]
src/tools/clippy/src/docs/result_unit_err.txt [new file with mode: 0644]
src/tools/clippy/src/docs/return_self_not_must_use.txt [new file with mode: 0644]
src/tools/clippy/src/docs/reversed_empty_ranges.txt [new file with mode: 0644]
src/tools/clippy/src/docs/same_functions_in_if_condition.txt [new file with mode: 0644]
src/tools/clippy/src/docs/same_item_push.txt [new file with mode: 0644]
src/tools/clippy/src/docs/same_name_method.txt [new file with mode: 0644]
src/tools/clippy/src/docs/search_is_some.txt [new file with mode: 0644]
src/tools/clippy/src/docs/self_assignment.txt [new file with mode: 0644]
src/tools/clippy/src/docs/self_named_constructors.txt [new file with mode: 0644]
src/tools/clippy/src/docs/self_named_module_files.txt [new file with mode: 0644]
src/tools/clippy/src/docs/semicolon_if_nothing_returned.txt [new file with mode: 0644]
src/tools/clippy/src/docs/separated_literal_suffix.txt [new file with mode: 0644]
src/tools/clippy/src/docs/serde_api_misuse.txt [new file with mode: 0644]
src/tools/clippy/src/docs/shadow_reuse.txt [new file with mode: 0644]
src/tools/clippy/src/docs/shadow_same.txt [new file with mode: 0644]
src/tools/clippy/src/docs/shadow_unrelated.txt [new file with mode: 0644]
src/tools/clippy/src/docs/short_circuit_statement.txt [new file with mode: 0644]
src/tools/clippy/src/docs/should_implement_trait.txt [new file with mode: 0644]
src/tools/clippy/src/docs/significant_drop_in_scrutinee.txt [new file with mode: 0644]
src/tools/clippy/src/docs/similar_names.txt [new file with mode: 0644]
src/tools/clippy/src/docs/single_char_add_str.txt [new file with mode: 0644]
src/tools/clippy/src/docs/single_char_lifetime_names.txt [new file with mode: 0644]
src/tools/clippy/src/docs/single_char_pattern.txt [new file with mode: 0644]
src/tools/clippy/src/docs/single_component_path_imports.txt [new file with mode: 0644]
src/tools/clippy/src/docs/single_element_loop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/single_match.txt [new file with mode: 0644]
src/tools/clippy/src/docs/single_match_else.txt [new file with mode: 0644]
src/tools/clippy/src/docs/size_of_in_element_count.txt [new file with mode: 0644]
src/tools/clippy/src/docs/skip_while_next.txt [new file with mode: 0644]
src/tools/clippy/src/docs/slow_vector_initialization.txt [new file with mode: 0644]
src/tools/clippy/src/docs/stable_sort_primitive.txt [new file with mode: 0644]
src/tools/clippy/src/docs/std_instead_of_alloc.txt [new file with mode: 0644]
src/tools/clippy/src/docs/std_instead_of_core.txt [new file with mode: 0644]
src/tools/clippy/src/docs/str_to_string.txt [new file with mode: 0644]
src/tools/clippy/src/docs/string_add.txt [new file with mode: 0644]
src/tools/clippy/src/docs/string_add_assign.txt [new file with mode: 0644]
src/tools/clippy/src/docs/string_extend_chars.txt [new file with mode: 0644]
src/tools/clippy/src/docs/string_from_utf8_as_bytes.txt [new file with mode: 0644]
src/tools/clippy/src/docs/string_lit_as_bytes.txt [new file with mode: 0644]
src/tools/clippy/src/docs/string_slice.txt [new file with mode: 0644]
src/tools/clippy/src/docs/string_to_string.txt [new file with mode: 0644]
src/tools/clippy/src/docs/strlen_on_c_strings.txt [new file with mode: 0644]
src/tools/clippy/src/docs/struct_excessive_bools.txt [new file with mode: 0644]
src/tools/clippy/src/docs/suboptimal_flops.txt [new file with mode: 0644]
src/tools/clippy/src/docs/suspicious_arithmetic_impl.txt [new file with mode: 0644]
src/tools/clippy/src/docs/suspicious_assignment_formatting.txt [new file with mode: 0644]
src/tools/clippy/src/docs/suspicious_else_formatting.txt [new file with mode: 0644]
src/tools/clippy/src/docs/suspicious_map.txt [new file with mode: 0644]
src/tools/clippy/src/docs/suspicious_op_assign_impl.txt [new file with mode: 0644]
src/tools/clippy/src/docs/suspicious_operation_groupings.txt [new file with mode: 0644]
src/tools/clippy/src/docs/suspicious_splitn.txt [new file with mode: 0644]
src/tools/clippy/src/docs/suspicious_to_owned.txt [new file with mode: 0644]
src/tools/clippy/src/docs/suspicious_unary_op_formatting.txt [new file with mode: 0644]
src/tools/clippy/src/docs/swap_ptr_to_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/tabs_in_doc_comments.txt [new file with mode: 0644]
src/tools/clippy/src/docs/temporary_assignment.txt [new file with mode: 0644]
src/tools/clippy/src/docs/to_digit_is_some.txt [new file with mode: 0644]
src/tools/clippy/src/docs/to_string_in_format_args.txt [new file with mode: 0644]
src/tools/clippy/src/docs/todo.txt [new file with mode: 0644]
src/tools/clippy/src/docs/too_many_arguments.txt [new file with mode: 0644]
src/tools/clippy/src/docs/too_many_lines.txt [new file with mode: 0644]
src/tools/clippy/src/docs/toplevel_ref_arg.txt [new file with mode: 0644]
src/tools/clippy/src/docs/trailing_empty_array.txt [new file with mode: 0644]
src/tools/clippy/src/docs/trait_duplication_in_bounds.txt [new file with mode: 0644]
src/tools/clippy/src/docs/transmute_bytes_to_str.txt [new file with mode: 0644]
src/tools/clippy/src/docs/transmute_float_to_int.txt [new file with mode: 0644]
src/tools/clippy/src/docs/transmute_int_to_bool.txt [new file with mode: 0644]
src/tools/clippy/src/docs/transmute_int_to_char.txt [new file with mode: 0644]
src/tools/clippy/src/docs/transmute_int_to_float.txt [new file with mode: 0644]
src/tools/clippy/src/docs/transmute_num_to_bytes.txt [new file with mode: 0644]
src/tools/clippy/src/docs/transmute_ptr_to_ptr.txt [new file with mode: 0644]
src/tools/clippy/src/docs/transmute_ptr_to_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/transmute_undefined_repr.txt [new file with mode: 0644]
src/tools/clippy/src/docs/transmutes_expressible_as_ptr_casts.txt [new file with mode: 0644]
src/tools/clippy/src/docs/transmuting_null.txt [new file with mode: 0644]
src/tools/clippy/src/docs/trim_split_whitespace.txt [new file with mode: 0644]
src/tools/clippy/src/docs/trivial_regex.txt [new file with mode: 0644]
src/tools/clippy/src/docs/trivially_copy_pass_by_ref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/try_err.txt [new file with mode: 0644]
src/tools/clippy/src/docs/type_complexity.txt [new file with mode: 0644]
src/tools/clippy/src/docs/type_repetition_in_bounds.txt [new file with mode: 0644]
src/tools/clippy/src/docs/undocumented_unsafe_blocks.txt [new file with mode: 0644]
src/tools/clippy/src/docs/undropped_manually_drops.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unicode_not_nfc.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unimplemented.txt [new file with mode: 0644]
src/tools/clippy/src/docs/uninit_assumed_init.txt [new file with mode: 0644]
src/tools/clippy/src/docs/uninit_vec.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unit_arg.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unit_cmp.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unit_hash.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unit_return_expecting_ord.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_cast.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_filter_map.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_find_map.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_fold.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_join.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_lazy_evaluations.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_mut_passed.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_operation.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_owned_empty_strings.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_self_imports.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_sort_by.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_to_owned.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_unwrap.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnecessary_wraps.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unneeded_field_pattern.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unneeded_wildcard_pattern.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unnested_or_patterns.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unreachable.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unreadable_literal.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unsafe_derive_deserialize.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unsafe_removed_from_name.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unseparated_literal_suffix.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unsound_collection_transmute.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unused_async.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unused_io_amount.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unused_peekable.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unused_rounding.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unused_self.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unused_unit.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unusual_byte_groupings.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unwrap_in_result.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unwrap_or_else_default.txt [new file with mode: 0644]
src/tools/clippy/src/docs/unwrap_used.txt [new file with mode: 0644]
src/tools/clippy/src/docs/upper_case_acronyms.txt [new file with mode: 0644]
src/tools/clippy/src/docs/use_debug.txt [new file with mode: 0644]
src/tools/clippy/src/docs/use_self.txt [new file with mode: 0644]
src/tools/clippy/src/docs/used_underscore_binding.txt [new file with mode: 0644]
src/tools/clippy/src/docs/useless_asref.txt [new file with mode: 0644]
src/tools/clippy/src/docs/useless_attribute.txt [new file with mode: 0644]
src/tools/clippy/src/docs/useless_conversion.txt [new file with mode: 0644]
src/tools/clippy/src/docs/useless_format.txt [new file with mode: 0644]
src/tools/clippy/src/docs/useless_let_if_seq.txt [new file with mode: 0644]
src/tools/clippy/src/docs/useless_transmute.txt [new file with mode: 0644]
src/tools/clippy/src/docs/useless_vec.txt [new file with mode: 0644]
src/tools/clippy/src/docs/vec_box.txt [new file with mode: 0644]
src/tools/clippy/src/docs/vec_init_then_push.txt [new file with mode: 0644]
src/tools/clippy/src/docs/vec_resize_to_zero.txt [new file with mode: 0644]
src/tools/clippy/src/docs/verbose_bit_mask.txt [new file with mode: 0644]
src/tools/clippy/src/docs/verbose_file_reads.txt [new file with mode: 0644]
src/tools/clippy/src/docs/vtable_address_comparisons.txt [new file with mode: 0644]
src/tools/clippy/src/docs/while_immutable_condition.txt [new file with mode: 0644]
src/tools/clippy/src/docs/while_let_loop.txt [new file with mode: 0644]
src/tools/clippy/src/docs/while_let_on_iterator.txt [new file with mode: 0644]
src/tools/clippy/src/docs/wildcard_dependencies.txt [new file with mode: 0644]
src/tools/clippy/src/docs/wildcard_enum_match_arm.txt [new file with mode: 0644]
src/tools/clippy/src/docs/wildcard_imports.txt [new file with mode: 0644]
src/tools/clippy/src/docs/wildcard_in_or_patterns.txt [new file with mode: 0644]
src/tools/clippy/src/docs/write_literal.txt [new file with mode: 0644]
src/tools/clippy/src/docs/write_with_newline.txt [new file with mode: 0644]
src/tools/clippy/src/docs/writeln_empty_string.txt [new file with mode: 0644]
src/tools/clippy/src/docs/wrong_self_convention.txt [new file with mode: 0644]
src/tools/clippy/src/docs/wrong_transmute.txt [new file with mode: 0644]
src/tools/clippy/src/docs/zero_divided_by_zero.txt [new file with mode: 0644]
src/tools/clippy/src/docs/zero_prefixed_literal.txt [new file with mode: 0644]
src/tools/clippy/src/docs/zero_ptr.txt [new file with mode: 0644]
src/tools/clippy/src/docs/zero_sized_map_values.txt [new file with mode: 0644]
src/tools/clippy/src/docs/zst_offset.txt [new file with mode: 0644]
src/tools/clippy/src/main.rs
src/tools/clippy/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs [deleted file]
src/tools/clippy/tests/ui-toml/arithmetic_allowed/clippy.toml [deleted file]
src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml [new file with mode: 0644]
src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
src/tools/clippy/tests/ui/arithmetic.fixed [deleted file]
src/tools/clippy/tests/ui/arithmetic.rs [deleted file]
src/tools/clippy/tests/ui/arithmetic_side_effects.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/arithmetic_side_effects.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/author/struct.rs
src/tools/clippy/tests/ui/bool_to_int_with_if.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/bool_to_int_with_if.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/bool_to_int_with_if.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/ice-9405.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/ice-9405.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/ice-9414.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_powf.fixed
src/tools/clippy/tests/ui/floating_point_powf.rs
src/tools/clippy/tests/ui/floating_point_powf.stderr
src/tools/clippy/tests/ui/large_enum_variant.rs
src/tools/clippy/tests/ui/large_enum_variant.stderr
src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr
src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr
src/tools/clippy/tests/ui/mut_mutex_lock.fixed
src/tools/clippy/tests/ui/mut_mutex_lock.rs
src/tools/clippy/tests/ui/or_fun_call.fixed
src/tools/clippy/tests/ui/or_fun_call.stderr
src/tools/clippy/tests/ui/range_plus_minus_one.fixed
src/tools/clippy/tests/ui/range_plus_minus_one.rs
src/tools/clippy/tests/ui/range_plus_minus_one.stderr
src/tools/clippy/tests/ui/result_large_err.rs
src/tools/clippy/tests/ui/result_large_err.stderr
src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
src/tools/clippy/tests/ui/unnecessary_to_owned.rs
src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
src/tools/clippy/tests/ui/unwrap_or_else_default.rs
src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
src/tools/clippy/tests/ui/vec_init_then_push.rs
src/tools/clippy/tests/ui/vec_init_then_push.stderr
src/tools/compiletest/src/header.rs
src/tools/lld-wrapper/src/main.rs
src/tools/miri
src/tools/rust-analyzer/.github/workflows/ci.yaml
src/tools/rust-analyzer/.github/workflows/release.yaml
src/tools/rust-analyzer/crates/hir-def/src/body.rs
src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
src/tools/rust-analyzer/crates/hir-def/src/expr.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
src/tools/rust-analyzer/crates/hir-expand/src/name.rs
src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs
src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs [new file with mode: 0644]
src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
src/tools/rust-analyzer/crates/hir/src/lib.rs
src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs [new file with mode: 0644]
src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_or_with_or_else.rs [new file with mode: 0644]
src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs [new file with mode: 0644]
src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast [new file with mode: 0644]
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs [new file with mode: 0644]
src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
src/tools/rust-analyzer/crates/syntax/rust.ungram
src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
src/tools/rust-analyzer/lib/la-arena/src/lib.rs
src/tools/tidy/src/features.rs

index 68ea8b51c555c7e920f21cfddc989518b746ae65..4e0e72d34153f0a84c173b2194f8f07846ea0f0c 100644 (file)
@@ -1656,12 +1656,13 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.2.0"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ab7905ea95c6d9af62940f9d7dd9596d54c334ae2c15300c482051292d5637f"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
 dependencies = [
  "compiler_builtins",
  "libc",
+ "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
@@ -3958,6 +3959,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
+ "rustc_type_ir",
  "smallvec",
  "thin-vec",
  "tracing",
@@ -4607,7 +4609,7 @@ dependencies = [
  "dlmalloc",
  "fortanix-sgx-abi",
  "hashbrown",
- "hermit-abi 0.2.0",
+ "hermit-abi 0.2.6",
  "libc",
  "miniz_oxide 0.4.0",
  "object 0.26.2",
index 72b2c16a01f83b63ce9d1f448ab652c21aeb5450..89fd4f2703b5d3a2dee4b205e478adc3902b5345 100644 (file)
@@ -217,6 +217,7 @@ Language
 - [Fix constants not getting dropped if part of a diverging expression][94775]
 - [Support unit struct/enum variant in destructuring assignment][95380]
 - [Remove mutable_borrow_reservation_conflict lint and allow the code pattern][96268]
+- [`const` functions may now specify `extern "C"` or `extern "Rust"`][95346]
 
 Compiler
 --------
@@ -306,6 +307,7 @@ and related tools.
 [94872]: https://github.com/rust-lang/rust/pull/94872/
 [95006]: https://github.com/rust-lang/rust/pull/95006/
 [95035]: https://github.com/rust-lang/rust/pull/95035/
+[95346]: https://github.com/rust-lang/rust/pull/95346/
 [95372]: https://github.com/rust-lang/rust/pull/95372/
 [95380]: https://github.com/rust-lang/rust/pull/95380/
 [95431]: https://github.com/rust-lang/rust/pull/95431/
index f25fdc942b0850db6590061f0956ba536b21302b..3f4911c4ecfcf63313fb68728f334d5d38a12d8c 100644 (file)
@@ -33,7 +33,6 @@
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use std::cmp::Ordering;
 use std::convert::TryFrom;
 use std::fmt;
 use std::mem;
@@ -324,46 +323,17 @@ pub fn span(&self) -> Span {
 /// Specifies the enforced ordering for generic parameters. In the future,
 /// if we wanted to relax this order, we could override `PartialEq` and
 /// `PartialOrd`, to allow the kinds to be unordered.
-#[derive(Hash, Clone, Copy)]
+#[derive(Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 pub enum ParamKindOrd {
     Lifetime,
-    Type,
-    Const,
-    // `Infer` is not actually constructed directly from the AST, but is implicitly constructed
-    // during HIR lowering, and `ParamKindOrd` will implicitly order inferred variables last.
-    Infer,
-}
-
-impl Ord for ParamKindOrd {
-    fn cmp(&self, other: &Self) -> Ordering {
-        use ParamKindOrd::*;
-        let to_int = |v| match v {
-            Lifetime => 0,
-            Infer | Type | Const => 1,
-        };
-
-        to_int(*self).cmp(&to_int(*other))
-    }
-}
-impl PartialOrd for ParamKindOrd {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-impl PartialEq for ParamKindOrd {
-    fn eq(&self, other: &Self) -> bool {
-        self.cmp(other) == Ordering::Equal
-    }
+    TypeOrConst,
 }
-impl Eq for ParamKindOrd {}
 
 impl fmt::Display for ParamKindOrd {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             ParamKindOrd::Lifetime => "lifetime".fmt(f),
-            ParamKindOrd::Type => "type".fmt(f),
-            ParamKindOrd::Const { .. } => "const".fmt(f),
-            ParamKindOrd::Infer => "infer".fmt(f),
+            ParamKindOrd::TypeOrConst => "type and const".fmt(f),
         }
     }
 }
@@ -2367,9 +2337,9 @@ pub fn is_async(self) -> bool {
     }
 
     /// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
-    pub fn opt_return_id(self) -> Option<NodeId> {
+    pub fn opt_return_id(self) -> Option<(NodeId, Span)> {
         match self {
-            Async::Yes { return_impl_trait_id, .. } => Some(return_impl_trait_id),
+            Async::Yes { return_impl_trait_id, span, .. } => Some((return_impl_trait_id, span)),
             Async::No => None,
         }
     }
@@ -3075,7 +3045,8 @@ mod size_asserts {
     static_assert_size!(Block, 48);
     static_assert_size!(Expr, 104);
     static_assert_size!(ExprKind, 72);
-    static_assert_size!(Fn, 192);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(Fn, 184);
     static_assert_size!(ForeignItem, 96);
     static_assert_size!(ForeignItemKind, 24);
     static_assert_size!(GenericArg, 24);
index 5b72ec2b6015c32550e8f53eb0ab6f01d3495fc1..6b0dac7c2f0b8d539bff0bf06ba0b622777bfd65 100644 (file)
@@ -232,6 +232,8 @@ pub fn meta_kind(&self) -> Option<MetaItemKind> {
 }
 
 impl Attribute {
+    /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
+    /// So `#[doc = "doc"]` will return `false`.
     pub fn is_doc_comment(&self) -> bool {
         match self.kind {
             AttrKind::Normal(..) => false,
index b0e9fe0469c41baab379f1b599301efda043f76f..90bb01aa2165dee8b9deaf969f7b243e73dd2436 100644 (file)
@@ -220,7 +220,7 @@ pub(crate) fn lower_inline_asm(
                                 &sym.qself,
                                 &sym.path,
                                 ParamMode::Optional,
-                                ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                                &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                             );
                             hir::InlineAsmOperand::SymStatic { path, def_id }
                         } else {
index 7cbfe143b4d83d3701a7b30e5571f8e4d4322c1c..7465706d1a9bb78b039f86ebdf8df23ab6ac7ecf 100644 (file)
@@ -84,10 +84,9 @@ fn lower_stmts(
     }
 
     fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
-        let ty = l
-            .ty
-            .as_ref()
-            .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
+        let ty = l.ty.as_ref().map(|t| {
+            self.lower_ty(t, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Variable))
+        });
         let init = l.kind.init().map(|init| self.lower_expr(init));
         let hir_id = self.lower_node_id(l.id);
         let pat = self.lower_pat(&l.pat);
index 4adeaef9bbfa832d708a5275c5209229c105c37f..c87d0ca96570e74f2904068202102ce712b68a9a 100644 (file)
@@ -334,3 +334,14 @@ pub struct InclusiveRangeWithNoEnd {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(SessionDiagnostic, Clone, Copy)]
+#[diag(ast_lowering::trait_fn_async, code = "E0706")]
+#[note]
+#[note(ast_lowering::note2)]
+pub struct TraitFnAsync {
+    #[primary_span]
+    pub fn_span: Span,
+    #[label]
+    pub span: Span,
+}
index 77babeb5d39d186099b6b9f2505b6522c0d9a928..f929549d70448100ea8c7f2516e4ac440f02066b 100644 (file)
@@ -66,7 +66,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                         seg,
                         ParamMode::Optional,
                         ParenthesizedGenericArgs::Err,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                     ));
                     let receiver = self.lower_expr(receiver);
                     let args =
@@ -89,14 +89,14 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                 }
                 ExprKind::Cast(ref expr, ref ty) => {
                     let expr = self.lower_expr(expr);
-                    let ty =
-                        self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                    let ty = self
+                        .lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                     hir::ExprKind::Cast(expr, ty)
                 }
                 ExprKind::Type(ref expr, ref ty) => {
                     let expr = self.lower_expr(expr);
-                    let ty =
-                        self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                    let ty = self
+                        .lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                     hir::ExprKind::Type(expr, ty)
                 }
                 ExprKind::AddrOf(k, m, ref ohs) => {
@@ -219,7 +219,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                         qself,
                         path,
                         ParamMode::Optional,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                     );
                     hir::ExprKind::Path(qpath)
                 }
@@ -253,7 +253,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                             &se.qself,
                             &se.path,
                             ParamMode::Optional,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                         )),
                         self.arena
                             .alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
@@ -550,12 +550,14 @@ pub(super) fn make_async_expr(
         async_gen_kind: hir::AsyncGeneratorKind,
         body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
     ) -> hir::ExprKind<'hir> {
-        let output = match ret_ty {
-            Some(ty) => hir::FnRetTy::Return(
-                self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)),
-            ),
-            None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
-        };
+        let output =
+            match ret_ty {
+                Some(ty) => hir::FnRetTy::Return(self.lower_ty(
+                    &ty,
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock),
+                )),
+                None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
+            };
 
         // Resume argument type. We let the compiler infer this to simplify the lowering. It is
         // fully constrained by `future::from_generator`.
@@ -847,21 +849,22 @@ fn lower_expr_closure(
             (body_id, generator_option)
         });
 
-        let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
-        // Lower outside new scope to preserve `is_in_loop_condition`.
-        let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
-
-        let c = self.arena.alloc(hir::Closure {
-            binder: binder_clause,
-            capture_clause,
-            bound_generic_params,
-            fn_decl,
-            body: body_id,
-            fn_decl_span: self.lower_span(fn_decl_span),
-            movability: generator_option,
-        });
+        self.lower_lifetime_binder(closure_id, generic_params, |lctx, bound_generic_params| {
+            // Lower outside new scope to preserve `is_in_loop_condition`.
+            let fn_decl = lctx.lower_fn_decl(decl, None, fn_decl_span, FnDeclKind::Closure, None);
+
+            let c = lctx.arena.alloc(hir::Closure {
+                binder: binder_clause,
+                capture_clause,
+                bound_generic_params,
+                fn_decl,
+                body: body_id,
+                fn_decl_span: lctx.lower_span(fn_decl_span),
+                movability: generator_option,
+            });
 
-        hir::ExprKind::Closure(c)
+            hir::ExprKind::Closure(c)
+        })
     }
 
     fn generator_movability_for_fn(
@@ -948,23 +951,24 @@ fn lower_expr_async_closure(
             body_id
         });
 
-        let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
-
-        // We need to lower the declaration outside the new scope, because we
-        // have to conserve the state of being inside a loop condition for the
-        // closure argument types.
-        let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
-
-        let c = self.arena.alloc(hir::Closure {
-            binder: binder_clause,
-            capture_clause,
-            bound_generic_params,
-            fn_decl,
-            body,
-            fn_decl_span: self.lower_span(fn_decl_span),
-            movability: None,
-        });
-        hir::ExprKind::Closure(c)
+        self.lower_lifetime_binder(closure_id, generic_params, |lctx, bound_generic_params| {
+            // We need to lower the declaration outside the new scope, because we
+            // have to conserve the state of being inside a loop condition for the
+            // closure argument types.
+            let fn_decl =
+                lctx.lower_fn_decl(&outer_decl, None, fn_decl_span, FnDeclKind::Closure, None);
+
+            let c = lctx.arena.alloc(hir::Closure {
+                binder: binder_clause,
+                capture_clause,
+                bound_generic_params,
+                fn_decl,
+                body,
+                fn_decl_span: lctx.lower_span(fn_decl_span),
+                movability: None,
+            });
+            hir::ExprKind::Closure(c)
+        })
     }
 
     /// Destructure the LHS of complex assignments.
@@ -1123,11 +1127,14 @@ fn destructure_assign_mut(
                         qself,
                         path,
                         ParamMode::Optional,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                     );
                     // Destructure like a tuple struct.
-                    let tuple_struct_pat =
-                        hir::PatKind::TupleStruct(qpath, pats, rest.map(|r| r.0));
+                    let tuple_struct_pat = hir::PatKind::TupleStruct(
+                        qpath,
+                        pats,
+                        hir::DotDotPos::new(rest.map(|r| r.0)),
+                    );
                     return self.pat_without_dbm(lhs.span, tuple_struct_pat);
                 }
             }
@@ -1139,7 +1146,7 @@ fn destructure_assign_mut(
                         qself,
                         path,
                         ParamMode::Optional,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                     );
                     // Destructure like a unit struct.
                     let unit_struct_pat = hir::PatKind::Path(qpath);
@@ -1163,7 +1170,7 @@ fn destructure_assign_mut(
                     &se.qself,
                     &se.path,
                     ParamMode::Optional,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                 );
                 let fields_omitted = match &se.rest {
                     StructRest::Base(e) => {
@@ -1182,13 +1189,13 @@ fn destructure_assign_mut(
             ExprKind::Tup(elements) => {
                 let (pats, rest) =
                     self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);
-                let tuple_pat = hir::PatKind::Tuple(pats, rest.map(|r| r.0));
+                let tuple_pat = hir::PatKind::Tuple(pats, hir::DotDotPos::new(rest.map(|r| r.0)));
                 return self.pat_without_dbm(lhs.span, tuple_pat);
             }
             ExprKind::Paren(e) => {
                 // We special-case `(..)` for consistency with patterns.
                 if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
-                    let tuple_pat = hir::PatKind::Tuple(&[], Some(0));
+                    let tuple_pat = hir::PatKind::Tuple(&[], hir::DotDotPos::new(Some(0)));
                     return self.pat_without_dbm(lhs.span, tuple_pat);
                 } else {
                     return self.destructure_assign_mut(e, eq_sign_span, assignments);
index 76f63d1d78a90c284aa3df5ff290ee356f0df509..52273778dcc009233e9cfe554c97e13163e092de 100644 (file)
@@ -1,6 +1,6 @@
 use super::errors::{InvalidAbi, MisplacedRelaxTraitBound};
 use super::ResolverAstLoweringExt;
-use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
+use super::{Arena, AstOwner, ImplTraitContext, ImplTraitPosition};
 use super::{FnDeclKind, LoweringContext, ParamMode};
 
 use rustc_ast::ptr::P;
@@ -25,6 +25,7 @@
 pub(super) struct ItemLowerer<'a, 'hir> {
     pub(super) tcx: TyCtxt<'hir>,
     pub(super) resolver: &'a mut ResolverAstLowering,
+    pub(super) ast_arena: &'a Arena<'static>,
     pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>,
     pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
 }
@@ -60,6 +61,7 @@ fn with_lctx(
             tcx: self.tcx,
             resolver: self.resolver,
             arena: self.tcx.hir_arena,
+            ast_arena: self.ast_arena,
 
             // HirId handling.
             bodies: Vec::new(),
@@ -264,10 +266,10 @@ fn lower_item_kind(
                     let body_id =
                         this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
 
-                    let itctx = ImplTraitContext::Universal;
-                    let (generics, decl) = this.lower_generics(generics, id, itctx, |this| {
+                    let mut itctx = ImplTraitContext::Universal;
+                    let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| {
                         let ret_id = asyncness.opt_return_id();
-                        this.lower_fn_decl(&decl, Some(id), FnDeclKind::Fn, ret_id)
+                        this.lower_fn_decl(&decl, Some(id), fn_sig_span, FnDeclKind::Fn, ret_id)
                     });
                     let sig = hir::FnSig {
                         decl,
@@ -311,8 +313,8 @@ fn lower_item_kind(
                 let (generics, ty) = self.lower_generics(
                     &generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    |this| this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| this.lower_ty(ty, &mut ImplTraitContext::TypeAliasesOpaqueTy),
                 );
                 hir::ItemKind::TyAlias(ty, generics)
             }
@@ -324,7 +326,7 @@ fn lower_item_kind(
                 let (generics, ty) = self.lower_generics(
                     &generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| this.arena.alloc(this.ty(span, hir::TyKind::Err)),
                 );
                 hir::ItemKind::TyAlias(ty, generics)
@@ -333,7 +335,7 @@ fn lower_item_kind(
                 let (generics, variants) = self.lower_generics(
                     generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
                         this.arena.alloc_from_iter(
                             enum_definition.variants.iter().map(|x| this.lower_variant(x)),
@@ -346,7 +348,7 @@ fn lower_item_kind(
                 let (generics, struct_def) = self.lower_generics(
                     generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| this.lower_variant_data(hir_id, struct_def),
                 );
                 hir::ItemKind::Struct(struct_def, generics)
@@ -355,7 +357,7 @@ fn lower_item_kind(
                 let (generics, vdata) = self.lower_generics(
                     generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| this.lower_variant_data(hir_id, vdata),
                 );
                 hir::ItemKind::Union(vdata, generics)
@@ -383,18 +385,20 @@ fn lower_item_kind(
                 // method, it will not be considered an in-band
                 // lifetime to be added, but rather a reference to a
                 // parent lifetime.
-                let itctx = ImplTraitContext::Universal;
+                let mut itctx = ImplTraitContext::Universal;
                 let (generics, (trait_ref, lowered_ty)) =
-                    self.lower_generics(ast_generics, id, itctx, |this| {
+                    self.lower_generics(ast_generics, id, &mut itctx, |this| {
                         let trait_ref = trait_ref.as_ref().map(|trait_ref| {
                             this.lower_trait_ref(
                                 trait_ref,
-                                ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
+                                &mut ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
                             )
                         });
 
-                        let lowered_ty = this
-                            .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                        let lowered_ty = this.lower_ty(
+                            ty,
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+                        );
 
                         (trait_ref, lowered_ty)
                     });
@@ -433,11 +437,11 @@ fn lower_item_kind(
                 let (generics, (unsafety, items, bounds)) = self.lower_generics(
                     generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
                         let bounds = this.lower_param_bounds(
                             bounds,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                         );
                         let items = this.arena.alloc_from_iter(
                             items.iter().map(|item| this.lower_trait_item_ref(item)),
@@ -452,11 +456,11 @@ fn lower_item_kind(
                 let (generics, bounds) = self.lower_generics(
                     generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
                         this.lower_param_bounds(
                             bounds,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                         )
                     },
                 );
@@ -479,7 +483,7 @@ fn lower_const_item(
         span: Span,
         body: Option<&Expr>,
     ) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
-        let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+        let ty = self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
         (ty, self.lower_const_body(span, body))
     }
 
@@ -652,12 +656,18 @@ fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir
             kind: match i.kind {
                 ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
                     let fdec = &sig.decl;
-                    let itctx = ImplTraitContext::Universal;
+                    let mut itctx = ImplTraitContext::Universal;
                     let (generics, (fn_dec, fn_args)) =
-                        self.lower_generics(generics, i.id, itctx, |this| {
+                        self.lower_generics(generics, i.id, &mut itctx, |this| {
                             (
                                 // Disallow `impl Trait` in foreign items.
-                                this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
+                                this.lower_fn_decl(
+                                    fdec,
+                                    None,
+                                    sig.span,
+                                    FnDeclKind::ExternFn,
+                                    None,
+                                ),
                                 this.lower_fn_params_to_names(fdec),
                             )
                         });
@@ -665,8 +675,8 @@ fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir
                     hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
                 }
                 ForeignItemKind::Static(ref t, m, _) => {
-                    let ty =
-                        self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                    let ty = self
+                        .lower_ty(t, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                     hir::ForeignItemKind::Static(ty, m)
                 }
                 ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
@@ -734,11 +744,11 @@ fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'
                 qself,
                 path,
                 ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
-                ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
             );
             self.arena.alloc(t)
         } else {
-            self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+            self.lower_ty(&f.ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type))
         };
         let hir_id = self.lower_node_id(f.id);
         self.lower_attrs(hir_id, &f.attrs);
@@ -761,14 +771,21 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
 
         let (generics, kind, has_default) = match i.kind {
             AssocItemKind::Const(_, ref ty, ref default) => {
-                let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                let ty =
+                    self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                 let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
                 (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
             }
             AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
+                let asyncness = sig.header.asyncness;
                 let names = self.lower_fn_params_to_names(&sig.decl);
-                let (generics, sig) =
-                    self.lower_method_sig(generics, sig, i.id, FnDeclKind::Trait, None);
+                let (generics, sig) = self.lower_method_sig(
+                    generics,
+                    sig,
+                    i.id,
+                    FnDeclKind::Trait,
+                    asyncness.opt_return_id(),
+                );
                 (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
             }
             AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
@@ -796,15 +813,18 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
                 let (generics, kind) = self.lower_generics(
                     &generics,
                     i.id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
                         let ty = ty.as_ref().map(|x| {
-                            this.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+                            this.lower_ty(
+                                x,
+                                &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+                            )
                         });
                         hir::TraitItemKind::Type(
                             this.lower_param_bounds(
                                 bounds,
-                                ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                                &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                             ),
                             ty,
                         )
@@ -857,7 +877,8 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
 
         let (generics, kind) = match &i.kind {
             AssocItemKind::Const(_, ty, expr) => {
-                let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                let ty =
+                    self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                 (
                     hir::Generics::empty(),
                     hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
@@ -884,14 +905,14 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
                 self.lower_generics(
                     &generics,
                     i.id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| match ty {
                         None => {
                             let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err));
                             hir::ImplItemKind::TyAlias(ty)
                         }
                         Some(ty) => {
-                            let ty = this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
+                            let ty = this.lower_ty(ty, &mut ImplTraitContext::TypeAliasesOpaqueTy);
                             hir::ImplItemKind::TyAlias(ty)
                         }
                     },
@@ -1231,12 +1252,12 @@ fn lower_method_sig(
         sig: &FnSig,
         id: NodeId,
         kind: FnDeclKind,
-        is_async: Option<NodeId>,
+        is_async: Option<(NodeId, Span)>,
     ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
         let header = self.lower_fn_header(sig.header);
-        let itctx = ImplTraitContext::Universal;
-        let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
-            this.lower_fn_decl(&sig.decl, Some(id), kind, is_async)
+        let mut itctx = ImplTraitContext::Universal;
+        let (generics, decl) = self.lower_generics(generics, id, &mut itctx, |this| {
+            this.lower_fn_decl(&sig.decl, Some(id), sig.span, kind, is_async)
         });
         (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
     }
@@ -1301,7 +1322,7 @@ fn lower_generics<T>(
         &mut self,
         generics: &Generics,
         parent_node_id: NodeId,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
         f: impl FnOnce(&mut Self) -> T,
     ) -> (&'hir hir::Generics<'hir>, T) {
         debug_assert!(self.impl_trait_defs.is_empty());
@@ -1406,7 +1427,7 @@ pub(super) fn lower_generic_bound_predicate(
         id: NodeId,
         kind: &GenericParamKind,
         bounds: &[GenericBound],
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
         origin: PredicateOrigin,
     ) -> Option<hir::WherePredicate<'hir>> {
         // Do not create a clause if we do not have anything inside it.
@@ -1481,12 +1502,14 @@ fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicat
                 span,
             }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
                 bound_generic_params: self.lower_generic_params(bound_generic_params),
-                bounded_ty: self
-                    .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
+                bounded_ty: self.lower_ty(
+                    bounded_ty,
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+                ),
                 bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
                     self.lower_param_bound(
                         bound,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                     )
                 })),
                 span: self.lower_span(span),
@@ -1501,16 +1524,20 @@ fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicat
                 lifetime: self.lower_lifetime(lifetime),
                 bounds: self.lower_param_bounds(
                     bounds,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                 ),
                 in_where_clause: true,
             }),
             WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span }) => {
                 hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
-                    lhs_ty: self
-                        .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
-                    rhs_ty: self
-                        .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
+                    lhs_ty: self.lower_ty(
+                        lhs_ty,
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+                    ),
+                    rhs_ty: self.lower_ty(
+                        rhs_ty,
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+                    ),
                     span: self.lower_span(span),
                 })
             }
index 3a94c7a91b23f7adf1c60e43ffd678decd950be6..0720f23ed756d449ad3c7f50155ee323912cfa54 100644 (file)
@@ -42,8 +42,9 @@
 #[macro_use]
 extern crate tracing;
 
-use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
+use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait, TraitFnAsync};
 
+use rustc_arena::declare_arena;
 use rustc_ast::ptr::P;
 use rustc_ast::visit;
 use rustc_ast::{self as ast, *};
@@ -95,6 +96,13 @@ struct LoweringContext<'a, 'hir> {
     /// Used to allocate HIR nodes.
     arena: &'hir hir::Arena<'hir>,
 
+    /// Used to allocate temporary AST nodes for use during lowering.
+    /// This allows us to create "fake" AST -- these nodes can sometimes
+    /// be allocated on the stack, but other times we need them to live longer
+    /// than the current stack frame, so they can be collected into vectors
+    /// and things like that.
+    ast_arena: &'a Arena<'static>,
+
     /// Bodies inside the owner being lowered.
     bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
     /// Attributes inside the owner being lowered.
@@ -140,6 +148,15 @@ struct LoweringContext<'a, 'hir> {
     generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
 }
 
+declare_arena!([
+    [] tys: rustc_ast::Ty,
+    [] aba: rustc_ast::AngleBracketedArgs,
+    [] ptr: rustc_ast::PolyTraitRef,
+    // This _marker field is needed because `declare_arena` creates `Arena<'tcx>` and we need to
+    // use `'tcx`. If we don't have this we get a compile error.
+    [] _marker: std::marker::PhantomData<&'tcx ()>,
+]);
+
 trait ResolverAstLoweringExt {
     fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
     fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
@@ -235,6 +252,7 @@ enum ImplTraitContext {
     ReturnPositionOpaqueTy {
         /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
         origin: hir::OpaqueTyOrigin,
+        in_trait: bool,
     },
     /// Impl trait in type aliases.
     TypeAliasesOpaqueTy,
@@ -294,7 +312,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq)]
 enum FnDeclKind {
     Fn,
     Inherent,
@@ -306,9 +324,17 @@ enum FnDeclKind {
 }
 
 impl FnDeclKind {
-    fn impl_trait_return_allowed(&self) -> bool {
+    fn impl_trait_return_allowed(&self, tcx: TyCtxt<'_>) -> bool {
         match self {
             FnDeclKind::Fn | FnDeclKind::Inherent => true,
+            FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true,
+            _ => false,
+        }
+    }
+
+    fn impl_trait_in_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool {
+        match self {
+            FnDeclKind::Trait if tcx.features().return_position_impl_trait_in_trait => true,
             _ => false,
         }
     }
@@ -401,10 +427,13 @@ pub fn lower_to_hir<'hir>(tcx: TyCtxt<'hir>, (): ()) -> hir::Crate<'hir> {
         tcx.definitions_untracked().def_index_count(),
     );
 
+    let ast_arena = Arena::default();
+
     for def_id in ast_index.indices() {
         item::ItemLowerer {
             tcx,
             resolver: &mut resolver,
+            ast_arena: &ast_arena,
             ast_index: &ast_index,
             owners: &mut owners,
         }
@@ -660,6 +689,7 @@ fn hash_owner(
     /// actually used in the HIR, as that would trigger an assertion in the
     /// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped
     /// properly. Calling the method twice with the same `NodeId` is fine though.
+    #[instrument(level = "debug", skip(self), ret)]
     fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
         assert_ne!(ast_node_id, DUMMY_NODE_ID);
 
@@ -693,6 +723,7 @@ fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
     }
 
     /// Generate a new `HirId` without a backing `NodeId`.
+    #[instrument(level = "debug", skip(self), ret)]
     fn next_id(&mut self) -> hir::HirId {
         let owner = self.current_hir_id_owner;
         let local_id = self.item_local_id_counter;
@@ -808,23 +839,31 @@ fn lifetime_res_to_generic_param(
     /// name resolver owing to lifetime elision; this also populates the resolver's node-id->def-id
     /// map, so that later calls to `opt_node_id_to_def_id` that refer to these extra lifetime
     /// parameters will be successful.
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self, in_binder))]
     #[inline]
-    fn lower_lifetime_binder(
+    fn lower_lifetime_binder<R>(
         &mut self,
         binder: NodeId,
         generic_params: &[GenericParam],
-    ) -> &'hir [hir::GenericParam<'hir>] {
-        let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect();
+        in_binder: impl FnOnce(&mut Self, &'hir [hir::GenericParam<'hir>]) -> R,
+    ) -> R {
         let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
         debug!(?extra_lifetimes);
-        generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
-            self.lifetime_res_to_generic_param(ident, node_id, res)
-        }));
+        let extra_lifetimes: Vec<_> = extra_lifetimes
+            .into_iter()
+            .filter_map(|(ident, node_id, res)| {
+                self.lifetime_res_to_generic_param(ident, node_id, res)
+            })
+            .collect();
+
+        let generic_params: Vec<_> = self
+            .lower_generic_params_mut(generic_params)
+            .chain(extra_lifetimes.into_iter())
+            .collect();
         let generic_params = self.arena.alloc_from_iter(generic_params);
         debug!(?generic_params);
 
-        generic_params
+        in_binder(self, generic_params)
     }
 
     fn with_dyn_type_scope<T>(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T {
@@ -953,7 +992,7 @@ fn lower_mac_args(&self, args: &MacArgs) -> MacArgs {
     fn lower_assoc_ty_constraint(
         &mut self,
         constraint: &AssocConstraint,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
         // lower generic arguments of identifier in constraint
@@ -964,18 +1003,15 @@ fn lower_assoc_ty_constraint(
                 }
                 GenericArgs::Parenthesized(ref data) => {
                     self.emit_bad_parenthesized_trait_in_assoc_ty(data);
-                    self.lower_angle_bracketed_parameter_data(
-                        &data.as_angle_bracketed_args(),
-                        ParamMode::Explicit,
-                        itctx,
-                    )
-                    .0
+                    let aba = self.ast_arena.aba.alloc(data.as_angle_bracketed_args());
+                    self.lower_angle_bracketed_parameter_data(aba, ParamMode::Explicit, itctx).0
                 }
             };
             gen_args_ctor.into_generic_args(self)
         } else {
             self.arena.alloc(hir::GenericArgs::none())
         };
+        let mut itctx_tait = ImplTraitContext::TypeAliasesOpaqueTy;
 
         let kind = match constraint.kind {
             AssocConstraintKind::Equality { ref term } => {
@@ -1014,7 +1050,7 @@ fn lower_assoc_ty_constraint(
                     //
                     // FIXME: this is only needed until `impl Trait` is allowed in type aliases.
                     ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => {
-                        (true, ImplTraitContext::TypeAliasesOpaqueTy)
+                        (true, &mut itctx_tait)
                     }
 
                     // We are in the parameter position, but not within a dyn type:
@@ -1037,15 +1073,13 @@ fn lower_assoc_ty_constraint(
 
                     self.with_dyn_type_scope(false, |this| {
                         let node_id = this.next_node_id();
-                        let ty = this.lower_ty(
-                            &Ty {
-                                id: node_id,
-                                kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
-                                span: this.lower_span(constraint.span),
-                                tokens: None,
-                            },
-                            itctx,
-                        );
+                        let ty = this.ast_arena.tys.alloc(Ty {
+                            id: node_id,
+                            kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
+                            span: this.lower_span(constraint.span),
+                            tokens: None,
+                        });
+                        let ty = this.lower_ty(ty, itctx);
 
                         hir::TypeBindingKind::Equality { term: ty.into() }
                     })
@@ -1096,7 +1130,7 @@ fn emit_bad_parenthesized_trait_in_assoc_ty(&self, data: &ParenthesizedArgs) {
     fn lower_generic_arg(
         &mut self,
         arg: &ast::GenericArg,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::GenericArg<'hir> {
         match arg {
             ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
@@ -1158,7 +1192,7 @@ fn lower_generic_arg(
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
+    fn lower_ty(&mut self, t: &Ty, itctx: &mut ImplTraitContext) -> &'hir hir::Ty<'hir> {
         self.arena.alloc(self.lower_ty_direct(t, itctx))
     }
 
@@ -1168,7 +1202,7 @@ fn lower_path_ty(
         qself: &Option<QSelf>,
         path: &Path,
         param_mode: ParamMode,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::Ty<'hir> {
         // Check whether we should interpret this as a bare trait object.
         // This check mirrors the one in late resolution.  We only introduce this special case in
@@ -1181,19 +1215,20 @@ fn lower_path_ty(
             && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
         {
             let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
+                let poly_trait_ref = this.ast_arena.ptr.alloc(PolyTraitRef {
+                    bound_generic_params: vec![],
+                    trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
+                    span: t.span
+                });
                 let bound = this.lower_poly_trait_ref(
-                    &PolyTraitRef {
-                        bound_generic_params: vec![],
-                        trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
-                        span: t.span
-                    },
+                    poly_trait_ref,
                     itctx,
                 );
                 let bounds = this.arena.alloc_from_iter([bound]);
                 let lifetime_bound = this.elided_dyn_bound(t.span);
                 (bounds, lifetime_bound)
             });
-            let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
+            let kind = hir::TyKind::TraitObject(bounds, &lifetime_bound, TraitObjectSyntax::None);
             return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
         }
 
@@ -1210,7 +1245,7 @@ fn ty_tup(&mut self, span: Span, tys: &'hir [hir::Ty<'hir>]) -> hir::Ty<'hir> {
         self.ty(span, hir::TyKind::Tup(tys))
     }
 
-    fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
+    fn lower_ty_direct(&mut self, t: &Ty, itctx: &mut ImplTraitContext) -> hir::Ty<'hir> {
         let kind = match t.kind {
             TyKind::Infer => hir::TyKind::Infer,
             TyKind::Err => hir::TyKind::Err,
@@ -1233,14 +1268,15 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
                 hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
             }
             TyKind::BareFn(ref f) => {
-                let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
-                hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
-                    generic_params,
-                    unsafety: self.lower_unsafety(f.unsafety),
-                    abi: self.lower_extern(f.ext),
-                    decl: self.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
-                    param_names: self.lower_fn_params_to_names(&f.decl),
-                }))
+                self.lower_lifetime_binder(t.id, &f.generic_params, |lctx, generic_params| {
+                    hir::TyKind::BareFn(lctx.arena.alloc(hir::BareFnTy {
+                        generic_params,
+                        unsafety: lctx.lower_unsafety(f.unsafety),
+                        abi: lctx.lower_extern(f.ext),
+                        decl: lctx.lower_fn_decl(&f.decl, None, t.span, FnDeclKind::Pointer, None),
+                        param_names: lctx.lower_fn_params_to_names(&f.decl),
+                    }))
+                })
             }
             TyKind::Never => hir::TyKind::Never,
             TyKind::Tup(ref tys) => hir::TyKind::Tup(
@@ -1306,19 +1342,23 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
             TyKind::ImplTrait(def_node_id, ref bounds) => {
                 let span = t.span;
                 match itctx {
-                    ImplTraitContext::ReturnPositionOpaqueTy { origin } => {
-                        self.lower_opaque_impl_trait(span, origin, def_node_id, bounds, itctx)
-                    }
-                    ImplTraitContext::TypeAliasesOpaqueTy => {
-                        let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
-                        self.lower_opaque_impl_trait(
+                    ImplTraitContext::ReturnPositionOpaqueTy { origin, in_trait } => self
+                        .lower_opaque_impl_trait(
                             span,
-                            hir::OpaqueTyOrigin::TyAlias,
+                            *origin,
                             def_node_id,
                             bounds,
-                            nested_itctx,
-                        )
-                    }
+                            *in_trait,
+                            itctx,
+                        ),
+                    ImplTraitContext::TypeAliasesOpaqueTy => self.lower_opaque_impl_trait(
+                        span,
+                        hir::OpaqueTyOrigin::TyAlias,
+                        def_node_id,
+                        bounds,
+                        false,
+                        &mut ImplTraitContext::TypeAliasesOpaqueTy,
+                    ),
                     ImplTraitContext::Universal => {
                         let span = t.span;
                         let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
@@ -1330,6 +1370,21 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
                         }
                         path
                     }
+                    ImplTraitContext::Disallowed(
+                        position @ (ImplTraitPosition::TraitReturn | ImplTraitPosition::ImplReturn),
+                    ) => {
+                        self.tcx
+                            .sess
+                            .create_feature_err(
+                                MisplacedImplTrait {
+                                    span: t.span,
+                                    position: DiagnosticArgFromDisplay(&position),
+                                },
+                                sym::return_position_impl_trait_in_trait,
+                            )
+                            .emit();
+                        hir::TyKind::Err
+                    }
                     ImplTraitContext::Disallowed(position) => {
                         self.tcx.sess.emit_err(MisplacedImplTrait {
                             span: t.span,
@@ -1381,14 +1436,15 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
     /// added explicitly in the HIR). But this includes all the lifetimes, and we only want to
     /// capture the lifetimes that are referenced in the bounds. Therefore, we add *extra* lifetime parameters
     /// for the lifetimes that get captured (`'x`, in our example above) and reference those.
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     fn lower_opaque_impl_trait(
         &mut self,
         span: Span,
         origin: hir::OpaqueTyOrigin,
         opaque_ty_node_id: NodeId,
         bounds: &GenericBounds,
-        itctx: ImplTraitContext,
+        in_trait: bool,
+        itctx: &mut ImplTraitContext,
     ) -> hir::TyKind<'hir> {
         // Make sure we know that some funky desugaring has been going on here.
         // This is a first: there is code in other places like for loop
@@ -1476,6 +1532,7 @@ fn lower_opaque_impl_trait(
                     }),
                     bounds: hir_bounds,
                     origin,
+                    in_trait,
                 };
                 debug!(?opaque_ty_item);
 
@@ -1502,7 +1559,7 @@ fn lower_opaque_impl_trait(
         debug!(?lifetimes);
 
         // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
-        hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
+        hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes, in_trait)
     }
 
     /// Registers a new opaque type with the proper `NodeId`s and
@@ -1561,8 +1618,7 @@ fn create_lifetime_defs(
 
                 LifetimeRes::Fresh { param, binder: _ } => {
                     debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
-                    let old_def_id = self.local_def_id(param);
-                    if remapping.get(&old_def_id).is_none() {
+                    if let Some(old_def_id) = self.opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
                         let node_id = self.next_node_id();
 
                         let new_def_id = self.create_def(
@@ -1611,19 +1667,17 @@ fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
     // `fn_def_id`: if `Some`, impl Trait arguments are lowered into generic parameters on the
     //      given DefId, otherwise impl Trait is disallowed. Must be `Some` if
     //      `make_ret_async` is also `Some`.
-    // `impl_trait_return_allow`: determines whether `impl Trait` can be used in return position.
-    //      This guards against trait declarations and implementations where `impl Trait` is
-    //      disallowed.
     // `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the
     //      return type. This is used for `async fn` declarations. The `NodeId` is the ID of the
-    //      return type `impl Trait` item.
+    //      return type `impl Trait` item, and the `Span` points to the `async` keyword.
     #[instrument(level = "debug", skip(self))]
     fn lower_fn_decl(
         &mut self,
         decl: &FnDecl,
         fn_node_id: Option<NodeId>,
+        fn_span: Span,
         kind: FnDeclKind,
-        make_ret_async: Option<NodeId>,
+        make_ret_async: Option<(NodeId, Span)>,
     ) -> &'hir hir::FnDecl<'hir> {
         let c_variadic = decl.c_variadic();
 
@@ -1636,11 +1690,11 @@ fn lower_fn_decl(
         }
         let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
             if fn_node_id.is_some() {
-                self.lower_ty_direct(&param.ty, ImplTraitContext::Universal)
+                self.lower_ty_direct(&param.ty, &mut ImplTraitContext::Universal)
             } else {
                 self.lower_ty_direct(
                     &param.ty,
-                    ImplTraitContext::Disallowed(match kind {
+                    &mut ImplTraitContext::Disallowed(match kind {
                         FnDeclKind::Fn | FnDeclKind::Inherent => {
                             unreachable!("fn should allow in-band lifetimes")
                         }
@@ -1654,20 +1708,63 @@ fn lower_fn_decl(
             }
         }));
 
-        let output = if let Some(ret_id) = make_ret_async {
-            self.lower_async_fn_ret_ty(
-                &decl.output,
-                fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
-                ret_id,
-            )
+        let output = if let Some((ret_id, span)) = make_ret_async {
+            match kind {
+                FnDeclKind::Trait => {
+                    if !kind.impl_trait_in_trait_allowed(self.tcx) {
+                        self.tcx
+                            .sess
+                            .create_feature_err(
+                                TraitFnAsync { fn_span, span },
+                                sym::return_position_impl_trait_in_trait,
+                            )
+                            .emit();
+                    }
+                    self.lower_async_fn_ret_ty(
+                        &decl.output,
+                        fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
+                        ret_id,
+                        true,
+                    )
+                }
+                _ => {
+                    if !kind.impl_trait_return_allowed(self.tcx) {
+                        if kind == FnDeclKind::Impl {
+                            self.tcx
+                                .sess
+                                .create_feature_err(
+                                    TraitFnAsync { fn_span, span },
+                                    sym::return_position_impl_trait_in_trait,
+                                )
+                                .emit();
+                        } else {
+                            self.tcx.sess.emit_err(TraitFnAsync { fn_span, span });
+                        }
+                    }
+                    self.lower_async_fn_ret_ty(
+                        &decl.output,
+                        fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
+                        ret_id,
+                        false,
+                    )
+                }
+            }
         } else {
             match decl.output {
                 FnRetTy::Ty(ref ty) => {
-                    let context = match fn_node_id {
-                        Some(fn_node_id) if kind.impl_trait_return_allowed() => {
+                    let mut context = match fn_node_id {
+                        Some(fn_node_id) if kind.impl_trait_return_allowed(self.tcx) => {
                             let fn_def_id = self.local_def_id(fn_node_id);
                             ImplTraitContext::ReturnPositionOpaqueTy {
                                 origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+                                in_trait: false,
+                            }
+                        }
+                        Some(fn_node_id) if kind.impl_trait_in_trait_allowed(self.tcx) => {
+                            let fn_def_id = self.local_def_id(fn_node_id);
+                            ImplTraitContext::ReturnPositionOpaqueTy {
+                                origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+                                in_trait: true,
                             }
                         }
                         _ => ImplTraitContext::Disallowed(match kind {
@@ -1681,7 +1778,7 @@ fn lower_fn_decl(
                             FnDeclKind::Impl => ImplTraitPosition::ImplReturn,
                         }),
                     };
-                    hir::FnRetTy::Return(self.lower_ty(ty, context))
+                    hir::FnRetTy::Return(self.lower_ty(ty, &mut context))
                 }
                 FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
             }
@@ -1731,6 +1828,7 @@ fn lower_async_fn_ret_ty(
         output: &FnRetTy,
         fn_node_id: NodeId,
         opaque_ty_node_id: NodeId,
+        in_trait: bool,
     ) -> hir::FnRetTy<'hir> {
         let span = output.span();
 
@@ -1857,8 +1955,14 @@ fn lower_async_fn_ret_ty(
                 //
                 // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
                 // hence the elision takes place at the fn site.
-                let future_bound =
-                    this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span);
+                let future_bound = this.lower_async_fn_output_type_to_future_bound(
+                    output,
+                    span,
+                    ImplTraitContext::ReturnPositionOpaqueTy {
+                        origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+                        in_trait,
+                    },
+                );
 
                 let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
                     |&(new_node_id, lifetime, _)| {
@@ -1896,6 +2000,7 @@ fn lower_async_fn_ret_ty(
                     }),
                     bounds: arena_vec![this; future_bound],
                     origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+                    in_trait,
                 };
 
                 trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
@@ -1932,8 +2037,7 @@ fn lower_async_fn_ret_ty(
                 let res = res.unwrap_or(
                     self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
                 );
-                let l = self.new_named_lifetime_with_res(id, span, ident, res);
-                hir::GenericArg::Lifetime(l)
+                hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, span, ident, res))
             },
         ));
 
@@ -1941,8 +2045,11 @@ fn lower_async_fn_ret_ty(
         // Foo = impl Trait` is, internally, created as a child of the
         // async fn, so the *type parameters* are inherited.  It's
         // only the lifetime parameters that we must supply.
-        let opaque_ty_ref =
-            hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, generic_args);
+        let opaque_ty_ref = hir::TyKind::OpaqueDef(
+            hir::ItemId { def_id: opaque_ty_def_id },
+            generic_args,
+            in_trait,
+        );
         let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
         hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
     }
@@ -1951,8 +2058,8 @@ fn lower_async_fn_ret_ty(
     fn lower_async_fn_output_type_to_future_bound(
         &mut self,
         output: &FnRetTy,
-        fn_def_id: LocalDefId,
         span: Span,
+        mut nested_impl_trait_context: ImplTraitContext,
     ) -> hir::GenericBound<'hir> {
         // Compute the `T` in `Future<Output = T>` from the return type.
         let output_ty = match output {
@@ -1960,10 +2067,7 @@ fn lower_async_fn_output_type_to_future_bound(
                 // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
                 // `impl Future` opaque type that `async fn` implicitly
                 // generates.
-                let context = ImplTraitContext::ReturnPositionOpaqueTy {
-                    origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
-                };
-                self.lower_ty(ty, context)
+                self.lower_ty(ty, &mut nested_impl_trait_context)
             }
             FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
         };
@@ -1989,7 +2093,7 @@ fn lower_async_fn_output_type_to_future_bound(
     fn lower_param_bound(
         &mut self,
         tpb: &GenericBound,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::GenericBound<'hir> {
         match tpb {
             GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
@@ -2002,7 +2106,7 @@ fn lower_param_bound(
         }
     }
 
-    fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
+    fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime {
         let span = self.lower_span(l.ident.span);
         let ident = self.lower_ident(l.ident);
         self.new_named_lifetime(l.id, l.id, span, ident)
@@ -2015,7 +2119,7 @@ fn new_named_lifetime_with_res(
         span: Span,
         ident: Ident,
         res: LifetimeRes,
-    ) -> hir::Lifetime {
+    ) -> &'hir hir::Lifetime {
         let name = match res {
             LifetimeRes::Param { param, .. } => {
                 let p_name = ParamName::Plain(ident);
@@ -2036,7 +2140,11 @@ fn new_named_lifetime_with_res(
         };
 
         debug!(?name);
-        hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
+        self.arena.alloc(hir::Lifetime {
+            hir_id: self.lower_node_id(id),
+            span: self.lower_span(span),
+            name,
+        })
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -2046,7 +2154,7 @@ fn new_named_lifetime(
         new_id: NodeId,
         span: Span,
         ident: Ident,
-    ) -> hir::Lifetime {
+    ) -> &'hir hir::Lifetime {
         let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
         self.new_named_lifetime_with_res(new_id, span, ident, res)
     }
@@ -2101,7 +2209,7 @@ fn lower_generic_param_kind(
             GenericParamKind::Type { ref default, .. } => {
                 let kind = hir::GenericParamKind::Type {
                     default: default.as_ref().map(|x| {
-                        self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+                        self.lower_ty(x, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type))
                     }),
                     synthetic: false,
                 };
@@ -2109,7 +2217,8 @@ fn lower_generic_param_kind(
                 (hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
             }
             GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
-                let ty = self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                let ty =
+                    self.lower_ty(&ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                 let default = default.as_ref().map(|def| self.lower_anon_const(def));
                 (
                     hir::ParamName::Plain(self.lower_ident(param.ident)),
@@ -2119,7 +2228,11 @@ fn lower_generic_param_kind(
         }
     }
 
-    fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef<'hir> {
+    fn lower_trait_ref(
+        &mut self,
+        p: &TraitRef,
+        itctx: &mut ImplTraitContext,
+    ) -> hir::TraitRef<'hir> {
         let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
             hir::QPath::Resolved(None, path) => path,
             qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
@@ -2131,34 +2244,41 @@ fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::Tra
     fn lower_poly_trait_ref(
         &mut self,
         p: &PolyTraitRef,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::PolyTraitRef<'hir> {
-        let bound_generic_params =
-            self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
-        let trait_ref = self.lower_trait_ref(&p.trait_ref, itctx);
-        hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
+        self.lower_lifetime_binder(
+            p.trait_ref.ref_id,
+            &p.bound_generic_params,
+            |lctx, bound_generic_params| {
+                let trait_ref = lctx.lower_trait_ref(&p.trait_ref, itctx);
+                hir::PolyTraitRef { bound_generic_params, trait_ref, span: lctx.lower_span(p.span) }
+            },
+        )
     }
 
-    fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
+    fn lower_mt(&mut self, mt: &MutTy, itctx: &mut ImplTraitContext) -> hir::MutTy<'hir> {
         hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
     fn lower_param_bounds(
         &mut self,
         bounds: &[GenericBound],
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::GenericBounds<'hir> {
         self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
     }
 
-    fn lower_param_bounds_mut<'s>(
+    fn lower_param_bounds_mut<'s, 'b>(
         &'s mut self,
         bounds: &'s [GenericBound],
-        itctx: ImplTraitContext,
-    ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> {
+        itctx: &'b mut ImplTraitContext,
+    ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> + Captures<'b>
+    {
         bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
     fn lower_generic_and_bounds(
         &mut self,
         node_id: NodeId,
@@ -2184,7 +2304,7 @@ fn lower_generic_and_bounds(
             node_id,
             &GenericParamKind::Type { default: None },
             bounds,
-            ImplTraitContext::Universal,
+            &mut ImplTraitContext::Universal,
             hir::PredicateOrigin::ImplTrait,
         );
 
@@ -2452,14 +2572,14 @@ fn ty_path(
     /// bound, like the bound in `Box<dyn Debug>`. This method is not invoked
     /// when the bound is written, even if it is written with `'_` like in
     /// `Box<dyn Debug + '_>`. In those cases, `lower_lifetime` is invoked.
-    fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime {
+    fn elided_dyn_bound(&mut self, span: Span) -> &'hir hir::Lifetime {
         let r = hir::Lifetime {
             hir_id: self.next_id(),
             span: self.lower_span(span),
             name: hir::LifetimeName::ImplicitObjectLifetimeDefault,
         };
         debug!("elided_dyn_bound: r={:?}", r);
-        r
+        self.arena.alloc(r)
     }
 }
 
index a1eee1be7984f63dfd174cc414d26c42820f50a5..1ea76fdbfcbbbab5996de26b9a163f8229d37792 100644 (file)
@@ -37,7 +37,7 @@ pub(crate) fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
                             qself,
                             path,
                             ParamMode::Optional,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                         );
                         let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
                         break hir::PatKind::TupleStruct(qpath, pats, ddpos);
@@ -53,7 +53,7 @@ pub(crate) fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
                             qself,
                             path,
                             ParamMode::Optional,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                         );
                         break hir::PatKind::Path(qpath);
                     }
@@ -63,7 +63,7 @@ pub(crate) fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
                             qself,
                             path,
                             ParamMode::Optional,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                         );
 
                         let fs = self.arena.alloc_from_iter(fields.iter().map(|f| {
@@ -116,7 +116,7 @@ fn lower_pat_tuple(
         &mut self,
         pats: &[P<Pat>],
         ctx: &str,
-    ) -> (&'hir [hir::Pat<'hir>], Option<usize>) {
+    ) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) {
         let mut elems = Vec::with_capacity(pats.len());
         let mut rest = None;
 
@@ -160,7 +160,7 @@ fn lower_pat_tuple(
             }
         }
 
-        (self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
+        (self.arena.alloc_from_iter(elems), hir::DotDotPos::new(rest.map(|(ddpos, _)| ddpos)))
     }
 
     /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
index de1467b1b07d6bee2031d423ca2b7d847e585ec5..a3d864023a9ff6319eb6991f427870a566ca25a6 100644 (file)
@@ -22,7 +22,7 @@ pub(crate) fn lower_qpath(
         qself: &Option<QSelf>,
         p: &Path,
         param_mode: ParamMode,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::QPath<'hir> {
         let qself_position = qself.as_ref().map(|q| q.position);
         let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
@@ -156,7 +156,7 @@ pub(crate) fn lower_path_extra(
                     segment,
                     param_mode,
                     ParenthesizedGenericArgs::Err,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                 )
             })),
             span: self.lower_span(p.span),
@@ -180,7 +180,7 @@ pub(crate) fn lower_path_segment(
         segment: &PathSegment,
         param_mode: ParamMode,
         parenthesized_generic_args: ParenthesizedGenericArgs,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::PathSegment<'hir> {
         debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
         let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
@@ -316,7 +316,7 @@ pub(crate) fn lower_angle_bracketed_parameter_data(
         &mut self,
         data: &AngleBracketedArgs,
         param_mode: ParamMode,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> (GenericArgsCtor<'hir>, bool) {
         let has_non_lt_args = data.args.iter().any(|arg| match arg {
             AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
@@ -350,12 +350,14 @@ fn lower_parenthesized_parameter_data(
         // we generally don't permit such things (see #51008).
         let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
         let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
-            self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
+            self.lower_ty_direct(
+                ty,
+                &mut ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam),
+            )
         }));
         let output_ty = match output {
-            FnRetTy::Ty(ty) => {
-                self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
-            }
+            FnRetTy::Ty(ty) => self
+                .lower_ty(&ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
             FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
         };
         let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
index d6d8881a53a146e0c4c62d8fb93123122fb735fe..6a0a1b08360133296069b79a284e80cfd2873707 100644 (file)
@@ -290,12 +290,6 @@ fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Iden
         }
     }
 
-    fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
-        if let Async::Yes { span, .. } = asyncness {
-            self.session.emit_err(TraitFnAsync { fn_span, span });
-        }
-    }
-
     fn check_trait_fn_not_const(&self, constness: Const) {
         if let Const::Yes(span) = constness {
             self.session.emit_err(TraitFnConst { span });
@@ -845,10 +839,10 @@ fn validate_generic_param_order(
         let (kind, bounds, span) = (&param.kind, &param.bounds, ident.span);
         let (ord_kind, ident) = match &param.kind {
             GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
-            GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
+            GenericParamKind::Type { default: _ } => (ParamKindOrd::TypeOrConst, ident.to_string()),
             GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
                 let ty = pprust::ty_to_string(ty);
-                (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
+                (ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty))
             }
         };
         param_idents.push((kind, ord_kind, bounds, idx, ident));
@@ -1596,7 +1590,6 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
             self.invalid_visibility(&item.vis, None);
             if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
                 self.check_trait_fn_not_const(sig.header.constness);
-                self.check_trait_fn_not_async(item.span, sig.header.asyncness);
             }
         }
 
index 21467e57651983fc78b918370d749af62bb78372..4f3b09c587113597d816dfc5bec14ca21283b91b 100644 (file)
@@ -79,17 +79,6 @@ pub enum InvalidVisibilityNote {
     IndividualForeignItems,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::trait_fn_async, code = "E0706")]
-#[note]
-#[note(ast_passes::note2)]
-pub struct TraitFnAsync {
-    #[primary_span]
-    pub fn_span: Span,
-    #[label]
-    pub span: Span,
-}
-
 #[derive(SessionDiagnostic)]
 #[diag(ast_passes::trait_fn_const, code = "E0379")]
 pub struct TraitFnConst {
index e1404ab15efa37add14cfed8823837b20c016c7a..bb972a18acbd8d5c4bdae5faa65a9d614b17e991 100644 (file)
@@ -1045,18 +1045,16 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                                 &name,
                             ),
                         });
-                    } else {
-                        if matches!(
-                            meta_item.name_or_empty(),
-                            sym::C | sym::simd | sym::transparent
-                        ) || int_type_of_word(meta_item.name_or_empty()).is_some()
-                        {
-                            recognised = true;
-                            sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
-                                span: meta_item.span,
-                                name: meta_item.name_or_empty().to_ident_string(),
-                            });
-                        }
+                    } else if matches!(
+                        meta_item.name_or_empty(),
+                        sym::C | sym::simd | sym::transparent
+                    ) || int_type_of_word(meta_item.name_or_empty()).is_some()
+                    {
+                        recognised = true;
+                        sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
+                            span: meta_item.span,
+                            name: meta_item.name_or_empty().to_ident_string(),
+                        });
                     }
                 } else if let MetaItemKind::List(_) = meta_item.kind {
                     if meta_item.has_name(sym::align) {
index 816288eb50b293e35518b7af57063dc19bc688d9..9f7a4d49989ab6b3aeddac712161c6168a120de3 100644 (file)
@@ -391,7 +391,7 @@ fn statement_effect(
             | mir::StatementKind::Retag { .. }
             | mir::StatementKind::AscribeUserType(..)
             | mir::StatementKind::Coverage(..)
-            | mir::StatementKind::CopyNonOverlapping(..)
+            | mir::StatementKind::Intrinsic(..)
             | mir::StatementKind::Nop => {}
         }
     }
index 75fde53b6cdecd24452e0293db2118ad598f9620..0707ff5ed02a0abf81f53c14173db134235f45a5 100644 (file)
@@ -772,7 +772,7 @@ fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Opti
     fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
         let hir = self.infcx.tcx.hir();
 
-        let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else {
+        let hir::TyKind::OpaqueDef(id, _, _) = hir_ty.kind else {
             span_bug!(
                 hir_ty.span,
                 "lowered return type of async fn is not OpaqueDef: {:?}",
index ec521b1cf0afdfa0fe7786725a174a679b0113b9..3157f861d93bec9fc047fd81d750d218d2248f7b 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue};
+use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue};
 use rustc_middle::mir::{BorrowKind, Mutability, Operand};
 use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
 use rustc_middle::mir::{Statement, StatementKind};
@@ -63,23 +63,24 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             StatementKind::FakeRead(box (_, _)) => {
                 // Only relevant for initialized/liveness/safety checks.
             }
-            StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
+            StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+                self.consume_operand(location, op);
+            }
+            StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
                 ref src,
                 ref dst,
                 ref count,
-            }) => {
+            })) => {
                 self.consume_operand(location, src);
                 self.consume_operand(location, dst);
                 self.consume_operand(location, count);
             }
-            StatementKind::Nop
+            // Only relevant for mir typeck
+            StatementKind::AscribeUserType(..)
+            // Doesn't have any language semantics
             | StatementKind::Coverage(..)
-            | StatementKind::AscribeUserType(..)
-            | StatementKind::Retag { .. }
-            | StatementKind::StorageLive(..) => {
-                // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
-                // to borrow check.
-            }
+            // Does not actually affect borrowck
+            | StatementKind::StorageLive(..) => {}
             StatementKind::StorageDead(local) => {
                 self.access_place(
                     location,
@@ -88,7 +89,10 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                     LocalMutationIsAllowed::Yes,
                 );
             }
-            StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+            StatementKind::Nop
+            | StatementKind::Retag { .. }
+            | StatementKind::Deinit(..)
+            | StatementKind::SetDiscriminant { .. } => {
                 bug!("Statement not allowed in this MIR phase")
             }
         }
index 20c22575bd1fadcd27e20412204801a0f34184d0..ec652f852179a43c6aff5401317ea097894dfe39 100644 (file)
@@ -26,8 +26,8 @@
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
 use rustc_middle::mir::{
-    traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
-    PlaceRef, VarDebugInfoContents,
+    traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
+    Place, PlaceElem, PlaceRef, VarDebugInfoContents,
 };
 use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
 use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
@@ -591,22 +591,19 @@ fn visit_statement_before_primary_effect(
                     flow_state,
                 );
             }
-            StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
-                ..
-            }) => {
-                span_bug!(
+            StatementKind::Intrinsic(box ref kind) => match kind {
+                NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state),
+                NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
                     span,
                     "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
                 )
             }
-            StatementKind::Nop
+            // Only relevant for mir typeck
+            StatementKind::AscribeUserType(..)
+            // Doesn't have any language semantics
             | StatementKind::Coverage(..)
-            | StatementKind::AscribeUserType(..)
-            | StatementKind::Retag { .. }
-            | StatementKind::StorageLive(..) => {
-                // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
-                // to borrow check.
-            }
+            // Does not actually affect borrowck
+            | StatementKind::StorageLive(..) => {}
             StatementKind::StorageDead(local) => {
                 self.access_place(
                     location,
@@ -616,7 +613,10 @@ fn visit_statement_before_primary_effect(
                     flow_state,
                 );
             }
-            StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+            StatementKind::Nop
+            | StatementKind::Retag { .. }
+            | StatementKind::Deinit(..)
+            | StatementKind::SetDiscriminant { .. } => {
                 bug!("Statement not allowed in this MIR phase")
             }
         }
index 8dc9368a0b994d197943ea914fa19b6578b554dc..de70b17e44ccd77204faa0d68b6be9091c984f91 100644 (file)
@@ -135,7 +135,6 @@ pub struct RegionInferenceContext<'tcx> {
 /// adds a new lower bound to the SCC it is analyzing: so you wind up
 /// with `'R: 'O` where `'R` is the pick-region and `'O` is the
 /// minimal viable option.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
 pub(crate) struct AppliedMemberConstraint {
     /// The SCC that was affected. (The "member region".)
     ///
index a620c987052ba0b987175df02e70fc9e5d3b9cd6..fc0e95f30c98fa8202508b35bf53493a57e3624c 100644 (file)
@@ -1302,12 +1302,13 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo
                     );
                 }
             }
-            StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
-                ..
-            }) => span_bug!(
-                stmt.source_info.span,
-                "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics",
-            ),
+            StatementKind::Intrinsic(box ref kind) => match kind {
+                NonDivergingIntrinsic::Assume(op) => self.check_operand(op, location),
+                NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
+                    stmt.source_info.span,
+                    "Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics",
+                ),
+            },
             StatementKind::FakeRead(..)
             | StatementKind::StorageLive(..)
             | StatementKind::StorageDead(..)
index c412e451a033e9619f2630e5362b5e0c12b4e08c..2aa11ac2eeaa653d1c0b2243afbf31e62effc467 100644 (file)
@@ -794,20 +794,31 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
         | StatementKind::AscribeUserType(..) => {}
 
         StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
-        StatementKind::CopyNonOverlapping(inner) => {
-            let dst = codegen_operand(fx, &inner.dst);
-            let pointee = dst
-                .layout()
-                .pointee_info_at(fx, rustc_target::abi::Size::ZERO)
-                .expect("Expected pointer");
-            let dst = dst.load_scalar(fx);
-            let src = codegen_operand(fx, &inner.src).load_scalar(fx);
-            let count = codegen_operand(fx, &inner.count).load_scalar(fx);
-            let elem_size: u64 = pointee.size.bytes();
-            let bytes =
-                if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
-            fx.bcx.call_memcpy(fx.target_config, dst, src, bytes);
-        }
+        StatementKind::Intrinsic(ref intrinsic) => match &**intrinsic {
+            // We ignore `assume` intrinsics, they are only useful for optimizations
+            NonDivergingIntrinsic::Assume(_) => {}
+            NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
+                src,
+                dst,
+                count,
+            }) => {
+                let dst = codegen_operand(fx, dst);
+                let pointee = dst
+                    .layout()
+                    .pointee_info_at(fx, rustc_target::abi::Size::ZERO)
+                    .expect("Expected pointer");
+                let dst = dst.load_scalar(fx);
+                let src = codegen_operand(fx, src).load_scalar(fx);
+                let count = codegen_operand(fx, count).load_scalar(fx);
+                let elem_size: u64 = pointee.size.bytes();
+                let bytes = if elem_size != 1 {
+                    fx.bcx.ins().imul_imm(count, elem_size as i64)
+                } else {
+                    count
+                };
+                fx.bcx.call_memcpy(fx.target_config, dst, src, bytes);
+            }
+        },
     }
 }
 
index 9224f499339cbd8e14cf6d5d75e8adaf608362a0..0305341da784e28dba54a1bdbb2892c1a937a994 100644 (file)
@@ -536,9 +536,11 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
                         {
                             return None;
                         }
-                        StatementKind::CopyNonOverlapping(_) => {
-                            return None;
-                        } // conservative handling
+                        StatementKind::Intrinsic(ref intrinsic) => match **intrinsic {
+                            NonDivergingIntrinsic::CopyNonOverlapping(..) => return None,
+                            NonDivergingIntrinsic::Assume(..) => {}
+                        },
+                        // conservative handling
                         StatementKind::Assign(_)
                         | StatementKind::FakeRead(_)
                         | StatementKind::SetDiscriminant { .. }
index e41ae1fbdbac54cd9a58bb80f4d8c9905e1738dc..97b395bcd05186b199e59026ddec9fda4472dc77 100644 (file)
@@ -42,10 +42,10 @@ pub(crate) fn codegen_set_discriminant<'tcx>(
         Variants::Multiple {
             tag: _,
             tag_field,
-            tag_encoding: TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
+            tag_encoding: TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start },
             variants: _,
         } => {
-            if variant_index != dataful_variant {
+            if variant_index != untagged_variant {
                 let niche = place.place_field(fx, mir::Field::new(tag_field));
                 let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
                 let niche_value = ty::ScalarInt::try_from_uint(
@@ -113,7 +113,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
             let res = CValue::by_val(val, dest_layout);
             dest.write_cvalue(fx, res);
         }
-        TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
+        TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
             // Rebase from niche values to discriminants, and check
             // whether the result is in range for the niche variants.
 
@@ -169,8 +169,9 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
                 fx.bcx.ins().iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
             };
 
-            let dataful_variant = fx.bcx.ins().iconst(cast_to, i64::from(dataful_variant.as_u32()));
-            let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant);
+            let untagged_variant =
+                fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32()));
+            let discr = fx.bcx.ins().select(is_niche, niche_discr, untagged_variant);
             let res = CValue::by_val(discr, dest_layout);
             dest.write_cvalue(fx, res);
         }
index 39e9e784a478b12a68268e2fa6c0b6209f864365..2e4ca594f91bb1b63e775902e2ce9ffe2f772232 100644 (file)
@@ -357,9 +357,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
     let usize_layout = fx.layout_of(fx.tcx.types.usize);
 
     match intrinsic {
-        sym::assume => {
-            intrinsic_args!(fx, args => (_a); intrinsic);
-        }
         sym::likely | sym::unlikely => {
             intrinsic_args!(fx, args => (a); intrinsic);
 
@@ -819,20 +816,13 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             ret.write_cvalue(fx, val);
         }
 
-        sym::ptr_guaranteed_eq => {
+        sym::ptr_guaranteed_cmp => {
             intrinsic_args!(fx, args => (a, b); intrinsic);
 
             let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b);
             ret.write_cvalue(fx, val);
         }
 
-        sym::ptr_guaranteed_ne => {
-            intrinsic_args!(fx, args => (a, b); intrinsic);
-
-            let val = crate::num::codegen_ptr_binop(fx, BinOp::Ne, a, b);
-            ret.write_cvalue(fx, val);
-        }
-
         sym::caller_location => {
             intrinsic_args!(fx, args => (); intrinsic);
 
index ccb6cbbc2c8a74bb98ab5a977c8698dea5b7c769..aa1c271c31cb46d7695995756b2d09e69311bab4 100644 (file)
@@ -158,10 +158,6 @@ fn const_to_opt_u128(&self, _v: RValue<'gcc>, _sign_ext: bool) -> Option<u128> {
         None
     }
 
-    fn zst_to_backend(&self, _ty: Type<'gcc>) -> RValue<'gcc> {
-        self.const_undef(self.type_ix(0))
-    }
-
     fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
         let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
         match cv {
index 0ce161d7e756cfbc2960375df513f12bd917733f..26f5225f6b445b820518fc74c26cada13e98308f 100644 (file)
@@ -19,6 +19,7 @@
 pub use rustc_target::abi::call::*;
 use rustc_target::abi::{self, HasDataLayout, Int};
 pub use rustc_target::spec::abi::Abi;
+use rustc_target::spec::SanitizerSet;
 
 use libc::c_uint;
 use smallvec::SmallVec;
@@ -90,6 +91,13 @@ fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool {
         if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
             attrs.push(llvm::AttributeKind::NoAlias.create_attr(cx.llcx));
         }
+    } else if cx.tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
+        // If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects
+        // memory sanitizer's behavior.
+
+        if regular.contains(ArgAttribute::NoUndef) {
+            attrs.push(llvm::AttributeKind::NoUndef.create_attr(cx.llcx));
+        }
     }
 
     attrs
index 13e437cfbf7fb1b52d06589eb20c068ad140a131..acee9134fb96e48a26c3d4eb7a465c8d66ac6bf9 100644 (file)
@@ -215,7 +215,11 @@ fn const_struct(&self, elts: &[&'ll Value], packed: bool) -> &'ll Value {
     }
 
     fn const_to_opt_uint(&self, v: &'ll Value) -> Option<u64> {
-        try_as_const_integral(v).map(|v| unsafe { llvm::LLVMConstIntGetZExtValue(v) })
+        try_as_const_integral(v).and_then(|v| unsafe {
+            let mut i = 0u64;
+            let success = llvm::LLVMRustConstIntGetZExtValue(v, &mut i);
+            success.then_some(i)
+        })
     }
 
     fn const_to_opt_u128(&self, v: &'ll Value, sign_ext: bool) -> Option<u128> {
@@ -226,10 +230,6 @@ fn const_to_opt_u128(&self, v: &'ll Value, sign_ext: bool) -> Option<u128> {
         })
     }
 
-    fn zst_to_backend(&self, _llty: &'ll Type) -> &'ll Value {
-        self.const_undef(self.type_ix(0))
-    }
-
     fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value {
         let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
         match cv {
index daec9303b2c67edbf6f009ec9492bc81a8c02f68..129e336c7e431c58dd68b2280188bce1ee199cfa 100644 (file)
@@ -99,7 +99,7 @@
 /// compiler versions.
 ///
 /// Niche-tag enums have one special variant, usually called the
-/// "dataful variant". This variant has a field that
+/// "untagged variant". This variant has a field that
 /// doubles as the tag of the enum. The variant is active when the value of
 /// that field is within a pre-defined range. Therefore the variant struct
 /// has a `DISCR_BEGIN` and `DISCR_END` field instead of `DISCR_EXACT` in
@@ -249,7 +249,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
                     None,
                 ),
                 Variants::Multiple {
-                    tag_encoding: TagEncoding::Niche { dataful_variant, .. },
+                    tag_encoding: TagEncoding::Niche { untagged_variant, .. },
                     ref variants,
                     tag_field,
                     ..
@@ -260,7 +260,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
                     enum_type_di_node,
                     variants.indices(),
                     tag_field,
-                    Some(dataful_variant),
+                    Some(untagged_variant),
                 ),
             }
         },
@@ -391,7 +391,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
     enum_type_di_node: &'ll DIType,
     variant_indices: impl Iterator<Item = VariantIdx> + Clone,
     tag_field: usize,
-    dataful_variant_index: Option<VariantIdx>,
+    untagged_variant_index: Option<VariantIdx>,
 ) -> SmallVec<&'ll DIType> {
     let tag_base_type = super::tag_base_type(cx, enum_type_and_layout);
 
@@ -436,7 +436,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
         variant_names_type_di_node,
         tag_base_type,
         tag_field,
-        dataful_variant_index,
+        untagged_variant_index,
     )
 }
 
@@ -472,7 +472,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
     enum_or_generator_type_and_layout: TyAndLayout<'tcx>,
     enum_or_generator_type_di_node: &'ll DIType,
     variant_index: VariantIdx,
-    dataful_variant_index: Option<VariantIdx>,
+    untagged_variant_index: Option<VariantIdx>,
     variant_struct_type_di_node: &'ll DIType,
     variant_names_type_di_node: &'ll DIType,
     tag_base_type_di_node: &'ll DIType,
@@ -517,7 +517,7 @@ enum DiscrKind {
                     }
                 }
                 DiscrResult::Range(min, max) => {
-                    assert_eq!(Some(variant_index), dataful_variant_index);
+                    assert_eq!(Some(variant_index), untagged_variant_index);
                     if is_128_bits {
                         DiscrKind::Range128(min, max)
                     } else {
@@ -757,7 +757,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>(
     discr_type_di_node: &'ll DIType,
     tag_base_type: Ty<'tcx>,
     tag_field: usize,
-    dataful_variant_index: Option<VariantIdx>,
+    untagged_variant_index: Option<VariantIdx>,
 ) -> SmallVec<&'ll DIType> {
     let tag_base_type_di_node = type_di_node(cx, tag_base_type);
     let mut unions_fields = SmallVec::with_capacity(variant_field_infos.len() + 1);
@@ -776,7 +776,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>(
             enum_type_and_layout,
             enum_type_di_node,
             variant_member_info.variant_index,
-            dataful_variant_index,
+            untagged_variant_index,
             variant_member_info.variant_struct_type_di_node,
             discr_type_di_node,
             tag_base_type_di_node,
index 9b3d080bfd6aa3f8dbb7b1f76de5c70ba62e9fe9..14044d0f99b987609ff17331b3ee50d4f2b83605 100644 (file)
@@ -417,7 +417,7 @@ fn opt_single_val(&self) -> Option<u128> {
 /// Returns the discriminant value corresponding to the variant index.
 ///
 /// Will return `None` if there is less than two variants (because then the enum won't have)
-/// a tag, and if this is the dataful variant of a niche-layout enum (because then there is no
+/// a tag, and if this is the untagged variant of a niche-layout enum (because then there is no
 /// single discriminant value).
 fn compute_discriminant_value<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
@@ -430,11 +430,11 @@ fn compute_discriminant_value<'ll, 'tcx>(
             enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val,
         ),
         &Variants::Multiple {
-            tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant },
+            tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, untagged_variant },
             tag,
             ..
         } => {
-            if variant_index == dataful_variant {
+            if variant_index == untagged_variant {
                 let valid_range = enum_type_and_layout
                     .for_variant(cx, variant_index)
                     .largest_niche
index dae90a43f2659c32ab5277b6a09d4071dc074bff..becbccc434d9ac33ee30091225aa0b87278986b7 100644 (file)
@@ -378,7 +378,7 @@ fn build_discr_member_di_node<'ll, 'tcx>(
 ///
 /// The DW_AT_discr_value is optional, and is omitted if
 ///   - This is the only variant of a univariant enum (i.e. their is no discriminant)
-///   - This is the "dataful" variant of a niche-layout enum
+///   - This is the "untagged" variant of a niche-layout enum
 ///     (where only the other variants are identified by a single value)
 ///
 /// There is only ever a single member, the type of which is a struct that describes the
index 172684414fc5534495d2218c26062c80306f4b94..ce27dc5a5d1ea23c61a094fbc07150630c4663e7 100644 (file)
@@ -1096,7 +1096,7 @@ pub fn LLVMMDNodeInContext2<'a>(
     pub fn LLVMConstInt(IntTy: &Type, N: c_ulonglong, SignExtend: Bool) -> &Value;
     pub fn LLVMConstIntOfArbitraryPrecision(IntTy: &Type, Wn: c_uint, Ws: *const u64) -> &Value;
     pub fn LLVMConstReal(RealTy: &Type, N: f64) -> &Value;
-    pub fn LLVMConstIntGetZExtValue(ConstantVal: &ConstantInt) -> c_ulonglong;
+    pub fn LLVMRustConstIntGetZExtValue(ConstantVal: &ConstantInt, Value: &mut u64) -> bool;
     pub fn LLVMRustConstInt128Get(
         ConstantVal: &ConstantInt,
         SExt: bool,
index 16aad07194da8afa048c5fcf94a02a6caa5d134b..215edbe02c08e95244984fdf3ca817459f31ab73 100644 (file)
@@ -77,10 +77,6 @@ pub fn codegen_intrinsic_call(
         let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
 
         let llval = match name {
-            sym::assume => {
-                bx.assume(args[0].immediate());
-                return;
-            }
             sym::abort => {
                 bx.abort();
                 return;
@@ -555,14 +551,10 @@ pub fn codegen_intrinsic_call(
                 return;
             }
 
-            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
+            sym::ptr_guaranteed_cmp => {
                 let a = args[0].immediate();
                 let b = args[1].immediate();
-                if name == sym::ptr_guaranteed_eq {
-                    bx.icmp(IntPredicate::IntEQ, a, b)
-                } else {
-                    bx.icmp(IntPredicate::IntNE, a, b)
-                }
+                bx.icmp(IntPredicate::IntEQ, a, b)
             }
 
             sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
index c612634fce2a6609cd5fc9368dca9aad53163561..37b1e036247bfcd8c4c2863c87bcd6385406816d 100644 (file)
@@ -72,10 +72,6 @@ pub fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
     ) -> Self {
         let layout = bx.layout_of(ty);
 
-        if layout.is_zst() {
-            return OperandRef::new_zst(bx, layout);
-        }
-
         let val = match val {
             ConstValue::Scalar(x) => {
                 let Abi::Scalar(scalar) = layout.abi else {
@@ -84,10 +80,7 @@ pub fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                 let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout));
                 OperandValue::Immediate(llval)
             }
-            ConstValue::ZeroSized => {
-                let llval = bx.zst_to_backend(bx.immediate_backend_type(layout));
-                OperandValue::Immediate(llval)
-            }
+            ConstValue::ZeroSized => return OperandRef::new_zst(bx, layout),
             ConstValue::Slice { data, start, end } => {
                 let Abi::ScalarPair(a_scalar, _) = layout.abi else {
                     bug!("from_const: invalid ScalarPair layout: {:#?}", layout);
index 04b8c8636f634ddeaebdaf90e7417939ae10c9ba..13d8f6eddd1de12579a15761d52d7f56acf5c50c 100644 (file)
@@ -244,7 +244,7 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                 };
                 bx.intcast(tag.immediate(), cast_to, signed)
             }
-            TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
+            TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
                 // Rebase from niche values to discriminants, and check
                 // whether the result is in range for the niche variants.
                 let niche_llty = bx.cx().immediate_backend_type(tag.layout);
@@ -302,7 +302,7 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                 bx.select(
                     is_niche,
                     niche_discr,
-                    bx.cx().const_uint(cast_to, dataful_variant.as_u32() as u64),
+                    bx.cx().const_uint(cast_to, untagged_variant.as_u32() as u64),
                 )
             }
         }
@@ -337,11 +337,11 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
             }
             Variants::Multiple {
                 tag_encoding:
-                    TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
+                    TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start },
                 tag_field,
                 ..
             } => {
-                if variant_index != dataful_variant {
+                if variant_index != untagged_variant {
                     let niche = self.project_field(bx, tag_field);
                     let niche_llty = bx.cx().immediate_backend_type(niche.layout);
                     let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
index 26b9fbf44284628cdf19e8bbd042de40375d8670..574746e340b7bff7f041ccfb4d9f9dca62e4d7fe 100644 (file)
@@ -87,7 +87,7 @@ pub fn codegen_rvalue(
                     let size = bx.const_usize(dest.layout.size.bytes());
 
                     // Use llvm.memset.p0i8.* to initialize all zero arrays
-                    if bx.cx().const_to_opt_uint(v) == Some(0) {
+                    if bx.cx().const_to_opt_u128(v, false) == Some(0) {
                         let fill = bx.cx().const_u8(0);
                         bx.memset(start, fill, size, dest.align, MemFlags::empty());
                         return bx;
index f452f29883f939a86d35bd16b92b81913eac60d1..1db0fb3a6f1b0381da9eb2a1ca06eb6e3689af75 100644 (file)
@@ -1,4 +1,5 @@
 use rustc_middle::mir;
+use rustc_middle::mir::NonDivergingIntrinsic;
 
 use super::FunctionCx;
 use super::LocalRef;
@@ -73,11 +74,14 @@ pub fn codegen_statement(&mut self, mut bx: Bx, statement: &mir::Statement<'tcx>
                 self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
                 bx
             }
-            mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping {
-                ref src,
-                ref dst,
-                ref count,
-            }) => {
+            mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
+                let op_val = self.codegen_operand(&mut bx, op);
+                bx.assume(op_val.immediate());
+                bx
+            }
+            mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+                mir::CopyNonOverlapping { ref count, ref src, ref dst },
+            )) => {
                 let dst_val = self.codegen_operand(&mut bx, dst);
                 let src_val = self.codegen_operand(&mut bx, src);
                 let count = self.codegen_operand(&mut bx, count).immediate();
index 8a91d4735ba0d5db6e46e9f3499e9be4b214d29f..fdc7a30e841ed1b7e4d64ff077a3fd6e1b26baf4 100644 (file)
@@ -29,7 +29,6 @@ pub trait ConstMethods<'tcx>: BackendTypes {
     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 zst_to_backend(&self, llty: Self::Type) -> Self::Value;
     fn from_const_alloc(
         &self,
         layout: TyAndLayout<'tcx>,
index 6e5c840bdfd6a7bca628508b6366c6d54a8f1e60..e5acacd9188888f670ec6498d97aee5b7e8558e8 100644 (file)
@@ -191,34 +191,35 @@ fn may_leak(self) -> bool {
 }
 
 impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
-    fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> {
+    /// See documentation on the `ptr_guaranteed_cmp` intrinsic.
+    fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> {
         Ok(match (a, b) {
             // Comparisons between integers are always known.
-            (Scalar::Int { .. }, Scalar::Int { .. }) => a == b,
-            // Equality with integers can never be known for sure.
-            (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => false,
-            // FIXME: return `true` for when both sides are the same pointer, *except* that
-            // some things (like functions and vtables) do not have stable addresses
-            // so we need to be careful around them (see e.g. #73722).
-            (Scalar::Ptr(..), Scalar::Ptr(..)) => false,
-        })
-    }
-
-    fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> {
-        Ok(match (a, b) {
-            // Comparisons between integers are always known.
-            (Scalar::Int(_), Scalar::Int(_)) => a != b,
+            (Scalar::Int { .. }, Scalar::Int { .. }) => {
+                if a == b {
+                    1
+                } else {
+                    0
+                }
+            }
             // Comparisons of abstract pointers with null pointers are known if the pointer
             // is in bounds, because if they are in bounds, the pointer can't be null.
             // Inequality with integers other than null can never be known for sure.
             (Scalar::Int(int), ptr @ Scalar::Ptr(..))
-            | (ptr @ Scalar::Ptr(..), Scalar::Int(int)) => {
-                int.is_null() && !self.scalar_may_be_null(ptr)?
+            | (ptr @ Scalar::Ptr(..), Scalar::Int(int))
+                if int.is_null() && !self.scalar_may_be_null(ptr)? =>
+            {
+                0
             }
-            // FIXME: return `true` for at least some comparisons where we can reliably
+            // Equality with integers can never be known for sure.
+            (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => 2,
+            // FIXME: return a `1` for when both sides are the same pointer, *except* that
+            // some things (like functions and vtables) do not have stable addresses
+            // so we need to be careful around them (see e.g. #73722).
+            // FIXME: return `0` for at least some comparisons where we can reliably
             // determine the result of runtime inequality tests at compile-time.
             // Examples include comparison of addresses in different static items.
-            (Scalar::Ptr(..), Scalar::Ptr(..)) => false,
+            (Scalar::Ptr(..), Scalar::Ptr(..)) => 2,
         })
     }
 }
@@ -329,15 +330,11 @@ fn call_intrinsic(
             throw_unsup_format!("intrinsic `{intrinsic_name}` is not supported at compile-time");
         };
         match intrinsic_name {
-            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
+            sym::ptr_guaranteed_cmp => {
                 let a = ecx.read_scalar(&args[0])?;
                 let b = ecx.read_scalar(&args[1])?;
-                let cmp = if intrinsic_name == sym::ptr_guaranteed_eq {
-                    ecx.guaranteed_eq(a, b)?
-                } else {
-                    ecx.guaranteed_ne(a, b)?
-                };
-                ecx.write_scalar(Scalar::from_bool(cmp), dest)?;
+                let cmp = ecx.guaranteed_cmp(a, b)?;
+                ecx.write_scalar(Scalar::from_u8(cmp), dest)?;
             }
             sym::const_allocate => {
                 let size = ecx.read_scalar(&args[0])?.to_machine_usize(ecx)?;
index 8b7c3cf3377cc9108bc7a9e9f1f7f4763b35cdf8..a964fe8465eeceefb96a68077e1297f34b577195 100644 (file)
@@ -97,7 +97,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
         }
 
         // Raw pointers are not allowed in type level constants, as we cannot properly test them for
-        // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`).
+        // equality at compile-time (see `ptr_guaranteed_cmp`).
         // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
         // agree with runtime equality tests.
         ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
index adda9639990d0e38934100bce1856cb15c67c518..7dba5059307eaea2bc3369ea1c003d59f6ce92d3 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_middle::mir::{
     self,
     interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar},
-    BinOp,
+    BinOp, NonDivergingIntrinsic,
 };
 use rustc_middle::ty;
 use rustc_middle::ty::layout::LayoutOf as _;
@@ -79,9 +79,9 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
             ty::Projection(_)
             | ty::Opaque(_, _)
             | ty::Param(_)
-            | ty::Bound(_, _)
             | ty::Placeholder(_)
             | ty::Infer(_) => throw_inval!(TooGeneric),
+            ty::Bound(_, _) => bug!("bound ty during ctfe"),
             ty::Bool
             | ty::Char
             | ty::Int(_)
@@ -506,12 +506,6 @@ pub fn emulate_intrinsic(
                 // These just return their argument
                 self.copy_op(&args[0], dest, /*allow_transmute*/ false)?;
             }
-            sym::assume => {
-                let cond = self.read_scalar(&args[0])?.to_bool()?;
-                if !cond {
-                    throw_ub_format!("`assume` intrinsic called with `false`");
-                }
-            }
             sym::raw_eq => {
                 let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
                 self.write_scalar(result, dest)?;
@@ -536,6 +530,32 @@ pub fn emulate_intrinsic(
         Ok(true)
     }
 
+    pub(super) fn emulate_nondiverging_intrinsic(
+        &mut self,
+        intrinsic: &NonDivergingIntrinsic<'tcx>,
+    ) -> InterpResult<'tcx> {
+        match intrinsic {
+            NonDivergingIntrinsic::Assume(op) => {
+                let op = self.eval_operand(op, None)?;
+                let cond = self.read_scalar(&op)?.to_bool()?;
+                if !cond {
+                    throw_ub_format!("`assume` called with `false`");
+                }
+                Ok(())
+            }
+            NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
+                count,
+                src,
+                dst,
+            }) => {
+                let src = self.eval_operand(src, None)?;
+                let dst = self.eval_operand(dst, None)?;
+                let count = self.eval_operand(count, None)?;
+                self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)
+            }
+        }
+    }
+
     pub fn exact_div(
         &mut self,
         a: &ImmTy<'tcx, M::Provenance>,
index 35c2cf8102dc571269645cc1537433a415339063..f6c4f7dd1122105405065a171e1978eb69370e54 100644 (file)
@@ -559,7 +559,7 @@ pub fn const_to_op(
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         match c.kind() {
-            ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
+            ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => throw_inval!(TooGeneric),
             ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => {
                 throw_inval!(AlreadyReported(reported))
             }
@@ -567,7 +567,7 @@ pub fn const_to_op(
                 let instance = self.resolve(uv.def, uv.substs)?;
                 Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into())
             }
-            ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
+            ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => {
                 span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", c)
             }
             ty::ConstKind::Value(valtree) => {
@@ -718,7 +718,7 @@ pub fn read_discriminant(
                 // Return the cast value, and the index.
                 (discr_val, index.0)
             }
-            TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
+            TagEncoding::Niche { untagged_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.
@@ -736,7 +736,7 @@ pub fn read_discriminant(
                         if !ptr_valid {
                             throw_ub!(InvalidTag(dbg_val))
                         }
-                        dataful_variant
+                        untagged_variant
                     }
                     Ok(tag_bits) => {
                         let tag_bits = tag_bits.assert_bits(tag_layout.size);
@@ -766,7 +766,7 @@ pub fn read_discriminant(
                             assert!(usize::try_from(variant_index).unwrap() < variants_len);
                             VariantIdx::from_u32(variant_index)
                         } else {
-                            dataful_variant
+                            untagged_variant
                         }
                     }
                 };
@@ -780,13 +780,13 @@ pub fn read_discriminant(
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
     // These are in alphabetical order, which is easy to maintain.
-    static_assert_size!(Immediate, 56);
-    static_assert_size!(ImmTy<'_>, 72);
-    static_assert_size!(Operand, 64);
-    static_assert_size!(OpTy<'_>, 88);
+    static_assert_size!(Immediate, 48);
+    static_assert_size!(ImmTy<'_>, 64);
+    static_assert_size!(Operand, 56);
+    static_assert_size!(OpTy<'_>, 80);
 }
index a03b0dfb6038b737739098c77213a4433caab1e5..b328892906df22217f8b2afcb39c160766f2bc74 100644 (file)
@@ -817,7 +817,7 @@ pub fn write_discriminant(
             }
             abi::Variants::Multiple {
                 tag_encoding:
-                    TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
+                    TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start },
                 tag: tag_layout,
                 tag_field,
                 ..
@@ -825,7 +825,7 @@ pub fn write_discriminant(
                 // No need to validate that the discriminant here because the
                 // `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
 
-                if variant_index != dataful_variant {
+                if variant_index != untagged_variant {
                     let variants_start = niche_variants.start().as_u32();
                     let variant_index_relative = variant_index
                         .as_u32()
@@ -890,6 +890,8 @@ mod size_asserts {
     static_assert_size!(MemPlaceMeta, 24);
     static_assert_size!(MemPlace, 40);
     static_assert_size!(MPlaceTy<'_>, 64);
-    static_assert_size!(Place, 48);
-    static_assert_size!(PlaceTy<'_>, 72);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(Place, 40);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(PlaceTy<'_>, 64);
 }
index 6b827149f505ea60f6c7c44e1d7fb39652eb67fa..c6e04cbfb6bf344200dcc916378ad8df4adcd454 100644 (file)
@@ -114,13 +114,7 @@ pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
                 M::retag(self, *kind, &dest)?;
             }
 
-            // Call CopyNonOverlapping
-            CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => {
-                let src = self.eval_operand(src, None)?;
-                let dst = self.eval_operand(dst, None)?;
-                let count = self.eval_operand(count, None)?;
-                self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?;
-            }
+            Intrinsic(box ref intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
 
             // Statements we do not track.
             AscribeUserType(..) => {}
index cbfdb47dd1a4072eb30b9c919873f69e38b69b32..3fa40dc305952ae2694937246c13e8360ff69716 100644 (file)
@@ -678,7 +678,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             | StatementKind::Retag { .. }
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {}
         }
     }
index b798862583952eb5d1604a56750c14850ac8c6ab..8576e0f0f7c16ad856d9f41ef09b6eefb7423944 100644 (file)
@@ -7,9 +7,10 @@
 use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
-    traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, Local, Location,
-    MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, RuntimePhase, Rvalue,
-    SourceScope, Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK,
+    traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping,
+    Local, Location, MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef,
+    ProjectionElem, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+    TerminatorKind, UnOp, START_BLOCK,
 };
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::subst::Subst;
@@ -89,20 +90,21 @@ pub fn equal_up_to_regions<'tcx>(
 
     // Normalize lifetimes away on both sides, then compare.
     let normalize = |ty: Ty<'tcx>| {
-        let ty = ty.fold_with(&mut BottomUpFolder {
-            tcx,
-            // FIXME: We erase all late-bound lifetimes, but this is not fully correct.
-            // If you have a type like `<for<'a> fn(&'a u32) as SomeTrait>::Assoc`,
-            // this is not necessarily equivalent to `<fn(&'static u32) as SomeTrait>::Assoc`,
-            // since one may have an `impl SomeTrait for fn(&32)` and
-            // `impl SomeTrait for fn(&'static u32)` at the same time which
-            // specify distinct values for Assoc. (See also #56105)
-            lt_op: |_| tcx.lifetimes.re_erased,
-            // Leave consts and types unchanged.
-            ct_op: |ct| ct,
-            ty_op: |ty| ty,
-        });
-        tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty)
+        tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty).fold_with(
+            &mut BottomUpFolder {
+                tcx,
+                // FIXME: We erase all late-bound lifetimes, but this is not fully correct.
+                // If you have a type like `<for<'a> fn(&'a u32) as SomeTrait>::Assoc`,
+                // this is not necessarily equivalent to `<fn(&'static u32) as SomeTrait>::Assoc`,
+                // since one may have an `impl SomeTrait for fn(&32)` and
+                // `impl SomeTrait for fn(&'static u32)` at the same time which
+                // specify distinct values for Assoc. (See also #56105)
+                lt_op: |_| tcx.lifetimes.re_erased,
+                // Leave consts and types unchanged.
+                ct_op: |ct| ct,
+                ty_op: |ty| ty,
+            },
+        )
     };
     tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok())
 }
@@ -636,11 +638,18 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                     );
                 }
             }
-            StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
-                ref src,
-                ref dst,
-                ref count,
-            }) => {
+            StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+                let ty = op.ty(&self.body.local_decls, self.tcx);
+                if !ty.is_bool() {
+                    self.fail(
+                        location,
+                        format!("`assume` argument must be `bool`, but got: `{}`", ty),
+                    );
+                }
+            }
+            StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+                CopyNonOverlapping { src, dst, count },
+            )) => {
                 let src_ty = src.ty(&self.body.local_decls, self.tcx);
                 let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) {
                     src_deref.ty
index 07a96dd7dbbf1dfb9a0750912bef073d415971d6..e351b650a16c1a8c7c6829e01dbc326a0ed8d13e 100644 (file)
@@ -117,6 +117,10 @@ fn process_backedge<'c, I>(&mut self, cycle: I, _marker: PhantomData<&'c Self::O
 }
 
 /// The result type used by `process_obligation`.
+// `repr(C)` to inhibit the niche filling optimization. Otherwise, the `match` appearing
+// in `process_obligations` is significantly slower, which can substantially affect
+// benchmarks like `rustc-perf`'s inflate and keccak.
+#[repr(C)]
 #[derive(Debug)]
 pub enum ProcessResult<O, E> {
     Unchanged,
index a193d5db6916a08af8eaf61d186d86210a13c998..d6f51d7eee1afca590f30d6fd3205bc51d2953de 100644 (file)
@@ -1119,22 +1119,25 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
     while let Some(arg) = args.next() {
         if let Some(a) = ICE_REPORT_COMPILER_FLAGS.iter().find(|a| arg.starts_with(*a)) {
             let content = if arg.len() == a.len() {
+                // A space-separated option, like `-C incremental=foo` or `--crate-type rlib`
                 match args.next() {
                     Some(arg) => arg.to_string(),
                     None => continue,
                 }
             } else if arg.get(a.len()..a.len() + 1) == Some("=") {
+                // An equals option, like `--crate-type=rlib`
                 arg[a.len() + 1..].to_string()
             } else {
+                // A non-space option, like `-Cincremental=foo`
                 arg[a.len()..].to_string()
             };
-            if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| content.starts_with(exc)) {
+            let option = content.split_once('=').map(|s| s.0).unwrap_or(&content);
+            if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| option == *exc) {
                 excluded_cargo_defaults = true;
             } else {
                 result.push(a.to_string());
-                match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| content.starts_with(*s))
-                {
-                    Some(s) => result.push(s.to_string()),
+                match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| option == **s) {
+                    Some(s) => result.push(format!("{}=[REDACTED]", s)),
                     None => result.push(content),
                 }
             }
index f2790531aba44de40e247d6d7a8b4d956fd08684..c45e045b4dba0d27d159382a181f94e10dc7368d 100644 (file)
@@ -131,3 +131,9 @@ ast_lowering_arbitrary_expression_in_pattern =
     arbitrary expressions aren't allowed in patterns
 
 ast_lowering_inclusive_range_with_no_end = inclusive range with no end
+
+ast_lowering_trait_fn_async =
+    functions in traits cannot be declared `async`
+    .label = `async` because of this
+    .note = `async` trait functions are not currently supported
+    .note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait
index d7108e1e2de35e5dbc22da59213a42b39cf8388b..e5cd1142b20c8c8738055ac3d52d845fb801b24d 100644 (file)
@@ -26,12 +26,6 @@ ast_passes_invalid_visibility =
     .individual_impl_items = place qualifiers on individual impl items instead
     .individual_foreign_items = place qualifiers on individual foreign items instead
 
-ast_passes_trait_fn_async =
-    functions in traits cannot be declared `async`
-    .label = `async` because of this
-    .note = `async` trait functions are not currently supported
-    .note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 ast_passes_trait_fn_const =
     functions in traits cannot be declared const
     .label = functions in traits cannot be const
index 60086cd6e477f430bff9432081f32af0d7583b40..2899b8304bc14884338564a480a2ffc54cdaec05 100644 (file)
@@ -104,9 +104,67 @@ infer_relate_object_bound = ...so that it can be closed over into an object
 infer_data_borrowed = ...so that the type `{$name}` is not borrowed for too long
 infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at
 infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues ->
-[true] ...
-*[false] {""}
+    [true] ...
+    *[false] {""}
 }
 infer_relate_param_bound_2 = ...that is required by this bound
 infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
 infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
+
+infer_nothing = {""}
+
+infer_lifetime_mismatch = lifetime mismatch
+
+infer_declared_different = this parameter and the return type are declared with different lifetimes...
+infer_data_returned = ...but data{$label_var1_exists ->
+    [true] {" "}from `{$label_var1}`
+    *[false] {""}
+} is returned here
+
+infer_data_lifetime_flow = ...but data with one lifetime flows into the other here
+infer_declared_multiple = this type is declared with multiple lifetimes...
+infer_types_declared_different = these two types are declared with different lifetimes...
+infer_data_flows = ...but data{$label_var1_exists ->
+    [true] -> {" "}from `{$label_var1}`
+    *[false] -> {""}
+} flows{$label_var2_exists ->
+    [true] -> {" "}into `{$label_var2}`
+    *[false] -> {""}
+} here
+
+infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
+    [true] {" "}and update trait if needed
+    *[false] {""}
+}
+infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime
+
+infer_region_explanation = {$pref_kind ->
+    *[should_not_happen] [{$pref_kind}]
+    [empty] {""}
+}{$pref_kind ->
+    [empty] {""}
+    *[other] {" "}
+}{$desc_kind ->
+    *[should_not_happen] [{$desc_kind}]
+    [restatic] the static lifetime
+    [reempty] the empty lifetime
+    [reemptyuni] the empty lifetime in universe {$desc_arg}
+    [revar] lifetime {$desc_arg}
+
+    [as_defined] the lifetime `{$desc_arg}` as defined here
+    [as_defined_anon] the anonymous lifetime as defined here
+    [defined_here] the anonymous lifetime defined here
+    [anon_num_here] the anonymous lifetime #{$desc_num_arg} defined here
+    [defined_here_reg] the lifetime `{$desc_arg}` as defined here
+}{$suff_kind ->
+    *[should_not_happen] [{$suff_kind}]
+    [empty]{""}
+    [continues] ...
+}
+
+infer_mismatched_static_lifetime = incompatible lifetime on type
+infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+infer_msl_introduces_static = introduces a `'static` lifetime requirement
+infer_msl_unmet_req = because this has an unmet lifetime requirement
+infer_msl_trait_note = this has an implicit `'static` lifetime requirement
+infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement
index bc17754c56ae309882e2980508c3fc1623b42812..f74df3d9746aec4173e0d566dc53c13d8198f055 100644 (file)
@@ -153,3 +153,6 @@ parser_left_arrow_operator = unexpected token: `<-`
 
 parser_remove_let = expected pattern, found `let`
     .suggestion = remove the unnecessary `let` keyword
+
+parser_use_eq_instead = unexpected `==`
+    .suggestion = try using `=` instead
index 983e5cee8237d801c8295fb85e706c993f0d5e7e..d2a2958f62436180cee3436fec51d91694485772 100644 (file)
@@ -14,3 +14,45 @@ session_feature_diagnostic_for_issue =
 
 session_feature_diagnostic_help =
     add `#![feature({$feature})]` to the crate attributes to enable
+
+session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
+
+session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist.
+
+session_linker_plugin_lto_windows_not_supported = linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets
+
+session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist.
+
+session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`
+
+session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
+
+session_sanitizers_not_supported = {$us} sanitizers are not supported for this target
+
+session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`
+
+session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
+
+session_sanitizer_cfi_enabled = `-Zsanitizer=cfi` requires `-Clto`
+
+session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
+
+session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
+
+session_target_invalid_address_space = invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
+
+session_target_invalid_bits = invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
+
+session_target_missing_alignment = missing alignment for `{$cause}` in "data-layout"
+
+session_target_invalid_alignment = invalid alignment for `{$cause}` in "data-layout": {$err}
+
+session_target_inconsistent_architecture = inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}`
+
+session_target_inconsistent_pointer_width = inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}`
+
+session_target_invalid_bits_size = {$err}
+
+session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored
+
+session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform
index a052aaee047567610702f244baf0a1910f193464..a774b52c8a592e75a321efa8b377c04167b2fd92 100644 (file)
 use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
 use rustc_span::{edition::Edition, Span, DUMMY_SP};
-use rustc_target::spec::PanicStrategy;
+use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
 use std::borrow::Cow;
 use std::fmt;
 use std::hash::{Hash, Hasher};
+use std::num::ParseIntError;
 use std::path::{Path, PathBuf};
 
 /// Error type for `Diagnostic`'s `suggestions` field, indicating that
@@ -91,6 +92,10 @@ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
     Edition,
     Ident,
     MacroRulesNormalizedIdent,
+    ParseIntError,
+    StackProtector,
+    &TargetTriple,
+    SplitDebuginfo
 );
 
 impl IntoDiagnosticArg for bool {
index 37ff6dcff7d795c26efaef3eadc111c9ad5ed81d..3e02d2ebb7e3e05bc207fc72d01fb657e5c5a2d7 100644 (file)
@@ -69,8 +69,8 @@
 // (See also the comment on `DiagnosticBuilder`'s `diagnostic` field.)
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16);
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))]
+rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
 
 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
 pub enum SuggestionStyle {
@@ -456,7 +456,7 @@ struct HandlerInner {
 }
 
 /// A key denoting where from a diagnostic was stashed.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub enum StashKey {
     ItemNoType,
     UnderscoreForArrayLengths,
index f71b3d59e2c04cb8d41d5586bfe802d2156e258b..98258834bd58964d29302c1351393eae28a69320 100644 (file)
@@ -478,7 +478,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows macro attributes on expressions, statements and non-inline modules.
     (active, proc_macro_hygiene, "1.30.0", Some(54727), None),
     /// Allows the use of raw-dylibs (RFC 2627).
-    (incomplete, raw_dylib, "1.40.0", Some(58713), None),
+    (active, raw_dylib, "CURRENT_RUSTC_VERSION", Some(58713), None),
     /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
     (active, raw_ref_op, "1.41.0", Some(64490), None),
     /// Allows using the `#[register_tool]` attribute.
@@ -487,6 +487,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (incomplete, repr128, "1.16.0", Some(56071), None),
     /// Allows `repr(simd)` and importing the various simd intrinsics.
     (active, repr_simd, "1.4.0", Some(27731), None),
+    /// Allows return-position `impl Trait` in traits.
+    (incomplete, return_position_impl_trait_in_trait, "CURRENT_RUSTC_VERSION", Some(91611), None),
     /// Allows `extern "rust-cold"`.
     (active, rust_cold_cc, "1.63.0", Some(97544), None),
     /// Allows the use of SIMD types in functions declared in `extern` blocks.
index 38a02cb1d7ce9f224e065897ae2b35f6caa464d9..8d88a90e39564b5dc506d8de7b50b9ba350e7e6c 100644 (file)
@@ -345,6 +345,7 @@ pub struct BuiltinAttribute {
     ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
     ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true),
     ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, @only_local: true),
+    ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding),
 
     // Limits:
     ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
@@ -406,10 +407,6 @@ pub struct BuiltinAttribute {
 
     // Linking:
     gated!(naked, Normal, template!(Word), WarnFollowing, @only_local: true, naked_functions, experimental!(naked)),
-    gated!(
-        link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, raw_dylib,
-        experimental!(link_ordinal)
-    ),
 
     // Plugins:
     BuiltinAttribute {
index d5ac07f1e6315d23023a8679fca60331fa1d36c4..e7c26bd726fbfd69fa45532d5658d752de9a4232 100644 (file)
@@ -109,6 +109,8 @@ pub enum DefKind {
     InlineConst,
     /// Opaque type, aka `impl Trait`.
     OpaqueTy,
+    /// A return-position `impl Trait` in a trait definition
+    ImplTraitPlaceholder,
     Field,
     /// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }`
     LifetimeParam,
@@ -138,6 +140,7 @@ pub fn descr(self, def_id: DefId) -> &'static str {
                 panic!("impossible struct constructor")
             }
             DefKind::OpaqueTy => "opaque type",
+            DefKind::ImplTraitPlaceholder => "opaque type in trait",
             DefKind::TyAlias => "type alias",
             DefKind::TraitAlias => "trait alias",
             DefKind::AssocTy => "associated type",
@@ -217,7 +220,8 @@ pub fn ns(&self) -> Option<Namespace> {
             | DefKind::Use
             | DefKind::ForeignMod
             | DefKind::GlobalAsm
-            | DefKind::Impl => None,
+            | DefKind::Impl
+            | DefKind::ImplTraitPlaceholder => None,
         }
     }
 
@@ -254,6 +258,7 @@ pub fn has_codegen_attrs(self) -> bool {
             | DefKind::Use
             | DefKind::ForeignMod
             | DefKind::OpaqueTy
+            | DefKind::ImplTraitPlaceholder
             | DefKind::Impl
             | DefKind::Field
             | DefKind::TyParam
@@ -457,7 +462,7 @@ pub fn unresolved_segments(&self) -> usize {
 
 /// Different kinds of symbols can coexist even if they share the same textual name.
 /// Therefore, they each have a separate universe (known as a "namespace").
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub enum Namespace {
     /// The type namespace includes `struct`s, `enum`s, `union`s, `trait`s, and `mod`s
     /// (and, by extension, crates).
index 50e7c5d2d04c8ba269584ac8d48001a3c2947ef6..c0f93b7c3382a32d3aa4cdbd4cd7085dc8c0313e 100644 (file)
@@ -259,7 +259,7 @@ pub fn to_ty(&self) -> Ty<'_> {
 
 #[derive(Debug, HashStable_Generic)]
 pub enum GenericArg<'hir> {
-    Lifetime(Lifetime),
+    Lifetime(&'hir Lifetime),
     Type(&'hir Ty<'hir>),
     Const(ConstArg),
     Infer(InferArg),
@@ -300,9 +300,9 @@ pub fn descr(&self) -> &'static str {
     pub fn to_ord(&self) -> ast::ParamKindOrd {
         match self {
             GenericArg::Lifetime(_) => ast::ParamKindOrd::Lifetime,
-            GenericArg::Type(_) => ast::ParamKindOrd::Type,
-            GenericArg::Const(_) => ast::ParamKindOrd::Const,
-            GenericArg::Infer(_) => ast::ParamKindOrd::Infer,
+            GenericArg::Type(_) | GenericArg::Const(_) | GenericArg::Infer(_) => {
+                ast::ParamKindOrd::TypeOrConst
+            }
         }
     }
 
@@ -430,7 +430,7 @@ pub enum GenericBound<'hir> {
     Trait(PolyTraitRef<'hir>, TraitBoundModifier),
     // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem`
     LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>),
-    Outlives(Lifetime),
+    Outlives(&'hir Lifetime),
 }
 
 impl GenericBound<'_> {
@@ -756,7 +756,7 @@ pub fn is_param_bound(&self, param_def_id: DefId) -> bool {
 pub struct WhereRegionPredicate<'hir> {
     pub span: Span,
     pub in_where_clause: bool,
-    pub lifetime: Lifetime,
+    pub lifetime: &'hir Lifetime,
     pub bounds: GenericBounds<'hir>,
 }
 
@@ -1059,6 +1059,35 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+// Equivalent to `Option<usize>`. That type takes up 16 bytes on 64-bit, but
+// this type only takes up 4 bytes, at the cost of being restricted to a
+// maximum value of `u32::MAX - 1`. In practice, this is more than enough.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable_Generic)]
+pub struct DotDotPos(u32);
+
+impl DotDotPos {
+    // Panics if n >= u32::MAX.
+    pub fn new(n: Option<usize>) -> Self {
+        match n {
+            Some(n) => {
+                assert!(n < u32::MAX as usize);
+                Self(n as u32)
+            }
+            None => Self(u32::MAX),
+        }
+    }
+
+    pub fn as_opt_usize(&self) -> Option<usize> {
+        if self.0 == u32::MAX { None } else { Some(self.0 as usize) }
+    }
+}
+
+impl fmt::Debug for DotDotPos {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.as_opt_usize().fmt(f)
+    }
+}
+
 #[derive(Debug, HashStable_Generic)]
 pub enum PatKind<'hir> {
     /// Represents a wildcard pattern (i.e., `_`).
@@ -1075,9 +1104,9 @@ pub enum PatKind<'hir> {
     Struct(QPath<'hir>, &'hir [PatField<'hir>], bool),
 
     /// A tuple struct/variant pattern `Variant(x, y, .., z)`.
-    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
+    /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position.
     /// `0 <= position <= subpats.len()`
-    TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], Option<usize>),
+    TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], DotDotPos),
 
     /// An or-pattern `A | B | C`.
     /// Invariant: `pats.len() >= 2`.
@@ -1089,7 +1118,7 @@ pub enum PatKind<'hir> {
     /// A tuple pattern (e.g., `(a, b)`).
     /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
     /// `0 <= position <= subpats.len()`
-    Tuple(&'hir [Pat<'hir>], Option<usize>),
+    Tuple(&'hir [Pat<'hir>], DotDotPos),
 
     /// A `box` pattern.
     Box(&'hir Pat<'hir>),
@@ -2372,6 +2401,14 @@ pub fn as_generic_param(&self) -> Option<(DefId, Ident)> {
             _ => None,
         }
     }
+
+    pub fn peel_refs(&self) -> &Self {
+        let mut final_ty = self;
+        while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind {
+            final_ty = &ty;
+        }
+        final_ty
+    }
 }
 
 /// Not represented directly in the AST; referred to by name through a `ty_path`.
@@ -2476,6 +2513,7 @@ pub struct OpaqueTy<'hir> {
     pub generics: &'hir Generics<'hir>,
     pub bounds: GenericBounds<'hir>,
     pub origin: OpaqueTyOrigin,
+    pub in_trait: bool,
 }
 
 /// From whence the opaque type came.
@@ -2499,7 +2537,7 @@ pub enum TyKind<'hir> {
     /// A raw pointer (i.e., `*const T` or `*mut T`).
     Ptr(MutTy<'hir>),
     /// A reference (i.e., `&'a T` or `&'a mut T`).
-    Rptr(Lifetime, MutTy<'hir>),
+    Rptr(&'hir Lifetime, MutTy<'hir>),
     /// A bare function (e.g., `fn(usize) -> bool`).
     BareFn(&'hir BareFnTy<'hir>),
     /// The never type (`!`).
@@ -2515,10 +2553,12 @@ pub enum TyKind<'hir> {
     ///
     /// The generic argument list contains the lifetimes (and in the future
     /// possibly parameters) that are actually bound on the `impl Trait`.
-    OpaqueDef(ItemId, &'hir [GenericArg<'hir>]),
+    ///
+    /// The last parameter specifies whether this opaque appears in a trait definition.
+    OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
-    TraitObject(&'hir [PolyTraitRef<'hir>], Lifetime, TraitObjectSyntax),
+    TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
     /// Unused for now.
     Typeof(AnonConst),
     /// `TyKind::Infer` means the type should be inferred instead of it having been
@@ -3473,25 +3513,30 @@ mod size_asserts {
     static_assert_size!(FnDecl<'_>, 40);
     static_assert_size!(ForeignItem<'_>, 72);
     static_assert_size!(ForeignItemKind<'_>, 40);
-    static_assert_size!(GenericArg<'_>, 40);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(GenericArg<'_>, 24);
     static_assert_size!(GenericBound<'_>, 48);
     static_assert_size!(Generics<'_>, 56);
     static_assert_size!(Impl<'_>, 80);
-    static_assert_size!(ImplItem<'_>, 88);
-    static_assert_size!(ImplItemKind<'_>, 40);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(ImplItem<'_>, 80);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(ImplItemKind<'_>, 32);
     static_assert_size!(Item<'_>, 80);
     static_assert_size!(ItemKind<'_>, 48);
     static_assert_size!(Local<'_>, 64);
     static_assert_size!(Param<'_>, 32);
-    static_assert_size!(Pat<'_>, 88);
-    static_assert_size!(PatKind<'_>, 64);
+    static_assert_size!(Pat<'_>, 72);
+    static_assert_size!(PatKind<'_>, 48);
     static_assert_size!(Path<'_>, 48);
     static_assert_size!(PathSegment<'_>, 56);
     static_assert_size!(QPath<'_>, 24);
     static_assert_size!(Stmt<'_>, 32);
     static_assert_size!(StmtKind<'_>, 16);
-    static_assert_size!(TraitItem<'_>, 96);
-    static_assert_size!(TraitItemKind<'_>, 56);
-    static_assert_size!(Ty<'_>, 72);
-    static_assert_size!(TyKind<'_>, 56);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(TraitItem<'_>, 88);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(TraitItemKind<'_>, 48);
+    static_assert_size!(Ty<'_>, 48);
+    static_assert_size!(TyKind<'_>, 32);
 }
index 20ec788463ac011e9938b6a4f0372125091afe1d..bf4ab06638bb15855eab275864e001dfacc3b400 100644 (file)
@@ -670,7 +670,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
         TyKind::Path(ref qpath) => {
             visitor.visit_qpath(qpath, typ.hir_id, typ.span);
         }
-        TyKind::OpaqueDef(item_id, lifetimes) => {
+        TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => {
             visitor.visit_nested_item(item_id);
             walk_list!(visitor, visit_generic_arg, lifetimes);
         }
index bc1ea1c4c736f4f3ba1bcc1e040b3c6d0bec0c34..ea17c1de9b70037c48ce828ea917c16e0434f591 100644 (file)
@@ -238,7 +238,6 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     Future,                  sym::future_trait,        future_trait,               Target::Trait,          GenericRequirement::Exact(0);
     GeneratorState,          sym::generator_state,     gen_state,                  Target::Enum,           GenericRequirement::None;
     Generator,               sym::generator,           gen_trait,                  Target::Trait,          GenericRequirement::Minimum(1);
-    GeneratorReturn,         sym::generator_return,    generator_return,           Target::AssocTy,        GenericRequirement::None;
     Unpin,                   sym::unpin,               unpin_trait,                Target::Trait,          GenericRequirement::None;
     Pin,                     sym::pin,                 pin_type,                   Target::Struct,         GenericRequirement::None;
 
index 9baaf9390f2c5aa181bfde02841de865236339af..0c1819bb0c745ef45190480c5cb3460b5bd757b2 100644 (file)
@@ -35,7 +35,7 @@ pub trait EnumerateAndAdjustIterator {
     fn enumerate_and_adjust(
         self,
         expected_len: usize,
-        gap_pos: Option<usize>,
+        gap_pos: hir::DotDotPos,
     ) -> EnumerateAndAdjust<Self>
     where
         Self: Sized;
@@ -45,7 +45,7 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
     fn enumerate_and_adjust(
         self,
         expected_len: usize,
-        gap_pos: Option<usize>,
+        gap_pos: hir::DotDotPos,
     ) -> EnumerateAndAdjust<Self>
     where
         Self: Sized,
@@ -53,7 +53,7 @@ fn enumerate_and_adjust(
         let actual_len = self.len();
         EnumerateAndAdjust {
             enumerate: self.enumerate(),
-            gap_pos: gap_pos.unwrap_or(expected_len),
+            gap_pos: gap_pos.as_opt_usize().unwrap_or(expected_len),
             gap_len: expected_len - actual_len,
         }
     }
index 78bfd7191dba9b3f713377ff4830ac3667644988..5917d5e346e371d2a1da00c227dcf2924f4bf51f 100644 (file)
@@ -36,6 +36,7 @@ pub enum Target {
     GlobalAsm,
     TyAlias,
     OpaqueTy,
+    ImplTraitPlaceholder,
     Enum,
     Variant,
     Struct,
@@ -79,7 +80,13 @@ pub fn from_item(item: &Item<'_>) -> Target {
             ItemKind::ForeignMod { .. } => Target::ForeignMod,
             ItemKind::GlobalAsm(..) => Target::GlobalAsm,
             ItemKind::TyAlias(..) => Target::TyAlias,
-            ItemKind::OpaqueTy(..) => Target::OpaqueTy,
+            ItemKind::OpaqueTy(ref opaque) => {
+                if opaque.in_trait {
+                    Target::ImplTraitPlaceholder
+                } else {
+                    Target::OpaqueTy
+                }
+            }
             ItemKind::Enum(..) => Target::Enum,
             ItemKind::Struct(..) => Target::Struct,
             ItemKind::Union(..) => Target::Union,
@@ -103,6 +110,7 @@ pub fn from_def_kind(def_kind: DefKind) -> Target {
             DefKind::GlobalAsm => Target::GlobalAsm,
             DefKind::TyAlias => Target::TyAlias,
             DefKind::OpaqueTy => Target::OpaqueTy,
+            DefKind::ImplTraitPlaceholder => Target::ImplTraitPlaceholder,
             DefKind::Enum => Target::Enum,
             DefKind::Struct => Target::Struct,
             DefKind::Union => Target::Union,
@@ -157,6 +165,7 @@ pub fn name(self) -> &'static str {
             Target::GlobalAsm => "global asm",
             Target::TyAlias => "type alias",
             Target::OpaqueTy => "opaque type",
+            Target::ImplTraitPlaceholder => "opaque type in trait",
             Target::Enum => "enum",
             Target::Variant => "enum variant",
             Target::Struct => "struct",
index 1220755f44b30866aa3394a31fc4588e55d1fd02..35a58296e370e4aa0daf15caa39690d9dc7cc46c 100644 (file)
@@ -1761,7 +1761,8 @@ pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
             PatKind::TupleStruct(ref qpath, elts, ddpos) => {
                 self.print_qpath(qpath, true);
                 self.popen();
-                if let Some(ddpos) = ddpos {
+                if let Some(ddpos) = ddpos.as_opt_usize() {
+                    let ddpos = ddpos as usize;
                     self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
                     if ddpos != 0 {
                         self.word_space(",");
@@ -1804,7 +1805,7 @@ pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
             }
             PatKind::Tuple(elts, ddpos) => {
                 self.popen();
-                if let Some(ddpos) = ddpos {
+                if let Some(ddpos) = ddpos.as_opt_usize() {
                     self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
                     if ddpos != 0 {
                         self.word_space(",");
diff --git a/compiler/rustc_infer/src/errors.rs b/compiler/rustc_infer/src/errors.rs
deleted file mode 100644 (file)
index 938f8aa..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-use rustc_errors::{fluent, AddSubdiagnostic, DiagnosticMessage, DiagnosticStyledString};
-use rustc_hir::FnRetTy;
-use rustc_macros::SessionDiagnostic;
-use rustc_span::{BytePos, Span};
-
-use crate::infer::error_reporting::{
-    need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
-    ObligationCauseAsDiagArg,
-};
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::opaque_hidden_type)]
-pub struct OpaqueHiddenTypeDiag {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[note(infer::opaque_type)]
-    pub opaque_type: Span,
-    #[note(infer::hidden_type)]
-    pub hidden_type: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0282")]
-pub struct AnnotationRequired<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub source_kind: &'static str,
-    pub source_name: &'a str,
-    #[label]
-    pub failure_span: Option<Span>,
-    #[subdiagnostic]
-    pub bad_label: Option<InferenceBadError<'a>>,
-    #[subdiagnostic]
-    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
-    #[subdiagnostic]
-    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-}
-
-// Copy of `AnnotationRequired` for E0283
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0283")]
-pub struct AmbigousImpl<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub source_kind: &'static str,
-    pub source_name: &'a str,
-    #[label]
-    pub failure_span: Option<Span>,
-    #[subdiagnostic]
-    pub bad_label: Option<InferenceBadError<'a>>,
-    #[subdiagnostic]
-    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
-    #[subdiagnostic]
-    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-}
-
-// Copy of `AnnotationRequired` for E0284
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0284")]
-pub struct AmbigousReturn<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub source_kind: &'static str,
-    pub source_name: &'a str,
-    #[label]
-    pub failure_span: Option<Span>,
-    #[subdiagnostic]
-    pub bad_label: Option<InferenceBadError<'a>>,
-    #[subdiagnostic]
-    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
-    #[subdiagnostic]
-    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::need_type_info_in_generator, code = "E0698")]
-pub struct NeedTypeInfoInGenerator<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub generator_kind: GeneratorKindAsDiagArg,
-    #[subdiagnostic]
-    pub bad_label: InferenceBadError<'a>,
-}
-
-// Used when a better one isn't available
-#[derive(SessionSubdiagnostic)]
-#[label(infer::label_bad)]
-pub struct InferenceBadError<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub bad_kind: &'static str,
-    pub prefix_kind: UnderspecifiedArgKind,
-    pub has_parent: bool,
-    pub prefix: &'a str,
-    pub parent_prefix: &'a str,
-    pub parent_name: String,
-    pub name: String,
-}
-
-#[derive(SessionSubdiagnostic)]
-pub enum SourceKindSubdiag<'a> {
-    #[suggestion_verbose(
-        infer::source_kind_subdiag_let,
-        code = ": {type_name}",
-        applicability = "has-placeholders"
-    )]
-    LetLike {
-        #[primary_span]
-        span: Span,
-        name: String,
-        type_name: String,
-        kind: &'static str,
-        x_kind: &'static str,
-        prefix_kind: UnderspecifiedArgKind,
-        prefix: &'a str,
-        arg_name: String,
-    },
-    #[label(infer::source_kind_subdiag_generic_label)]
-    GenericLabel {
-        #[primary_span]
-        span: Span,
-        is_type: bool,
-        param_name: String,
-        parent_exists: bool,
-        parent_prefix: String,
-        parent_name: String,
-    },
-    #[suggestion_verbose(
-        infer::source_kind_subdiag_generic_suggestion,
-        code = "::<{args}>",
-        applicability = "has-placeholders"
-    )]
-    GenericSuggestion {
-        #[primary_span]
-        span: Span,
-        arg_count: usize,
-        args: String,
-    },
-}
-
-// Has to be implemented manually because multipart suggestions are not supported by the derive macro.
-// Would be a part of `SourceKindSubdiag` otherwise.
-pub enum SourceKindMultiSuggestion<'a> {
-    FullyQualified {
-        span: Span,
-        def_path: String,
-        adjustment: &'a str,
-        successor: (&'a str, BytePos),
-    },
-    ClosureReturn {
-        ty_info: String,
-        data: &'a FnRetTy<'a>,
-        should_wrap_expr: Option<Span>,
-    },
-}
-
-impl AddSubdiagnostic for SourceKindMultiSuggestion<'_> {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
-        match self {
-            Self::FullyQualified { span, def_path, adjustment, successor } => {
-                let suggestion = vec![
-                    (span.shrink_to_lo(), format!("{def_path}({adjustment}")),
-                    (span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
-                ];
-                diag.multipart_suggestion_verbose(
-                    fluent::infer::source_kind_fully_qualified,
-                    suggestion,
-                    rustc_errors::Applicability::HasPlaceholders,
-                );
-            }
-            Self::ClosureReturn { ty_info, data, should_wrap_expr } => {
-                let (arrow, post) = match data {
-                    FnRetTy::DefaultReturn(_) => ("-> ", " "),
-                    _ => ("", ""),
-                };
-                let suggestion = match should_wrap_expr {
-                    Some(end_span) => vec![
-                        (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post)),
-                        (end_span, " }".to_string()),
-                    ],
-                    None => vec![(data.span(), format!("{}{}{}", arrow, ty_info, post))],
-                };
-                diag.multipart_suggestion_verbose(
-                    fluent::infer::source_kind_closure_return,
-                    suggestion,
-                    rustc_errors::Applicability::HasPlaceholders,
-                );
-            }
-        }
-    }
-}
-
-pub enum RegionOriginNote<'a> {
-    Plain {
-        span: Span,
-        msg: DiagnosticMessage,
-    },
-    WithName {
-        span: Span,
-        msg: DiagnosticMessage,
-        name: &'a str,
-        continues: bool,
-    },
-    WithRequirement {
-        span: Span,
-        requirement: ObligationCauseAsDiagArg<'a>,
-        expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
-    },
-}
-
-impl AddSubdiagnostic for RegionOriginNote<'_> {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
-        let mut label_or_note = |span, msg: DiagnosticMessage| {
-            let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
-            let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
-            let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
-            if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
-                diag.span_label(span, msg);
-            } else if span_is_primary && expanded_sub_count == 0 {
-                diag.note(msg);
-            } else {
-                diag.span_note(span, msg);
-            }
-        };
-        match self {
-            RegionOriginNote::Plain { span, msg } => {
-                label_or_note(span, msg);
-            }
-            RegionOriginNote::WithName { span, msg, name, continues } => {
-                label_or_note(span, msg);
-                diag.set_arg("name", name);
-                diag.set_arg("continues", continues);
-            }
-            RegionOriginNote::WithRequirement {
-                span,
-                requirement,
-                expected_found: Some((expected, found)),
-            } => {
-                label_or_note(span, fluent::infer::subtype);
-                diag.set_arg("requirement", requirement);
-
-                diag.note_expected_found(&"", expected, &"", found);
-            }
-            RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
-                // FIXME: this really should be handled at some earlier stage. Our
-                // handling of region checking when type errors are present is
-                // *terrible*.
-                label_or_note(span, fluent::infer::subtype_2);
-                diag.set_arg("requirement", requirement);
-            }
-        };
-    }
-}
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
new file mode 100644 (file)
index 0000000..d232a18
--- /dev/null
@@ -0,0 +1,499 @@
+use hir::GenericParamKind;
+use rustc_errors::{
+    fluent, AddSubdiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString, MultiSpan,
+};
+use rustc_hir as hir;
+use rustc_hir::{FnRetTy, Ty};
+use rustc_macros::SessionDiagnostic;
+use rustc_middle::ty::{Region, TyCtxt};
+use rustc_span::symbol::kw;
+use rustc_span::{symbol::Ident, BytePos, Span};
+
+use crate::infer::error_reporting::{
+    need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
+    ObligationCauseAsDiagArg,
+};
+
+pub mod note_and_explain;
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::opaque_hidden_type)]
+pub struct OpaqueHiddenTypeDiag {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note(infer::opaque_type)]
+    pub opaque_type: Span,
+    #[note(infer::hidden_type)]
+    pub hidden_type: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::type_annotations_needed, code = "E0282")]
+pub struct AnnotationRequired<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub source_kind: &'static str,
+    pub source_name: &'a str,
+    #[label]
+    pub failure_span: Option<Span>,
+    #[subdiagnostic]
+    pub bad_label: Option<InferenceBadError<'a>>,
+    #[subdiagnostic]
+    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+    #[subdiagnostic]
+    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+// Copy of `AnnotationRequired` for E0283
+#[derive(SessionDiagnostic)]
+#[diag(infer::type_annotations_needed, code = "E0283")]
+pub struct AmbigousImpl<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub source_kind: &'static str,
+    pub source_name: &'a str,
+    #[label]
+    pub failure_span: Option<Span>,
+    #[subdiagnostic]
+    pub bad_label: Option<InferenceBadError<'a>>,
+    #[subdiagnostic]
+    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+    #[subdiagnostic]
+    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+// Copy of `AnnotationRequired` for E0284
+#[derive(SessionDiagnostic)]
+#[diag(infer::type_annotations_needed, code = "E0284")]
+pub struct AmbigousReturn<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub source_kind: &'static str,
+    pub source_name: &'a str,
+    #[label]
+    pub failure_span: Option<Span>,
+    #[subdiagnostic]
+    pub bad_label: Option<InferenceBadError<'a>>,
+    #[subdiagnostic]
+    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+    #[subdiagnostic]
+    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::need_type_info_in_generator, code = "E0698")]
+pub struct NeedTypeInfoInGenerator<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub generator_kind: GeneratorKindAsDiagArg,
+    #[subdiagnostic]
+    pub bad_label: InferenceBadError<'a>,
+}
+
+// Used when a better one isn't available
+#[derive(SessionSubdiagnostic)]
+#[label(infer::label_bad)]
+pub struct InferenceBadError<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub bad_kind: &'static str,
+    pub prefix_kind: UnderspecifiedArgKind,
+    pub has_parent: bool,
+    pub prefix: &'a str,
+    pub parent_prefix: &'a str,
+    pub parent_name: String,
+    pub name: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum SourceKindSubdiag<'a> {
+    #[suggestion_verbose(
+        infer::source_kind_subdiag_let,
+        code = ": {type_name}",
+        applicability = "has-placeholders"
+    )]
+    LetLike {
+        #[primary_span]
+        span: Span,
+        name: String,
+        type_name: String,
+        kind: &'static str,
+        x_kind: &'static str,
+        prefix_kind: UnderspecifiedArgKind,
+        prefix: &'a str,
+        arg_name: String,
+    },
+    #[label(infer::source_kind_subdiag_generic_label)]
+    GenericLabel {
+        #[primary_span]
+        span: Span,
+        is_type: bool,
+        param_name: String,
+        parent_exists: bool,
+        parent_prefix: String,
+        parent_name: String,
+    },
+    #[suggestion_verbose(
+        infer::source_kind_subdiag_generic_suggestion,
+        code = "::<{args}>",
+        applicability = "has-placeholders"
+    )]
+    GenericSuggestion {
+        #[primary_span]
+        span: Span,
+        arg_count: usize,
+        args: String,
+    },
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum SourceKindMultiSuggestion<'a> {
+    #[multipart_suggestion_verbose(
+        infer::source_kind_fully_qualified,
+        applicability = "has-placeholders"
+    )]
+    FullyQualified {
+        #[suggestion_part(code = "{def_path}({adjustment}")]
+        span_lo: Span,
+        #[suggestion_part(code = "{successor_pos}")]
+        span_hi: Span,
+        def_path: String,
+        adjustment: &'a str,
+        successor_pos: &'a str,
+    },
+    #[multipart_suggestion_verbose(
+        infer::source_kind_closure_return,
+        applicability = "has-placeholders"
+    )]
+    ClosureReturn {
+        #[suggestion_part(code = "{start_span_code}")]
+        start_span: Span,
+        start_span_code: String,
+        #[suggestion_part(code = " }}")]
+        end_span: Option<Span>,
+    },
+}
+
+impl<'a> SourceKindMultiSuggestion<'a> {
+    pub fn new_fully_qualified(
+        span: Span,
+        def_path: String,
+        adjustment: &'a str,
+        successor: (&'a str, BytePos),
+    ) -> Self {
+        Self::FullyQualified {
+            span_lo: span.shrink_to_lo(),
+            span_hi: span.shrink_to_hi().with_hi(successor.1),
+            def_path,
+            adjustment,
+            successor_pos: successor.0,
+        }
+    }
+
+    pub fn new_closure_return(
+        ty_info: String,
+        data: &'a FnRetTy<'a>,
+        should_wrap_expr: Option<Span>,
+    ) -> Self {
+        let (arrow, post) = match data {
+            FnRetTy::DefaultReturn(_) => ("-> ", " "),
+            _ => ("", ""),
+        };
+        let (start_span, start_span_code, end_span) = match should_wrap_expr {
+            Some(end_span) => {
+                (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post), Some(end_span))
+            }
+            None => (data.span(), format!("{}{}{}", arrow, ty_info, post), None),
+        };
+        Self::ClosureReturn { start_span, start_span_code, end_span }
+    }
+}
+
+pub enum RegionOriginNote<'a> {
+    Plain {
+        span: Span,
+        msg: DiagnosticMessage,
+    },
+    WithName {
+        span: Span,
+        msg: DiagnosticMessage,
+        name: &'a str,
+        continues: bool,
+    },
+    WithRequirement {
+        span: Span,
+        requirement: ObligationCauseAsDiagArg<'a>,
+        expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
+    },
+}
+
+impl AddSubdiagnostic for RegionOriginNote<'_> {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        let mut label_or_note = |span, msg: DiagnosticMessage| {
+            let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
+            let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
+            let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
+            if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
+                diag.span_label(span, msg);
+            } else if span_is_primary && expanded_sub_count == 0 {
+                diag.note(msg);
+            } else {
+                diag.span_note(span, msg);
+            }
+        };
+        match self {
+            RegionOriginNote::Plain { span, msg } => {
+                label_or_note(span, msg);
+            }
+            RegionOriginNote::WithName { span, msg, name, continues } => {
+                label_or_note(span, msg);
+                diag.set_arg("name", name);
+                diag.set_arg("continues", continues);
+            }
+            RegionOriginNote::WithRequirement {
+                span,
+                requirement,
+                expected_found: Some((expected, found)),
+            } => {
+                label_or_note(span, fluent::infer::subtype);
+                diag.set_arg("requirement", requirement);
+
+                diag.note_expected_found(&"", expected, &"", found);
+            }
+            RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
+                // FIXME: this really should be handled at some earlier stage. Our
+                // handling of region checking when type errors are present is
+                // *terrible*.
+                label_or_note(span, fluent::infer::subtype_2);
+                diag.set_arg("requirement", requirement);
+            }
+        };
+    }
+}
+
+pub enum LifetimeMismatchLabels {
+    InRet {
+        param_span: Span,
+        ret_span: Span,
+        span: Span,
+        label_var1: Option<Ident>,
+    },
+    Normal {
+        hir_equal: bool,
+        ty_sup: Span,
+        ty_sub: Span,
+        span: Span,
+        sup: Option<Ident>,
+        sub: Option<Ident>,
+    },
+}
+
+impl AddSubdiagnostic for LifetimeMismatchLabels {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        match self {
+            LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
+                diag.span_label(param_span, fluent::infer::declared_different);
+                diag.span_label(ret_span, fluent::infer::nothing);
+                diag.span_label(span, fluent::infer::data_returned);
+                diag.set_arg("label_var1_exists", label_var1.is_some());
+                diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
+            }
+            LifetimeMismatchLabels::Normal {
+                hir_equal,
+                ty_sup,
+                ty_sub,
+                span,
+                sup: label_var1,
+                sub: label_var2,
+            } => {
+                if hir_equal {
+                    diag.span_label(ty_sup, fluent::infer::declared_multiple);
+                    diag.span_label(ty_sub, fluent::infer::nothing);
+                    diag.span_label(span, fluent::infer::data_lifetime_flow);
+                } else {
+                    diag.span_label(ty_sup, fluent::infer::types_declared_different);
+                    diag.span_label(ty_sub, fluent::infer::nothing);
+                    diag.span_label(span, fluent::infer::data_flows);
+                    diag.set_arg("label_var1_exists", label_var1.is_some());
+                    diag.set_arg(
+                        "label_var1",
+                        label_var1.map(|x| x.to_string()).unwrap_or_default(),
+                    );
+                    diag.set_arg("label_var2_exists", label_var2.is_some());
+                    diag.set_arg(
+                        "label_var2",
+                        label_var2.map(|x| x.to_string()).unwrap_or_default(),
+                    );
+                }
+            }
+        }
+    }
+}
+
+pub struct AddLifetimeParamsSuggestion<'a> {
+    pub tcx: TyCtxt<'a>,
+    pub sub: Region<'a>,
+    pub ty_sup: &'a Ty<'a>,
+    pub ty_sub: &'a Ty<'a>,
+    pub add_note: bool,
+}
+
+impl AddSubdiagnostic for AddLifetimeParamsSuggestion<'_> {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        let mut mk_suggestion = || {
+            let (
+                hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
+                hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+            ) = (self.ty_sub, self.ty_sup) else {
+                return false;
+            };
+
+            if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
+                return false;
+            };
+
+            let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
+                return false;
+            };
+
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
+
+            let node = self.tcx.hir().get(hir_id);
+            let is_impl = matches!(&node, hir::Node::ImplItem(_));
+            let generics = match node {
+                hir::Node::Item(&hir::Item {
+                    kind: hir::ItemKind::Fn(_, ref generics, ..),
+                    ..
+                })
+                | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
+                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
+                _ => return false,
+            };
+
+            let suggestion_param_name = generics
+                .params
+                .iter()
+                .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+                .map(|p| p.name.ident().name)
+                .find(|i| *i != kw::UnderscoreLifetime);
+            let introduce_new = suggestion_param_name.is_none();
+            let suggestion_param_name =
+                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
+
+            debug!(?lifetime_sup.span);
+            debug!(?lifetime_sub.span);
+            let make_suggestion = |span: rustc_span::Span| {
+                if span.is_empty() {
+                    (span, format!("{}, ", suggestion_param_name))
+                } else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref()
+                {
+                    (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
+                } else {
+                    (span, suggestion_param_name.clone())
+                }
+            };
+            let mut suggestions =
+                vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
+
+            if introduce_new {
+                let new_param_suggestion = if let Some(first) =
+                    generics.params.iter().find(|p| !p.name.ident().span.is_empty())
+                {
+                    (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
+                } else {
+                    (generics.span, format!("<{}>", suggestion_param_name))
+                };
+
+                suggestions.push(new_param_suggestion);
+            }
+
+            diag.multipart_suggestion(
+                fluent::infer::lifetime_param_suggestion,
+                suggestions,
+                Applicability::MaybeIncorrect,
+            );
+            diag.set_arg("is_impl", is_impl);
+            true
+        };
+        if mk_suggestion() && self.add_note {
+            diag.note(fluent::infer::lifetime_param_suggestion_elided);
+        }
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::lifetime_mismatch, code = "E0623")]
+pub struct LifetimeMismatch<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub labels: LifetimeMismatchLabels,
+    #[subdiagnostic]
+    pub suggestion: AddLifetimeParamsSuggestion<'a>,
+}
+
+pub struct IntroducesStaticBecauseUnmetLifetimeReq {
+    pub unmet_requirements: MultiSpan,
+    pub binding_span: Span,
+}
+
+impl AddSubdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
+    fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) {
+        self.unmet_requirements
+            .push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
+        diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req);
+    }
+}
+
+pub struct ImplNote {
+    pub impl_span: Option<Span>,
+}
+
+impl AddSubdiagnostic for ImplNote {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        match self.impl_span {
+            Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
+            None => diag.note(fluent::infer::msl_impl_note),
+        };
+    }
+}
+
+pub enum TraitSubdiag {
+    Note { span: Span },
+    Sugg { span: Span },
+}
+
+// FIXME(#100717) used in `Vec<TraitSubdiag>` so requires eager translation/list support
+impl AddSubdiagnostic for TraitSubdiag {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        match self {
+            TraitSubdiag::Note { span } => {
+                diag.span_note(span, "this has an implicit `'static` lifetime requirement");
+            }
+            TraitSubdiag::Sugg { span } => {
+                diag.span_suggestion_verbose(
+                    span,
+                    "consider relaxing the implicit `'static` requirement",
+                    " + '_".to_owned(),
+                    rustc_errors::Applicability::MaybeIncorrect,
+                );
+            }
+        }
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::mismatched_static_lifetime)]
+pub struct MismatchedStaticLifetime<'a> {
+    #[primary_span]
+    pub cause_span: Span,
+    #[subdiagnostic]
+    pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq,
+    #[subdiagnostic]
+    pub expl: Option<note_and_explain::RegionExplanation<'a>>,
+    #[subdiagnostic]
+    pub impl_note: ImplNote,
+    #[subdiagnostic]
+    pub trait_subdiags: Vec<TraitSubdiag>,
+}
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
new file mode 100644 (file)
index 0000000..6f1f952
--- /dev/null
@@ -0,0 +1,179 @@
+use crate::infer::error_reporting::nice_region_error::find_anon_type;
+use rustc_errors::{self, fluent, AddSubdiagnostic, IntoDiagnosticArg};
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::{symbol::kw, Span};
+
+#[derive(Default)]
+struct DescriptionCtx<'a> {
+    span: Option<Span>,
+    kind: &'a str,
+    arg: String,
+    num_arg: u32,
+}
+
+impl<'a> DescriptionCtx<'a> {
+    fn new<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        region: ty::Region<'tcx>,
+        alt_span: Option<Span>,
+    ) -> Option<Self> {
+        let mut me = DescriptionCtx::default();
+        me.span = alt_span;
+        match *region {
+            ty::ReEarlyBound(_) | ty::ReFree(_) => {
+                return Self::from_early_bound_and_free_regions(tcx, region);
+            }
+            ty::ReStatic => {
+                me.kind = "restatic";
+            }
+
+            ty::ReEmpty(ty::UniverseIndex::ROOT) => me.kind = "reempty",
+
+            ty::ReEmpty(ui) => {
+                me.kind = "reemptyuni";
+                me.arg = format!("{:?}", ui);
+            }
+
+            ty::RePlaceholder(_) => return None,
+
+            // FIXME(#13998) RePlaceholder should probably print like
+            // ReFree rather than dumping Debug output on the user.
+            //
+            // We shouldn't really be having unification failures with ReVar
+            // and ReLateBound though.
+            ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
+                me.kind = "revar";
+                me.arg = format!("{:?}", region);
+            }
+        };
+        Some(me)
+    }
+
+    fn from_early_bound_and_free_regions<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        region: ty::Region<'tcx>,
+    ) -> Option<Self> {
+        let mut me = DescriptionCtx::default();
+        let scope = region.free_region_binding_scope(tcx).expect_local();
+        match *region {
+            ty::ReEarlyBound(ref br) => {
+                let mut sp = tcx.def_span(scope);
+                if let Some(param) =
+                    tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
+                {
+                    sp = param.span;
+                }
+                if br.has_name() {
+                    me.kind = "as_defined";
+                    me.arg = br.name.to_string();
+                } else {
+                    me.kind = "as_defined_anon";
+                };
+                me.span = Some(sp)
+            }
+            ty::ReFree(ref fr) => {
+                if !fr.bound_region.is_named()
+                    && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
+                {
+                    me.kind = "defined_here";
+                    me.span = Some(ty.span);
+                } else {
+                    match fr.bound_region {
+                        ty::BoundRegionKind::BrNamed(_, name) => {
+                            let mut sp = tcx.def_span(scope);
+                            if let Some(param) =
+                                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+                            {
+                                sp = param.span;
+                            }
+                            if name == kw::UnderscoreLifetime {
+                                me.kind = "as_defined_anon";
+                            } else {
+                                me.kind = "as_defined";
+                                me.arg = name.to_string();
+                            };
+                            me.span = Some(sp);
+                        }
+                        ty::BrAnon(idx) => {
+                            me.kind = "anon_num_here";
+                            me.num_arg = idx+1;
+                            me.span = Some(tcx.def_span(scope));
+                        },
+                        _ => {
+                            me.kind = "defined_here_reg";
+                            me.arg = region.to_string();
+                            me.span = Some(tcx.def_span(scope));
+                        },
+                    }
+                }
+            }
+            _ => bug!(),
+        }
+        Some(me)
+    }
+
+    fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
+        diag.set_arg("desc_kind", self.kind);
+        diag.set_arg("desc_arg", self.arg);
+        diag.set_arg("desc_num_arg", self.num_arg);
+    }
+}
+
+pub enum PrefixKind {
+    Empty,
+}
+
+pub enum SuffixKind {
+    Continues,
+}
+
+impl IntoDiagnosticArg for PrefixKind {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        let kind = match self {
+            Self::Empty => "empty",
+        }
+        .into();
+        rustc_errors::DiagnosticArgValue::Str(kind)
+    }
+}
+
+impl IntoDiagnosticArg for SuffixKind {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        let kind = match self {
+            Self::Continues => "continues",
+        }
+        .into();
+        rustc_errors::DiagnosticArgValue::Str(kind)
+    }
+}
+
+pub struct RegionExplanation<'a> {
+    desc: DescriptionCtx<'a>,
+    prefix: PrefixKind,
+    suffix: SuffixKind,
+}
+
+impl RegionExplanation<'_> {
+    pub fn new<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        region: ty::Region<'tcx>,
+        alt_span: Option<Span>,
+        prefix: PrefixKind,
+        suffix: SuffixKind,
+    ) -> Option<Self> {
+        Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix })
+    }
+}
+
+impl AddSubdiagnostic for RegionExplanation<'_> {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        if let Some(span) = self.desc.span {
+            diag.span_note(span, fluent::infer::region_explanation);
+        } else {
+            diag.note(fluent::infer::region_explanation);
+        }
+        self.desc.add_to(diag);
+        diag.set_arg("pref_kind", self.prefix);
+        diag.set_arg("suff_kind", self.suffix);
+    }
+}
index d4350aa5734dee4aefe5583a5f1e6233d0cf2303..c1fb59009d369ef5e85463ac42fe5654287721ad 100644 (file)
@@ -486,7 +486,7 @@ struct Generalizer<'cx, 'tcx> {
 
     param_env: ty::ParamEnv<'tcx>,
 
-    cache: SsoHashMap<Ty<'tcx>, RelateResult<'tcx, Ty<'tcx>>>,
+    cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
 }
 
 /// Result from a generalization operation. This includes
@@ -593,8 +593,8 @@ fn relate_with_variance<T: Relate<'tcx>>(
     fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
 
-        if let Some(result) = self.cache.get(&t) {
-            return result.clone();
+        if let Some(&result) = self.cache.get(&t) {
+            return Ok(result);
         }
         debug!("generalize: t={:?}", t);
 
@@ -664,10 +664,10 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 Ok(t)
             }
             _ => relate::super_relate_tys(self, t, t),
-        };
+        }?;
 
-        self.cache.insert(t, result.clone());
-        return result;
+        self.cache.insert(t, result);
+        Ok(result)
     }
 
     fn regions(
@@ -743,9 +743,7 @@ fn consts(
                     }
                 }
             }
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
-                if self.tcx().lazy_normalization() =>
-            {
+            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
                 assert_eq!(promoted, None);
                 let substs = self.relate_with_variance(
                     ty::Variance::Invariant,
@@ -967,9 +965,7 @@ fn consts(
                     }
                 }
             }
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
-                if self.tcx().lazy_normalization() =>
-            {
+            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
                 assert_eq!(promoted, None);
                 let substs = self.relate_with_variance(
                     ty::Variance::Invariant,
index d9252d426d82b8ed0aebc06353f08c6eb60f3c04..08460463998fdaca6829be873d158fe65f72aa6b 100644 (file)
@@ -61,6 +61,7 @@
 use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::Node;
@@ -1586,28 +1587,31 @@ enum Mismatch<'a> {
             Some(values) => {
                 let values = self.resolve_vars_if_possible(values);
                 let (is_simple_error, exp_found) = match values {
-                    ValuePairs::Terms(infer::ExpectedFound {
-                        expected: ty::Term::Ty(expected),
-                        found: ty::Term::Ty(found),
-                    }) => {
-                        let is_simple_err = expected.is_simple_text() && found.is_simple_text();
-                        OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
-                            .report(diag);
-
-                        (
-                            is_simple_err,
-                            Mismatch::Variable(infer::ExpectedFound { expected, found }),
-                        )
+                    ValuePairs::Terms(infer::ExpectedFound { expected, found }) => {
+                        match (expected.unpack(), found.unpack()) {
+                            (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
+                                let is_simple_err =
+                                    expected.is_simple_text() && found.is_simple_text();
+                                OpaqueTypesVisitor::visit_expected_found(
+                                    self.tcx, expected, found, span,
+                                )
+                                .report(diag);
+
+                                (
+                                    is_simple_err,
+                                    Mismatch::Variable(infer::ExpectedFound { expected, found }),
+                                )
+                            }
+                            (ty::TermKind::Const(_), ty::TermKind::Const(_)) => {
+                                (false, Mismatch::Fixed("constant"))
+                            }
+                            _ => (false, Mismatch::Fixed("type")),
+                        }
                     }
-                    ValuePairs::Terms(infer::ExpectedFound {
-                        expected: ty::Term::Const(_),
-                        found: ty::Term::Const(_),
-                    }) => (false, Mismatch::Fixed("constant")),
                     ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
                         (false, Mismatch::Fixed("trait"))
                     }
                     ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
-                    _ => (false, Mismatch::Fixed("type")),
                 };
                 let vals = match self.values_str(values) {
                     Some((expected, found)) => Some((expected, found)),
@@ -1679,6 +1683,19 @@ enum Mismatch<'a> {
                                 pos.col.to_usize() + 1,
                             )
                         }
+                        (true, ty::Projection(proj))
+                            if self.tcx.def_kind(proj.item_def_id)
+                                == DefKind::ImplTraitPlaceholder =>
+                        {
+                            let sm = self.tcx.sess.source_map();
+                            let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
+                            format!(
+                                " (trait associated opaque type at <{}:{}:{}>)",
+                                sm.filename_for_diagnostics(&pos.file.name),
+                                pos.line,
+                                pos.col.to_usize() + 1,
+                            )
+                        }
                         (true, _) => format!(" ({})", ty.sort_string(self.tcx)),
                         (false, _) => "".to_string(),
                     };
@@ -1755,7 +1772,7 @@ enum Mismatch<'a> {
 
         // In some (most?) cases cause.body_id points to actual body, but in some cases
         // it's an actual definition. According to the comments (e.g. in
-        // librustc_typeck/check/compare_method.rs:compare_predicate_entailment) the latter
+        // librustc_typeck/check/compare_method.rs:compare_predicates_and_trait_impl_trait_tys) the latter
         // is relied upon by some other code. This might (or might not) need cleanup.
         let body_owner_def_id =
             self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {
@@ -2273,11 +2290,11 @@ fn expected_found_str_term(
             return None;
         }
 
-        Some(match (exp_found.expected, exp_found.found) {
-            (ty::Term::Ty(expected), ty::Term::Ty(found)) => self.cmp(expected, found),
-            (expected, found) => (
-                DiagnosticStyledString::highlighted(expected.to_string()),
-                DiagnosticStyledString::highlighted(found.to_string()),
+        Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) {
+            (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => self.cmp(expected, found),
+            _ => (
+                DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
+                DiagnosticStyledString::highlighted(exp_found.found.to_string()),
             ),
         })
     }
index 20ce28fe8d03d966925f174f8c9e8e37893597c0..cb2be93589d051b13da021d5a363b9416dd577c9 100644 (file)
@@ -511,20 +511,20 @@ pub fn emit_inference_failure_err(
                     _ => "",
                 };
 
-                multi_suggestions.push(SourceKindMultiSuggestion::FullyQualified {
-                    span: receiver.span,
+                multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
+                    receiver.span,
                     def_path,
                     adjustment,
                     successor,
-                });
+                ));
             }
             InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
                 let ty_info = ty_to_string(self, ty);
-                multi_suggestions.push(SourceKindMultiSuggestion::ClosureReturn {
+                multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
                     ty_info,
                     data,
                     should_wrap_expr,
-                });
+                ));
             }
         }
         match error_code {
index 9a2ab3e32248bfda7c966720cc25cabb6de2bda4..3a4320a9a8f1d23f3d8874cf5fc8ba5d36e34303 100644 (file)
@@ -1,6 +1,9 @@
 //! Error Reporting for Anonymous Region Lifetime Errors
 //! where both the regions are anonymous.
 
+use crate::errors::AddLifetimeParamsSuggestion;
+use crate::errors::LifetimeMismatch;
+use crate::errors::LifetimeMismatchLabels;
 use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
 use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo;
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::SubregionOrigin;
 use crate::infer::TyCtxt;
 
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
-use rustc_hir as hir;
-use rustc_hir::{GenericParamKind, Ty};
+use rustc_errors::AddSubdiagnostic;
+use rustc_errors::{Diagnostic, ErrorGuaranteed};
+use rustc_hir::Ty;
 use rustc_middle::ty::Region;
-use rustc_span::symbol::kw;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when both the concerned regions are anonymous.
@@ -98,137 +100,50 @@ pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorGuaranteed> {
         let sub_is_ret_type =
             self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
 
-        let span_label_var1 = match anon_param_sup.pat.simple_ident() {
-            Some(simple_ident) => format!(" from `{}`", simple_ident),
-            None => String::new(),
-        };
-
-        let span_label_var2 = match anon_param_sub.pat.simple_ident() {
-            Some(simple_ident) => format!(" into `{}`", simple_ident),
-            None => String::new(),
-        };
-
         debug!(
             "try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}",
             sub_is_ret_type, sup_is_ret_type
         );
 
-        let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
-
-        match (sup_is_ret_type, sub_is_ret_type) {
+        let labels = match (sup_is_ret_type, sub_is_ret_type) {
             (ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => {
                 let param_span =
                     if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span };
-
-                err.span_label(
+                LifetimeMismatchLabels::InRet {
                     param_span,
-                    "this parameter and the return type are declared with different lifetimes...",
-                );
-                err.span_label(ret_span, "");
-                err.span_label(span, format!("...but data{} is returned here", span_label_var1));
-            }
-
-            (None, None) => {
-                if ty_sup.hir_id == ty_sub.hir_id {
-                    err.span_label(ty_sup.span, "this type is declared with multiple lifetimes...");
-                    err.span_label(ty_sub.span, "");
-                    err.span_label(span, "...but data with one lifetime flows into the other here");
-                } else {
-                    err.span_label(
-                        ty_sup.span,
-                        "these two types are declared with different lifetimes...",
-                    );
-                    err.span_label(ty_sub.span, "");
-                    err.span_label(
-                        span,
-                        format!("...but data{} flows{} here", span_label_var1, span_label_var2),
-                    );
+                    ret_span,
+                    span,
+                    label_var1: anon_param_sup.pat.simple_ident(),
                 }
             }
-        }
 
-        if suggest_adding_lifetime_params(self.tcx(), sub, ty_sup, ty_sub, &mut err) {
-            err.note("each elided lifetime in input position becomes a distinct lifetime");
-        }
+            (None, None) => LifetimeMismatchLabels::Normal {
+                hir_equal: ty_sup.hir_id == ty_sub.hir_id,
+                ty_sup: ty_sup.span,
+                ty_sub: ty_sub.span,
+                span,
+                sup: anon_param_sup.pat.simple_ident(),
+                sub: anon_param_sub.pat.simple_ident(),
+            },
+        };
 
-        let reported = err.emit();
+        let suggestion =
+            AddLifetimeParamsSuggestion { tcx: self.tcx(), sub, ty_sup, ty_sub, add_note: true };
+        let err = LifetimeMismatch { span, labels, suggestion };
+        let reported = self.tcx().sess.emit_err(err);
         Some(reported)
     }
 }
 
+/// Currently only used in rustc_borrowck, probably should be
+/// removed in favour of public_errors::AddLifetimeParamsSuggestion
 pub fn suggest_adding_lifetime_params<'tcx>(
     tcx: TyCtxt<'tcx>,
     sub: Region<'tcx>,
-    ty_sup: &Ty<'_>,
-    ty_sub: &Ty<'_>,
+    ty_sup: &'tcx Ty<'_>,
+    ty_sub: &'tcx Ty<'_>,
     err: &mut Diagnostic,
-) -> bool {
-    let (
-        hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
-        hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
-    ) = (ty_sub, ty_sup) else {
-        return false;
-    };
-
-    if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
-        return false;
-    };
-
-    let Some(anon_reg) = tcx.is_suitable_region(sub) else {
-        return false;
-    };
-
-    let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
-
-    let node = tcx.hir().get(hir_id);
-    let is_impl = matches!(&node, hir::Node::ImplItem(_));
-    let generics = match node {
-        hir::Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, ref generics, ..), .. })
-        | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
-        | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
-        _ => return false,
-    };
-
-    let suggestion_param_name = generics
-        .params
-        .iter()
-        .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
-        .map(|p| p.name.ident().name)
-        .find(|i| *i != kw::UnderscoreLifetime);
-    let introduce_new = suggestion_param_name.is_none();
-    let suggestion_param_name =
-        suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
-
-    debug!(?lifetime_sup.span);
-    debug!(?lifetime_sub.span);
-    let make_suggestion = |span: rustc_span::Span| {
-        if span.is_empty() {
-            (span, format!("{}, ", suggestion_param_name))
-        } else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() {
-            (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
-        } else {
-            (span, suggestion_param_name.clone())
-        }
-    };
-    let mut suggestions =
-        vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
-
-    if introduce_new {
-        let new_param_suggestion =
-            if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) {
-                (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
-            } else {
-                (generics.span, format!("<{}>", suggestion_param_name))
-            };
-
-        suggestions.push(new_param_suggestion);
-    }
-
-    let mut sugg = String::from("consider introducing a named lifetime parameter");
-    if is_impl {
-        sugg.push_str(" and update trait if needed");
-    }
-    err.multipart_suggestion(sugg, suggestions, Applicability::MaybeIncorrect);
-
-    true
+) {
+    let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false };
+    suggestion.add_to_diagnostic(err);
 }
index c20b96cae2e4f000a28da7346e06c14b1b40e2f0..1410e2b63b0b87fbfa433ba727a410780b1354de 100644 (file)
@@ -1,13 +1,14 @@
 //! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate
 //! to hold.
 
+use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq};
+use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag};
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use crate::infer::error_reporting::note_and_explain_region;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::ObligationCauseCode;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::ty::TypeVisitor;
@@ -39,12 +40,23 @@ pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorGuaran
             = *parent.code() else {
             return None;
         };
-        let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type");
+
         // FIXME: we should point at the lifetime
-        let mut multi_span: MultiSpan = vec![binding_span].into();
-        multi_span.push_span_label(binding_span, "introduces a `'static` lifetime requirement");
-        err.span_note(multi_span, "because this has an unmet lifetime requirement");
-        note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span));
+        let multi_span: MultiSpan = vec![binding_span].into();
+        let multispan_subdiag = IntroducesStaticBecauseUnmetLifetimeReq {
+            unmet_requirements: multi_span,
+            binding_span,
+        };
+
+        let expl = note_and_explain::RegionExplanation::new(
+            self.tcx(),
+            sup,
+            Some(binding_span),
+            note_and_explain::PrefixKind::Empty,
+            note_and_explain::SuffixKind::Continues,
+        );
+        let mut impl_span = None;
+        let mut trait_subdiags = Vec::new();
         if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
             // If an impl is local, then maybe this isn't what they want. Try to
             // be as helpful as possible with implicit lifetimes.
@@ -73,31 +85,30 @@ pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorGuaran
                 // there aren't trait objects or because none are implicit, then just
                 // write a single note on the impl itself.
 
-                let impl_span = self.tcx().def_span(*impl_def_id);
-                err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
+                impl_span = Some(self.tcx().def_span(*impl_def_id));
             } else {
                 // Otherwise, point at all implicit static lifetimes
 
-                err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
                 for span in &traits {
-                    err.span_note(*span, "this has an implicit `'static` lifetime requirement");
+                    trait_subdiags.push(TraitSubdiag::Note { span: *span });
                     // It would be nice to put this immediately under the above note, but they get
                     // pushed to the end.
-                    err.span_suggestion_verbose(
-                        span.shrink_to_hi(),
-                        "consider relaxing the implicit `'static` requirement",
-                        " + '_",
-                        Applicability::MaybeIncorrect,
-                    );
+                    trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() });
                 }
             }
         } else {
             // Otherwise just point out the impl.
 
-            let impl_span = self.tcx().def_span(*impl_def_id);
-            err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
+            impl_span = Some(self.tcx().def_span(*impl_def_id));
         }
-        let reported = err.emit();
+        let err = MismatchedStaticLifetime {
+            cause_span: cause.span,
+            unmet_lifetime_reqs: multispan_subdiag,
+            expl,
+            impl_note: ImplNote { impl_span },
+            trait_subdiags,
+        };
+        let reported = self.tcx().sess.emit_err(err);
         Some(reported)
     }
 }
index f804569b0747ea0c45771f7f6be92de3fc603e02..b115ac8b3df954ba0f388bd07b27fe85e9a70fe1 100644 (file)
@@ -300,7 +300,7 @@ pub fn suggest_new_region_bound(
             continue;
         }
         match fn_return.kind {
-            TyKind::OpaqueDef(item_id, _) => {
+            TyKind::OpaqueDef(item_id, _, _) => {
                 let item = tcx.hir().item(item_id);
                 let ItemKind::OpaqueTy(opaque) = &item.kind else {
                     return;
index fe037a458a7f85106d756c92aef897a779552738..bbbc044b85a48e7f17a899116691a99e36e816d4 100644 (file)
@@ -353,12 +353,11 @@ pub enum ValuePairs<'tcx> {
 
 impl<'tcx> ValuePairs<'tcx> {
     pub fn ty(&self) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
-        if let ValuePairs::Terms(ExpectedFound {
-            expected: ty::Term::Ty(expected),
-            found: ty::Term::Ty(found),
-        }) = self
+        if let ValuePairs::Terms(ExpectedFound { expected, found }) = self
+            && let Some(expected) = expected.ty()
+            && let Some(found) = found.ty()
         {
-            Some((*expected, *found))
+            Some((expected, found))
         } else {
             None
         }
index c7d7ef40d9d413ae64a541371e73a6f3154ca9de..75233495040ca561dfed4ab9a4425641bd816e64 100644 (file)
@@ -50,13 +50,13 @@ pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
-        debug!("param_bound(param_ty={:?})", param_ty);
-
         // Start with anything like `T: 'a` we can scrape from the
         // environment. If the environment contains something like
         // `for<'a> T: 'a`, then we know that `T` outlives everything.
         let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty);
+        debug!(?declared_bounds_from_env);
         let mut param_bounds = vec![];
         for declared_bound in declared_bounds_from_env {
             let bound_region = declared_bound.map_bound(|outlives| outlives.1);
@@ -65,6 +65,7 @@ fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
                 param_bounds.push(VerifyBound::OutlivedBy(region));
             } else {
                 // This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here.
+                debug!("found that {param_ty:?} outlives any lifetime, returning empty vector");
                 return VerifyBound::AllBounds(vec![]);
             }
         }
@@ -72,6 +73,7 @@ fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
         // Add in the default bound of fn body that applies to all in
         // scope type parameters:
         if let Some(r) = self.implicit_region_bound {
+            debug!("adding implicit region bound of {r:?}");
             param_bounds.push(VerifyBound::OutlivedBy(r));
         }
 
index bb534a3c7afce6399abb885ae5dfe2984e22aab9..c41b154c3e066cb936a5b76a3cce35bbaaf823db 100644 (file)
@@ -573,13 +573,24 @@ fn write_out_deps(
         // Account for explicitly marked-to-track files
         // (e.g. accessed in proc macros).
         let file_depinfo = sess.parse_sess.file_depinfo.borrow();
-        let extra_tracked_files = file_depinfo.iter().map(|path_sym| {
-            let path = PathBuf::from(path_sym.as_str());
+
+        let normalize_path = |path: PathBuf| {
             let file = FileName::from(path);
             escape_dep_filename(&file.prefer_local().to_string())
-        });
+        };
+
+        let extra_tracked_files =
+            file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str())));
         files.extend(extra_tracked_files);
 
+        // We also need to track used PGO profile files
+        if let Some(ref profile_instr) = sess.opts.cg.profile_use {
+            files.push(normalize_path(profile_instr.as_path().to_path_buf()));
+        }
+        if let Some(ref profile_sample) = sess.opts.unstable_opts.profile_sample_use {
+            files.push(normalize_path(profile_sample.as_path().to_path_buf()));
+        }
+
         if sess.binary_dep_depinfo() {
             if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend {
                 if backend.contains('.') {
index 178366f7d8045a9263ec22a7081bef423f103ffa..a79c982649afca775168aa27d61a4a875bad075a 100644 (file)
@@ -141,7 +141,7 @@ pub enum TokenKind {
     Unknown,
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum DocStyle {
     Outer,
     Inner,
index 9a163cf207e97ba7dc6bc0a56d81c4af6c21edcc..7ca6ec5d9623475eaeabb13eba62360d85cd7d8c 100644 (file)
 use std::iter;
 use std::slice;
 
+type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync;
+type LateLintPassFactory =
+    dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::Send + sync::Sync;
+
 /// Information about the registered lints.
 ///
 /// This is basically the subset of `Context` that we can
@@ -64,11 +68,11 @@ pub struct LintStore {
     /// interior mutability, we don't enforce this (and lints should, in theory,
     /// be compatible with being constructed more than once, though not
     /// necessarily in a sane manner. This is safe though.)
-    pub pre_expansion_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
-    pub early_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
-    pub late_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
+    pub pre_expansion_passes: Vec<Box<EarlyLintPassFactory>>,
+    pub early_passes: Vec<Box<EarlyLintPassFactory>>,
+    pub late_passes: Vec<Box<LateLintPassFactory>>,
     /// This is unique in that we construct them per-module, so not once.
-    pub late_module_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
+    pub late_module_passes: Vec<Box<LateLintPassFactory>>,
 
     /// Lints indexed by name.
     by_name: FxHashMap<String, TargetLint>,
@@ -186,14 +190,20 @@ pub fn register_pre_expansion_pass(
 
     pub fn register_late_pass(
         &mut self,
-        pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync,
+        pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
+        + 'static
+        + sync::Send
+        + sync::Sync,
     ) {
         self.late_passes.push(Box::new(pass));
     }
 
     pub fn register_late_mod_pass(
         &mut self,
-        pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync,
+        pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
+        + 'static
+        + sync::Send
+        + sync::Sync,
     ) {
         self.late_module_passes.push(Box::new(pass));
     }
@@ -558,7 +568,7 @@ pub trait LintPassObject: Sized {}
 
 impl LintPassObject for EarlyLintPassObject {}
 
-impl LintPassObject for LateLintPassObject {}
+impl LintPassObject for LateLintPassObject<'_> {}
 
 pub trait LintContext: Sized {
     type PassObject: LintPassObject;
@@ -949,8 +959,8 @@ pub(crate) fn new(
     }
 }
 
-impl LintContext for LateContext<'_> {
-    type PassObject = LateLintPassObject;
+impl<'tcx> LintContext for LateContext<'tcx> {
+    type PassObject = LateLintPassObject<'tcx>;
 
     /// Gets the overall compiler `Session` object.
     fn sess(&self) -> &Session {
index 8a336844dc2fac73f02f7c0fb003ae23ac77181c..66dc3ed59a3841b00b64b19196f14151382ab1e7 100644 (file)
@@ -306,12 +306,12 @@ fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
     }
 }
 
-struct LateLintPassObjects<'a> {
-    lints: &'a mut [LateLintPassObject],
+struct LateLintPassObjects<'a, 'tcx> {
+    lints: &'a mut [LateLintPassObject<'tcx>],
 }
 
 #[allow(rustc::lint_pass_impl_without_macro)]
-impl LintPass for LateLintPassObjects<'_> {
+impl LintPass for LateLintPassObjects<'_, '_> {
     fn name(&self) -> &'static str {
         panic!()
     }
@@ -329,7 +329,7 @@ macro_rules! expand_late_lint_pass_impl_methods {
 
 macro_rules! late_lint_pass_impl {
     ([], [$hir:tt], $methods:tt) => {
-        impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_> {
+        impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_, $hir> {
             expand_late_lint_pass_impl_methods!([$hir], $methods);
         }
     };
@@ -382,7 +382,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>(
     late_lint_mod_pass(tcx, module_def_id, builtin_lints);
 
     let mut passes: Vec<_> =
-        unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect();
+        unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect();
 
     if !passes.is_empty() {
         late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
@@ -418,7 +418,8 @@ fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T)
 }
 
 fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
-    let mut passes = unerased_lint_store(tcx).late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
+    let mut passes =
+        unerased_lint_store(tcx).late_passes.iter().map(|p| (p)(tcx)).collect::<Vec<_>>();
 
     if !tcx.sess.opts.unstable_opts.no_interleave_lints {
         if !passes.is_empty() {
@@ -434,7 +435,7 @@ fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints
         }
 
         let mut passes: Vec<_> =
-            unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect();
+            unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect();
 
         for pass in &mut passes {
             tcx.sess.prof.extra_verbose_generic_activity("run_late_module_lint", pass.name()).run(
index 370a75cf700691d81485c3a13f15f54ccc40e93a..e0e6f1a8c080caf0b3dbbe2748262041acd6ca2b 100644 (file)
@@ -260,26 +260,41 @@ macro_rules! add_lint_group {
         )
     }
 
-    macro_rules! register_pass {
+    macro_rules! register_early_pass {
         ($method:ident, $ty:ident, $constructor:expr) => {
             store.register_lints(&$ty::get_lints());
             store.$method(|| Box::new($constructor));
         };
     }
 
-    macro_rules! register_passes {
+    macro_rules! register_late_pass {
+        ($method:ident, $ty:ident, $constructor:expr) => {
+            store.register_lints(&$ty::get_lints());
+            store.$method(|_| Box::new($constructor));
+        };
+    }
+
+    macro_rules! register_early_passes {
+        ($method:ident, [$($passes:ident: $constructor:expr,)*]) => (
+            $(
+                register_early_pass!($method, $passes, $constructor);
+            )*
+        )
+    }
+
+    macro_rules! register_late_passes {
         ($method:ident, [$($passes:ident: $constructor:expr,)*]) => (
             $(
-                register_pass!($method, $passes, $constructor);
+                register_late_pass!($method, $passes, $constructor);
             )*
         )
     }
 
     if no_interleave_lints {
-        pre_expansion_lint_passes!(register_passes, register_pre_expansion_pass);
-        early_lint_passes!(register_passes, register_early_pass);
-        late_lint_passes!(register_passes, register_late_pass);
-        late_lint_mod_passes!(register_passes, register_late_mod_pass);
+        pre_expansion_lint_passes!(register_early_passes, register_pre_expansion_pass);
+        early_lint_passes!(register_early_passes, register_early_pass);
+        late_lint_passes!(register_late_passes, register_late_pass);
+        late_lint_mod_passes!(register_late_passes, register_late_mod_pass);
     } else {
         store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints());
         store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
@@ -510,19 +525,19 @@ fn register_internals(store: &mut LintStore) {
     store.register_lints(&LintPassImpl::get_lints());
     store.register_early_pass(|| Box::new(LintPassImpl));
     store.register_lints(&DefaultHashTypes::get_lints());
-    store.register_late_pass(|| Box::new(DefaultHashTypes));
+    store.register_late_pass(|_| Box::new(DefaultHashTypes));
     store.register_lints(&QueryStability::get_lints());
-    store.register_late_pass(|| Box::new(QueryStability));
+    store.register_late_pass(|_| Box::new(QueryStability));
     store.register_lints(&ExistingDocKeyword::get_lints());
-    store.register_late_pass(|| Box::new(ExistingDocKeyword));
+    store.register_late_pass(|_| Box::new(ExistingDocKeyword));
     store.register_lints(&TyTyKind::get_lints());
-    store.register_late_pass(|| Box::new(TyTyKind));
+    store.register_late_pass(|_| Box::new(TyTyKind));
     store.register_lints(&Diagnostics::get_lints());
-    store.register_late_pass(|| Box::new(Diagnostics));
+    store.register_late_pass(|_| Box::new(Diagnostics));
     store.register_lints(&BadOptAccess::get_lints());
-    store.register_late_pass(|| Box::new(BadOptAccess));
+    store.register_late_pass(|_| Box::new(BadOptAccess));
     store.register_lints(&PassByValue::get_lints());
-    store.register_late_pass(|| Box::new(PassByValue));
+    store.register_late_pass(|_| Box::new(PassByValue));
     // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and
     // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and
     // these lints will trigger all of the time - change this once migration to diagnostic structs
index 90c554c2e040bf248c36969efdbccb8409cca4ea..666e61b85acfc8c21eeaac9705da51e98f5678d0 100644 (file)
@@ -244,4 +244,4 @@ fn name(&self) -> &'static str {
 
 /// A lint pass boxed up as a trait object.
 pub type EarlyLintPassObject = Box<dyn EarlyLintPass + sync::Send + 'static>;
-pub type LateLintPassObject = Box<dyn for<'tcx> LateLintPass<'tcx> + sync::Send + 'static>;
+pub type LateLintPassObject<'tcx> = Box<dyn LateLintPass<'tcx> + sync::Send + 'tcx>;
index 05d2a214d0b79374b73454ab9c7592fe2d7b9255..24e18826048983f2e51cc4f0f2546328b8aa16a4 100644 (file)
@@ -134,7 +134,12 @@ extern "C" LLVMPassRef LLVMRustCreateMemorySanitizerPass(int TrackOrigins, bool
   const bool CompileKernel = false;
 
   return wrap(createMemorySanitizerLegacyPassPass(
-      MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel}));
+#if LLVM_VERSION_GE(14, 0)
+      MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel, /*EagerChecks=*/true}
+#else
+      MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel}
+#endif
+  ));
 #else
   report_fatal_error("Legacy PM not supported with LLVM 15");
 #endif
@@ -930,18 +935,28 @@ LLVMRustOptimizeWithNewPassManager(
 
   if (SanitizerOptions) {
     if (SanitizerOptions->SanitizeMemory) {
+#if LLVM_VERSION_GE(14, 0)
+      MemorySanitizerOptions Options(
+          SanitizerOptions->SanitizeMemoryTrackOrigins,
+          SanitizerOptions->SanitizeMemoryRecover,
+          /*CompileKernel=*/false,
+          /*EagerChecks=*/true);
+#else
       MemorySanitizerOptions Options(
           SanitizerOptions->SanitizeMemoryTrackOrigins,
           SanitizerOptions->SanitizeMemoryRecover,
           /*CompileKernel=*/false);
+#endif
       OptimizerLastEPCallbacks.push_back(
         [Options](ModulePassManager &MPM, OptimizationLevel Level) {
-#if LLVM_VERSION_GE(14, 0)
+#if LLVM_VERSION_GE(14, 0) && LLVM_VERSION_LT(16, 0)
           MPM.addPass(ModuleMemorySanitizerPass(Options));
 #else
           MPM.addPass(MemorySanitizerPass(Options));
 #endif
+#if LLVM_VERSION_LT(16, 0)
           MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
+#endif
         }
       );
     }
@@ -972,7 +987,11 @@ LLVMRustOptimizeWithNewPassManager(
             /*UseAfterScope=*/true,
             AsanDetectStackUseAfterReturnMode::Runtime,
           };
+#if LLVM_VERSION_LT(16, 0)
           MPM.addPass(ModuleAddressSanitizerPass(opts));
+#else
+          MPM.addPass(AddressSanitizerPass(opts));
+#endif
 #else
           MPM.addPass(ModuleAddressSanitizerPass(
               /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
index 931ce78721cb862b7b83d28352bd3bdbbfc6ff15..6ee3c7d68213ee9382413d66975ee048ed9bb7f3 100644 (file)
@@ -1618,6 +1618,14 @@ extern "C" LLVMValueRef LLVMRustConstInBoundsGEP2(LLVMTypeRef Ty,
   return wrap(ConstantExpr::getInBoundsGetElementPtr(unwrap(Ty), Val, IdxList));
 }
 
+extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) {
+    auto C = unwrap<llvm::ConstantInt>(CV);
+    if (C->getBitWidth() > 64)
+      return false;
+    *value = C->getZExtValue();
+    return true;
+}
+
 // Returns true if both high and low were successfully set. Fails in case constant wasn’t any of
 // the common sizes (1, 8, 16, 32, 64, 128 bits)
 extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *high, uint64_t *low)
index 87b5e750f1cb14fba7110775e572e53af2aa34ae..3acabc4e69ce653b96d7d3a8a142c73b15a12f28 100644 (file)
@@ -113,12 +113,12 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                             "raw-dylib" => {
                                 if !sess.target.is_like_windows {
                                     sess.emit_err(FrameworkOnlyWindows { span });
-                                } else if !features.raw_dylib {
+                                } else if !features.raw_dylib && sess.target.arch == "x86" {
                                     feature_err(
                                         &sess.parse_sess,
                                         sym::raw_dylib,
                                         span,
-                                        "link kind `raw-dylib` is unstable",
+                                        "link kind `raw-dylib` is unstable on x86",
                                     )
                                     .emit();
                                 }
index 6f026678170b7af312fbde3ba26f97d40ebf3982..562246f4e8a1b239db23ab7af534d752cca14ba6 100644 (file)
@@ -911,8 +911,14 @@ fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics {
         self.root.tables.generics_of.get(self, item_id).unwrap().decode((self, sess))
     }
 
-    fn get_visibility(self, id: DefIndex) -> ty::Visibility {
-        self.root.tables.visibility.get(self, id).unwrap().decode(self)
+    fn get_visibility(self, id: DefIndex) -> ty::Visibility<DefId> {
+        self.root
+            .tables
+            .visibility
+            .get(self, id)
+            .unwrap()
+            .decode(self)
+            .map_id(|index| self.local_def_id(index))
     }
 
     fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> {
@@ -1182,7 +1188,10 @@ fn get_struct_field_names(
             .map(move |index| respan(self.get_span(index, sess), self.item_name(index)))
     }
 
-    fn get_struct_field_visibilities(self, id: DefIndex) -> impl Iterator<Item = Visibility> + 'a {
+    fn get_struct_field_visibilities(
+        self,
+        id: DefIndex,
+    ) -> impl Iterator<Item = Visibility<DefId>> + 'a {
         self.root
             .tables
             .children
index 6b447ebd99910ae21f348d34728e24b00095168f..dede1b2122a3cc06f62b8efb4b76f9f78f6b9419 100644 (file)
@@ -210,7 +210,6 @@ fn into_args(self) -> (DefId, SimplifiedType) {
     lookup_const_stability => { table }
     lookup_default_body_stability => { table }
     lookup_deprecation_entry => { table }
-    visibility => { table }
     unused_generic_params => { table }
     opt_def_kind => { table_direct }
     impl_parent => { table }
@@ -225,6 +224,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
     generator_kind => { table }
     trait_def => { table }
 
+    visibility => { cdata.get_visibility(def_id.index) }
     adt_def => { cdata.get_adt_def(def_id.index, tcx) }
     adt_destructor => {
         let _ = cdata;
@@ -485,7 +485,7 @@ pub fn struct_field_names_untracked<'a>(
     pub fn struct_field_visibilities_untracked(
         &self,
         def: DefId,
-    ) -> impl Iterator<Item = Visibility> + '_ {
+    ) -> impl Iterator<Item = Visibility<DefId>> + '_ {
         self.get_crate_data(def.krate).get_struct_field_visibilities(def.index)
     }
 
@@ -493,7 +493,7 @@ pub fn ctor_def_id_and_kind_untracked(&self, def: DefId) -> Option<(DefId, CtorK
         self.get_crate_data(def.krate).get_ctor_def_id_and_kind(def.index)
     }
 
-    pub fn visibility_untracked(&self, def: DefId) -> Visibility {
+    pub fn visibility_untracked(&self, def: DefId) -> Visibility<DefId> {
         self.get_crate_data(def.krate).get_visibility(def.index)
     }
 
index 039486ba02c37a466b580cfb163580f9c95a19ac..f967ac9a4dc3ed25dc05f26b60107eef1d7edcd1 100644 (file)
@@ -847,6 +847,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
         | DefKind::Use
         | DefKind::ForeignMod
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::Impl
         | DefKind::Field => true,
         DefKind::TyParam
@@ -879,6 +880,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
         | DefKind::ForeignMod
         | DefKind::TyAlias
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::Enum
         | DefKind::Union
         | DefKind::Impl
@@ -967,6 +969,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
         | DefKind::ForeignMod
         | DefKind::TyAlias
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::Impl
         | DefKind::Trait
         | DefKind::TraitAlias
@@ -1003,6 +1006,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
         | DefKind::AnonConst
         | DefKind::InlineConst
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::Impl
         | DefKind::Field
         | DefKind::TyParam
@@ -1032,6 +1036,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
         | DefKind::Static(..)
         | DefKind::TyAlias
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::ForeignTy
         | DefKind::Impl
         | DefKind::AssocFn
@@ -1081,6 +1086,7 @@ fn should_encode_const(def_kind: DefKind) -> bool {
         | DefKind::Static(..)
         | DefKind::TyAlias
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::ForeignTy
         | DefKind::Impl
         | DefKind::AssocFn
@@ -1138,7 +1144,9 @@ fn encode_def_ids(&mut self) {
                 record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id));
             }
             if should_encode_visibility(def_kind) {
-                record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+                let vis =
+                    self.tcx.local_visibility(local_id).map_id(|def_id| def_id.local_def_index);
+                record!(self.tables.visibility[def_id] <- vis);
             }
             if should_encode_stability(def_kind) {
                 self.encode_stability(def_id);
@@ -1727,7 +1735,8 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
             self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
             record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
             self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local());
-            record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
+            let vis = tcx.local_visibility(CRATE_DEF_ID).map_id(|def_id| def_id.local_def_index);
+            record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- vis);
             if let Some(stability) = stability {
                 record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability);
             }
index 6f849a58580e679550216f06ff690d75e11a8a8f..748b3afec37c7b0661c7798b7f84a8945c013645 100644 (file)
@@ -338,7 +338,7 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     children: Table<DefIndex, LazyArray<DefIndex>>,
 
     opt_def_kind: Table<DefIndex, DefKind>,
-    visibility: Table<DefIndex, LazyValue<ty::Visibility>>,
+    visibility: Table<DefIndex, LazyValue<ty::Visibility<DefIndex>>>,
     def_span: Table<DefIndex, LazyValue<Span>>,
     def_ident_span: Table<DefIndex, LazyValue<Span>>,
     lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
index d5f151f0ed8e50a4116de32d27be14044bf589eb..e7c1abd126e044893aa805a08888281e8a0a2ff4 100644 (file)
@@ -90,6 +90,7 @@ impl FixedSizeEncoding for Option<$ty> {
         ( AnonConst                                )
         ( InlineConst                              )
         ( OpaqueTy                                 )
+        ( ImplTraitPlaceholder                     )
         ( Field                                    )
         ( LifetimeParam                            )
         ( GlobalAsm                                )
index 65d5f755f72482173aafada909ce89241ff9ebaf..9b1fedd0b533c404e0c51802426ea77f930ecddd 100644 (file)
@@ -101,6 +101,8 @@ macro_rules! arena_types {
             [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
 
             [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>,
+
+            [] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap<rustc_hir::def_id::DefId, rustc_middle::ty::Ty<'tcx>>,
         ]);
     )
 }
index 6217bffb8f76c206b4df1840eb12dd9586c7277a..5a65ec9a4765a21865125d834ea371c87cc4f092 100644 (file)
@@ -212,7 +212,13 @@ pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
                 ItemKind::Fn(..) => DefKind::Fn,
                 ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind),
                 ItemKind::Mod(..) => DefKind::Mod,
-                ItemKind::OpaqueTy(..) => DefKind::OpaqueTy,
+                ItemKind::OpaqueTy(ref opaque) => {
+                    if opaque.in_trait {
+                        DefKind::ImplTraitPlaceholder
+                    } else {
+                        DefKind::OpaqueTy
+                    }
+                }
                 ItemKind::TyAlias(..) => DefKind::TyAlias,
                 ItemKind::Enum(..) => DefKind::Enum,
                 ItemKind::Struct(..) => DefKind::Struct,
@@ -1187,7 +1193,13 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
                 ItemKind::ForeignMod { .. } => "foreign mod",
                 ItemKind::GlobalAsm(..) => "global asm",
                 ItemKind::TyAlias(..) => "ty",
-                ItemKind::OpaqueTy(..) => "opaque type",
+                ItemKind::OpaqueTy(ref opaque) => {
+                    if opaque.in_trait {
+                        "opaque type in trait"
+                    } else {
+                        "opaque type"
+                    }
+                }
                 ItemKind::Enum(..) => "enum",
                 ItemKind::Struct(..) => "struct",
                 ItemKind::Union(..) => "union",
index 1e3a6bcfc7d32ef6287ac7a01ee07656dee271cc..4064a8f97334b4f4c683aafb25fbb844f12d9348 100644 (file)
@@ -96,6 +96,7 @@
 pub mod thir;
 pub mod traits;
 pub mod ty;
+mod values;
 
 pub mod util {
     pub mod bug;
index c8e78747d8e7b3a74ac53afb841bef9b9bd047dd..5ff014c7815a9c0ba52aaaffa49d29d0ffdce603 100644 (file)
@@ -2,6 +2,7 @@
 
 use rustc_hir::def::Res;
 use rustc_macros::HashStable;
+use rustc_span::def_id::DefId;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
@@ -18,7 +19,7 @@ pub struct ModChild {
     /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
     pub res: Res<!>,
     /// Visibility of the item.
-    pub vis: ty::Visibility,
+    pub vis: ty::Visibility<DefId>,
     /// Span of the item.
     pub span: Span,
     /// A proper `macro_rules` item (not a reexport).
index c5a450b0e2e5393e6ae2601893cef89e808ae7d8..753e1f4b9daaf72f247ef14fc91debed7ad3e573 100644 (file)
@@ -1362,13 +1362,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
                 write!(fmt, "Coverage::{:?} for {:?}", kind, rgn)
             }
             Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind),
-            CopyNonOverlapping(box crate::mir::CopyNonOverlapping {
-                ref src,
-                ref dst,
-                ref count,
-            }) => {
-                write!(fmt, "copy_nonoverlapping(src={:?}, dst={:?}, count={:?})", src, dst, count)
-            }
+            Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
             Nop => write!(fmt, "nop"),
         }
     }
@@ -1470,7 +1464,9 @@ pub fn is_indirect(&self) -> bool {
     /// It's guaranteed to be in the first place
     pub fn has_deref(&self) -> bool {
         // To make sure this is not accidently used in wrong mir phase
-        debug_assert!(!self.projection[1..].contains(&PlaceElem::Deref));
+        debug_assert!(
+            self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref)
+        );
         self.projection.first() == Some(&PlaceElem::Deref)
     }
 
index 6e64a3b80c1fb18beaff270d864d96235c348890..4e06d91012c0dfc9c0f0eb50d1792357df25a2ef 100644 (file)
@@ -249,7 +249,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
         Retag(..) => "Retag",
         AscribeUserType(..) => "AscribeUserType",
         Coverage(..) => "Coverage",
-        CopyNonOverlapping(..) => "CopyNonOverlapping",
+        Intrinsic(..) => "Intrinsic",
         Nop => "Nop",
     }
 }
index d7b9d59eced51eee813171db11a11635a881378e..1f7643a76afe505a3ab21c71399a36b439a9d837 100644 (file)
@@ -327,6 +327,34 @@ pub enum StatementKind<'tcx> {
     /// executed.
     Coverage(Box<Coverage>),
 
+    /// Denotes a call to an intrinsic that does not require an unwind path and always returns.
+    /// This avoids adding a new block and a terminator for simple intrinsics.
+    Intrinsic(Box<NonDivergingIntrinsic<'tcx>>),
+
+    /// No-op. Useful for deleting instructions without affecting statement indices.
+    Nop,
+}
+
+#[derive(
+    Clone,
+    TyEncodable,
+    TyDecodable,
+    Debug,
+    PartialEq,
+    Hash,
+    HashStable,
+    TypeFoldable,
+    TypeVisitable
+)]
+pub enum NonDivergingIntrinsic<'tcx> {
+    /// Denotes a call to the intrinsic function `assume`.
+    ///
+    /// The operand must be a boolean. Optimizers may use the value of the boolean to backtrack its
+    /// computation to infer information about other variables. So if the boolean came from a
+    /// `x < y` operation, subsequent operations on `x` and `y` could elide various bound checks.
+    /// If the argument is `false`, this operation is equivalent to `TerminatorKind::Unreachable`.
+    Assume(Operand<'tcx>),
+
     /// Denotes a call to the intrinsic function `copy_nonoverlapping`.
     ///
     /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer,
@@ -340,10 +368,18 @@ pub enum StatementKind<'tcx> {
     ///
     /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved?
     /// I vaguely remember Ralf saying somewhere that he thought it should not be.
-    CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>),
+    CopyNonOverlapping(CopyNonOverlapping<'tcx>),
+}
 
-    /// No-op. Useful for deleting instructions without affecting statement indices.
-    Nop,
+impl std::fmt::Display for NonDivergingIntrinsic<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Assume(op) => write!(f, "assume({op:?})"),
+            Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
+                write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})")
+            }
+        }
+    }
 }
 
 /// Describes what kind of retag is to be performed.
@@ -705,7 +741,7 @@ pub enum TerminatorKind<'tcx> {
 }
 
 /// Information about an assertion failure.
-#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)]
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub enum AssertKind<O> {
     BoundsCheck { len: O, index: O },
     Overflow(BinOp, O, O),
@@ -1195,7 +1231,8 @@ pub enum BinOp {
 mod size_asserts {
     use super::*;
     // These are in alphabetical order, which is easy to maintain.
-    static_assert_size!(AggregateKind<'_>, 48);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(AggregateKind<'_>, 40);
     static_assert_size!(Operand<'_>, 24);
     static_assert_size!(Place<'_>, 16);
     static_assert_size!(PlaceElem<'_>, 24);
index 9ccf5aea63ca83c634f4e6969894ef4bb4ea0984..02a9958525b2229ebd8fc3d825a2449ffee2ef10 100644 (file)
@@ -14,7 +14,7 @@
 
 pub use super::query::*;
 
-#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)]
+#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub struct SwitchTargets {
     /// Possible values. The locations to branch to in each case
     /// are found in the corresponding indices from the `targets` vector.
index 7bd65f42e3f925a2b2d799cb681394ba2410a835..708ea4398c852102f8c7c1d3ce12cddf4364ccd3 100644 (file)
@@ -425,14 +425,15 @@ fn super_statement(&mut self,
                             location
                         )
                     }
-                    StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{
-                        src,
-                        dst,
-                        count,
-                    }) => {
-                      self.visit_operand(src, location);
-                      self.visit_operand(dst, location);
-                      self.visit_operand(count, location)
+                    StatementKind::Intrinsic(box ref $($mutability)? intrinsic) => {
+                        match intrinsic {
+                            NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location),
+                            NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
+                                self.visit_operand(src, location);
+                                self.visit_operand(dst, location);
+                                self.visit_operand(count, location);
+                            }
+                        }
                     }
                     StatementKind::Nop => {}
                 }
index 8e7bacca262e10d7da0e6177720f57f7379b4ffd..f72e7389fc606d9b935fd257aff85ff0ee03d384 100644 (file)
         separate_provide_extern
     }
 
+    query compare_predicates_and_trait_impl_trait_tys(key: DefId)
+        -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>
+    {
+        desc { "better description please" }
+        separate_provide_extern
+    }
+
     query analysis(key: ()) -> Result<(), ErrorGuaranteed> {
         eval_always
         desc { "running analysis passes on this crate" }
         }
     }
 
-    query codegen_fulfill_obligation(
+    query codegen_select_candidate(
         key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
     ) -> Result<&'tcx ImplSource<'tcx, ()>, traits::CodegenObligationError> {
         cache_on_disk_if { true }
-        desc { |tcx|
-            "checking if `{}` fulfills its obligations",
-            tcx.def_path_str(key.1.def_id())
-        }
+        desc { |tcx| "computing candidate for `{}`", key.1 }
     }
 
     /// Return all `impl` blocks in the current crate.
         desc { "looking up late bound vars" }
     }
 
-    query visibility(def_id: DefId) -> ty::Visibility {
+    query visibility(def_id: DefId) -> ty::Visibility<DefId> {
         desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
         separate_provide_extern
     }
index 7e543929b0f3ae5bedecfc308368031e62acf9e0..c50f8b0eebe1a03686430d45872cdb63999b20b6 100644 (file)
@@ -825,8 +825,12 @@ mod size_asserts {
     static_assert_size!(Block, 56);
     static_assert_size!(Expr<'_>, 64);
     static_assert_size!(ExprKind<'_>, 40);
-    static_assert_size!(Pat<'_>, 72);
-    static_assert_size!(PatKind<'_>, 56);
-    static_assert_size!(Stmt<'_>, 56);
-    static_assert_size!(StmtKind<'_>, 48);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(Pat<'_>, 64);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(PatKind<'_>, 48);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(Stmt<'_>, 48);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(StmtKind<'_>, 40);
 }
index ab7e5ba3a1067f56cae54bf1e87489231a80114b..755d9f8f696675859c387125c2181a95b95f3921 100644 (file)
@@ -12,7 +12,7 @@
 use crate::infer::canonical::Canonical;
 use crate::ty::abstract_const::NotConstEvaluatable;
 use crate::ty::subst::SubstsRef;
-use crate::ty::{self, AdtKind, Predicate, Ty, TyCtxt};
+use crate::ty::{self, AdtKind, Ty, TyCtxt};
 
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic};
@@ -416,7 +416,7 @@ pub enum ObligationCauseCode<'tcx> {
     BinOp {
         rhs_span: Option<Span>,
         is_lit: bool,
-        output_pred: Option<Predicate<'tcx>>,
+        output_ty: Option<Ty<'tcx>>,
     },
 }
 
@@ -1024,7 +1024,7 @@ pub enum MethodViolationCode {
     UndispatchableReceiver(Option<Span>),
 }
 
-/// These are the error cases for `codegen_fulfill_obligation`.
+/// These are the error cases for `codegen_select_candidate`.
 #[derive(Copy, Clone, Debug, Hash, HashStable, Encodable, Decodable)]
 pub enum CodegenObligationError {
     /// Ambiguity can happen when monomorphizing during trans
index c97156ac17ff6067ed1f5298bf417f5678a895da..55ee5bd2f810d0999641b9e490e27c780cdab700 100644 (file)
@@ -42,7 +42,7 @@ pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
     }
 
     #[inline]
-    pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility {
+    pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId> {
         tcx.visibility(self.def_id)
     }
 
index 3840e79cebd84e8d577b412366a049f552270719..ff20da65c016de18341a4352e1fd8f1e8fc37e5c 100644 (file)
@@ -180,6 +180,7 @@ fn try_eval_inner(
         param_env: ParamEnv<'tcx>,
         eval_mode: EvalMode,
     ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
+        assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
         if let ConstKind::Unevaluated(unevaluated) = self {
             use crate::mir::interpret::ErrorHandled;
 
index 262d59f8ff8a78963c95f2fbe60717215e465ebd..53e91e48c24d013275e5de85b3edd8ffa5fc9414 100644 (file)
@@ -22,6 +22,7 @@
     FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List,
     ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region,
     RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy,
+    Visibility,
 };
 use rustc_ast as ast;
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -1251,7 +1252,7 @@ pub fn create_global_ctxt(
         output_filenames: OutputFilenames,
     ) -> GlobalCtxt<'tcx> {
         let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| {
-            s.fatal(&err);
+            s.emit_fatal(err);
         });
         let interners = CtxtInterners::new(arena);
         let common_types = CommonTypes::new(
@@ -1728,6 +1729,11 @@ pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx {
             .chain(self.crates(()).iter().copied())
             .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied())
     }
+
+    #[inline]
+    pub fn local_visibility(self, def_id: LocalDefId) -> Visibility {
+        self.visibility(def_id.to_def_id()).expect_local()
+    }
 }
 
 /// A trait implemented for all `X<'a>` types that can be safely and
index dd2f43210603abb6c0e13a1fe88bbd7489ed0541..648f5f7161fa6ead00fd41a5d75357a0e56ba909 100644 (file)
@@ -102,13 +102,25 @@ pub fn suggest_arbitrary_trait_bound<'tcx>(
     generics: &hir::Generics<'_>,
     err: &mut Diagnostic,
     trait_pred: PolyTraitPredicate<'tcx>,
+    associated_ty: Option<(&'static str, Ty<'tcx>)>,
 ) -> bool {
     if !trait_pred.is_suggestable(tcx, false) {
         return false;
     }
 
     let param_name = trait_pred.skip_binder().self_ty().to_string();
-    let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
+    let mut constraint = trait_pred.print_modifiers_and_trait_path().to_string();
+
+    if let Some((name, term)) = associated_ty {
+        // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err.
+        // That should be extracted into a helper function.
+        if constraint.ends_with('>') {
+            constraint = format!("{}, {} = {}>", &constraint[..constraint.len() - 1], name, term);
+        } else {
+            constraint.push_str(&format!("<{} = {}>", name, term));
+        }
+    }
+
     let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
 
     // Skip, there is a param named Self
@@ -396,7 +408,7 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
             ) => {
                 self.0.push(ty);
             }
-            hir::TyKind::OpaqueDef(item_id, _) => {
+            hir::TyKind::OpaqueDef(item_id, _, _) => {
                 self.0.push(ty);
                 let item = self.1.item(item_id);
                 hir::intravisit::walk_item(self, item);
index da564c66a70e1519ea72e29c5886d3596bfab84f..279c8c8d6d16db9ff922115c0bbf7cb3bb94084d 100644 (file)
@@ -2,6 +2,7 @@
 use crate::ty::diagnostics::suggest_constraining_type_param;
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
+use hir::def::DefKind;
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{pluralize, Diagnostic, MultiSpan};
 use rustc_hir as hir;
@@ -538,7 +539,7 @@ fn foo(&self, x: T) -> T { x }
                             diag.span_label(p_span, "this type parameter");
                         }
                     }
-                    (ty::Projection(proj_ty), _) => {
+                    (ty::Projection(proj_ty), _) if self.def_kind(proj_ty.item_def_id) != DefKind::ImplTraitPlaceholder => {
                         self.expected_projection(
                             diag,
                             proj_ty,
@@ -547,7 +548,7 @@ fn foo(&self, x: T) -> T { x }
                             cause.code(),
                         );
                     }
-                    (_, ty::Projection(proj_ty)) => {
+                    (_, ty::Projection(proj_ty)) if self.def_kind(proj_ty.item_def_id) != DefKind::ImplTraitPlaceholder => {
                         let msg = format!(
                             "consider constraining the associated type `{}` to `{}`",
                             values.found, values.expected,
index ea6bb8a7abd4b8941a7d57c4dedae0fbb093e8a7..c22c899c5cce17104de0d82db5ea8052be002b3a 100644 (file)
@@ -1,5 +1,5 @@
 use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::{self, InferConst, Term, Ty, TypeFlags};
+use crate::ty::{self, InferConst, Ty, TypeFlags};
 use std::slice;
 
 #[derive(Debug)]
@@ -243,9 +243,9 @@ fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
             }
             ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
                 self.add_projection_ty(projection_ty);
-                match term {
-                    Term::Ty(ty) => self.add_ty(ty),
-                    Term::Const(c) => self.add_const(c),
+                match term.unpack() {
+                    ty::TermKind::Ty(ty) => self.add_ty(ty),
+                    ty::TermKind::Const(c) => self.add_const(c),
                 }
             }
             ty::PredicateKind::WellFormed(arg) => {
@@ -320,9 +320,9 @@ fn add_unevaluated_const<P>(&mut self, ct: ty::Unevaluated<'_, P>) {
 
     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
         self.add_substs(projection.substs);
-        match projection.term {
-            ty::Term::Ty(ty) => self.add_ty(ty),
-            ty::Term::Const(ct) => self.add_const(ct),
+        match projection.term.unpack() {
+            ty::TermKind::Ty(ty) => self.add_ty(ty),
+            ty::TermKind::Const(ct) => self.add_const(ct),
         }
     }
 
index a1d980af921afeb05590a6ae722dc0436146dbb5..0c8bdde9c8bceefcd8a32490da48aaa5f1f1b948 100644 (file)
@@ -27,8 +27,9 @@ pub fn descr(&self) -> &'static str {
     pub fn to_ord(&self) -> ast::ParamKindOrd {
         match self {
             GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime,
-            GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type,
-            GenericParamDefKind::Const { .. } => ast::ParamKindOrd::Const,
+            GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+                ast::ParamKindOrd::TypeOrConst
+            }
         }
     }
 
@@ -328,6 +329,7 @@ pub fn instantiate_own(
         }
     }
 
+    #[instrument(level = "debug", skip(self, tcx))]
     fn instantiate_into(
         &self,
         tcx: TyCtxt<'tcx>,
index 2c587b76f025f49a2a6d0a3b3853cec065ab3b39..abb7ddd88b14db57bdfa0828ba3732cbba1147e7 100644 (file)
@@ -22,7 +22,7 @@
 use rustc_target::abi::*;
 use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
 
-use std::cmp;
+use std::cmp::{self, Ordering};
 use std::fmt;
 use std::iter;
 use std::num::NonZeroUsize;
@@ -1046,131 +1046,191 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'
                 // that allow representation optimization.)
                 assert!(def.is_enum());
 
-                // The current code for niche-filling relies on variant indices
-                // instead of actual discriminants, so dataful enums with
-                // explicit discriminants (RFC #2363) would misbehave.
-                let no_explicit_discriminants = def
-                    .variants()
-                    .iter_enumerated()
-                    .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32()));
-
-                let mut niche_filling_layout = None;
-
-                // Niche-filling enum optimization.
-                if !def.repr().inhibit_enum_layout_opt() && no_explicit_discriminants {
-                    let mut dataful_variant = None;
-                    let mut niche_variants = VariantIdx::MAX..=VariantIdx::new(0);
+                // Until we've decided whether to use the tagged or
+                // niche filling LayoutS, we don't want to intern the
+                // variant layouts, so we can't store them in the
+                // overall LayoutS. Store the overall LayoutS
+                // and the variant LayoutSs here until then.
+                struct TmpLayout<'tcx> {
+                    layout: LayoutS<'tcx>,
+                    variants: IndexVec<VariantIdx, LayoutS<'tcx>>,
+                }
 
-                    // Find one non-ZST variant.
-                    'variants: for (v, fields) in variants.iter_enumerated() {
-                        if absent(fields) {
-                            continue 'variants;
+                let calculate_niche_filling_layout =
+                    || -> Result<Option<TmpLayout<'tcx>>, LayoutError<'tcx>> {
+                        // The current code for niche-filling relies on variant indices
+                        // instead of actual discriminants, so enums with
+                        // explicit discriminants (RFC #2363) would misbehave.
+                        if def.repr().inhibit_enum_layout_opt()
+                            || def
+                                .variants()
+                                .iter_enumerated()
+                                .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()))
+                        {
+                            return Ok(None);
                         }
-                        for f in fields {
-                            if !f.is_zst() {
-                                if dataful_variant.is_none() {
-                                    dataful_variant = Some(v);
-                                    continue 'variants;
-                                } else {
-                                    dataful_variant = None;
-                                    break 'variants;
-                                }
-                            }
+
+                        if variants.len() < 2 {
+                            return Ok(None);
                         }
-                        niche_variants = *niche_variants.start().min(&v)..=v;
-                    }
 
-                    if niche_variants.start() > niche_variants.end() {
-                        dataful_variant = None;
-                    }
+                        let mut align = dl.aggregate_align;
+                        let mut variant_layouts = variants
+                            .iter_enumerated()
+                            .map(|(j, v)| {
+                                let mut st = self.univariant_uninterned(
+                                    ty,
+                                    v,
+                                    &def.repr(),
+                                    StructKind::AlwaysSized,
+                                )?;
+                                st.variants = Variants::Single { index: j };
+
+                                align = align.max(st.align);
+
+                                Ok(st)
+                            })
+                            .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
+
+                        let largest_variant_index = match variant_layouts
+                            .iter_enumerated()
+                            .max_by_key(|(_i, layout)| layout.size.bytes())
+                            .map(|(i, _layout)| i)
+                        {
+                            None => return Ok(None),
+                            Some(i) => i,
+                        };
 
-                    if let Some(i) = dataful_variant {
-                        let count = (niche_variants.end().as_u32()
-                            - niche_variants.start().as_u32()
-                            + 1) as u128;
+                        let all_indices = VariantIdx::new(0)..=VariantIdx::new(variants.len() - 1);
+                        let needs_disc = |index: VariantIdx| {
+                            index != largest_variant_index && !absent(&variants[index])
+                        };
+                        let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap()
+                            ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap();
+
+                        let count = niche_variants.size_hint().1.unwrap() as u128;
 
                         // Find the field with the largest niche
-                        let niche_candidate = variants[i]
+                        let (field_index, niche, (niche_start, niche_scalar)) = match variants
+                            [largest_variant_index]
                             .iter()
                             .enumerate()
                             .filter_map(|(j, field)| Some((j, field.largest_niche?)))
-                            .max_by_key(|(_, niche)| niche.available(dl));
-
-                        if let Some((field_index, niche, (niche_start, niche_scalar))) =
-                            niche_candidate.and_then(|(field_index, niche)| {
-                                Some((field_index, niche, niche.reserve(self, count)?))
-                            })
+                            .max_by_key(|(_, niche)| niche.available(dl))
+                            .and_then(|(j, niche)| Some((j, niche, niche.reserve(self, count)?)))
                         {
-                            let mut align = dl.aggregate_align;
-                            let st = variants
-                                .iter_enumerated()
-                                .map(|(j, v)| {
-                                    let mut st = self.univariant_uninterned(
-                                        ty,
-                                        v,
-                                        &def.repr(),
-                                        StructKind::AlwaysSized,
-                                    )?;
-                                    st.variants = Variants::Single { index: j };
+                            None => return Ok(None),
+                            Some(x) => x,
+                        };
 
-                                    align = align.max(st.align);
+                        let niche_offset = niche.offset
+                            + variant_layouts[largest_variant_index].fields.offset(field_index);
+                        let niche_size = niche.value.size(dl);
+                        let size = variant_layouts[largest_variant_index].size.align_to(align.abi);
 
-                                    Ok(tcx.intern_layout(st))
-                                })
-                                .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
+                        let all_variants_fit =
+                            variant_layouts.iter_enumerated_mut().all(|(i, layout)| {
+                                if i == largest_variant_index {
+                                    return true;
+                                }
 
-                            let offset = st[i].fields().offset(field_index) + niche.offset;
+                                layout.largest_niche = None;
 
-                            // Align the total size to the largest alignment.
-                            let size = st[i].size().align_to(align.abi);
+                                if layout.size <= niche_offset {
+                                    // This variant will fit before the niche.
+                                    return true;
+                                }
 
-                            let abi = if st.iter().all(|v| v.abi().is_uninhabited()) {
-                                Abi::Uninhabited
-                            } else if align == st[i].align() && size == st[i].size() {
-                                // When the total alignment and size match, we can use the
-                                // same ABI as the scalar variant with the reserved niche.
-                                match st[i].abi() {
-                                    Abi::Scalar(_) => Abi::Scalar(niche_scalar),
-                                    Abi::ScalarPair(first, second) => {
-                                        // Only the niche is guaranteed to be initialised,
-                                        // so use union layout for the other primitive.
-                                        if offset.bytes() == 0 {
-                                            Abi::ScalarPair(niche_scalar, second.to_union())
-                                        } else {
-                                            Abi::ScalarPair(first.to_union(), niche_scalar)
+                                // Determine if it'll fit after the niche.
+                                let this_align = layout.align.abi;
+                                let this_offset = (niche_offset + niche_size).align_to(this_align);
+
+                                if this_offset + layout.size > size {
+                                    return false;
+                                }
+
+                                // It'll fit, but we need to make some adjustments.
+                                match layout.fields {
+                                    FieldsShape::Arbitrary { ref mut offsets, .. } => {
+                                        for (j, offset) in offsets.iter_mut().enumerate() {
+                                            if !variants[i][j].is_zst() {
+                                                *offset += this_offset;
+                                            }
                                         }
                                     }
-                                    _ => Abi::Aggregate { sized: true },
+                                    _ => {
+                                        panic!("Layout of fields should be Arbitrary for variants")
+                                    }
                                 }
-                            } else {
-                                Abi::Aggregate { sized: true }
-                            };
 
-                            let largest_niche = Niche::from_scalar(dl, offset, niche_scalar);
-
-                            niche_filling_layout = Some(LayoutS {
-                                variants: Variants::Multiple {
-                                    tag: niche_scalar,
-                                    tag_encoding: TagEncoding::Niche {
-                                        dataful_variant: i,
-                                        niche_variants,
-                                        niche_start,
-                                    },
-                                    tag_field: 0,
-                                    variants: st,
-                                },
-                                fields: FieldsShape::Arbitrary {
-                                    offsets: vec![offset],
-                                    memory_index: vec![0],
-                                },
-                                abi,
-                                largest_niche,
-                                size,
-                                align,
+                                // It can't be a Scalar or ScalarPair because the offset isn't 0.
+                                if !layout.abi.is_uninhabited() {
+                                    layout.abi = Abi::Aggregate { sized: true };
+                                }
+                                layout.size += this_offset;
+
+                                true
                             });
+
+                        if !all_variants_fit {
+                            return Ok(None);
                         }
-                    }
-                }
+
+                        let largest_niche = Niche::from_scalar(dl, niche_offset, niche_scalar);
+
+                        let others_zst = variant_layouts.iter_enumerated().all(|(i, layout)| {
+                            i == largest_variant_index || layout.size == Size::ZERO
+                        });
+                        let same_size = size == variant_layouts[largest_variant_index].size;
+                        let same_align = align == variant_layouts[largest_variant_index].align;
+
+                        let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) {
+                            Abi::Uninhabited
+                        } else if same_size && same_align && others_zst {
+                            match variant_layouts[largest_variant_index].abi {
+                                // When the total alignment and size match, we can use the
+                                // same ABI as the scalar variant with the reserved niche.
+                                Abi::Scalar(_) => Abi::Scalar(niche_scalar),
+                                Abi::ScalarPair(first, second) => {
+                                    // Only the niche is guaranteed to be initialised,
+                                    // so use union layouts for the other primitive.
+                                    if niche_offset == Size::ZERO {
+                                        Abi::ScalarPair(niche_scalar, second.to_union())
+                                    } else {
+                                        Abi::ScalarPair(first.to_union(), niche_scalar)
+                                    }
+                                }
+                                _ => Abi::Aggregate { sized: true },
+                            }
+                        } else {
+                            Abi::Aggregate { sized: true }
+                        };
+
+                        let layout = LayoutS {
+                            variants: Variants::Multiple {
+                                tag: niche_scalar,
+                                tag_encoding: TagEncoding::Niche {
+                                    untagged_variant: largest_variant_index,
+                                    niche_variants,
+                                    niche_start,
+                                },
+                                tag_field: 0,
+                                variants: IndexVec::new(),
+                            },
+                            fields: FieldsShape::Arbitrary {
+                                offsets: vec![niche_offset],
+                                memory_index: vec![0],
+                            },
+                            abi,
+                            largest_niche,
+                            size,
+                            align,
+                        };
+
+                        Ok(Some(TmpLayout { layout, variants: variant_layouts }))
+                    };
+
+                let niche_filling_layout = calculate_niche_filling_layout()?;
 
                 let (mut min, mut max) = (i128::MAX, i128::MIN);
                 let discr_type = def.repr().discr_type();
@@ -1425,15 +1485,12 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'
 
                 let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
 
-                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,
                         tag_field: 0,
-                        variants: layout_variants,
+                        variants: IndexVec::new(),
                     },
                     fields: FieldsShape::Arbitrary {
                         offsets: vec![Size::ZERO],
@@ -1445,20 +1502,45 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'
                     size,
                 };
 
-                let best_layout = match (tagged_layout, niche_filling_layout) {
-                    (tagged_layout, Some(niche_filling_layout)) => {
+                let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants };
+
+                let mut best_layout = match (tagged_layout, niche_filling_layout) {
+                    (tl, Some(nl)) => {
                         // Pick the smaller layout; otherwise,
                         // pick the layout with the larger niche; otherwise,
                         // pick tagged as it has simpler codegen.
-                        cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| {
-                            let niche_size = layout.largest_niche.map_or(0, |n| n.available(dl));
-                            (layout.size, cmp::Reverse(niche_size))
-                        })
+                        use Ordering::*;
+                        let niche_size = |tmp_l: &TmpLayout<'_>| {
+                            tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl))
+                        };
+                        match (
+                            tl.layout.size.cmp(&nl.layout.size),
+                            niche_size(&tl).cmp(&niche_size(&nl)),
+                        ) {
+                            (Greater, _) => nl,
+                            (Equal, Less) => nl,
+                            _ => tl,
+                        }
                     }
-                    (tagged_layout, None) => tagged_layout,
+                    (tl, None) => tl,
+                };
+
+                // Now we can intern the variant layouts and store them in the enum layout.
+                best_layout.layout.variants = match best_layout.layout.variants {
+                    Variants::Multiple { tag, tag_encoding, tag_field, .. } => Variants::Multiple {
+                        tag,
+                        tag_encoding,
+                        tag_field,
+                        variants: best_layout
+                            .variants
+                            .into_iter()
+                            .map(|layout| tcx.intern_layout(layout))
+                            .collect(),
+                    },
+                    _ => bug!(),
                 };
 
-                tcx.intern_layout(best_layout)
+                tcx.intern_layout(best_layout.layout)
             }
 
             // Types with no meaningful known layout.
@@ -2559,11 +2641,11 @@ fn ty_and_layout_pointee_info_at(
                     // using more niches than just null (e.g., the first page of
                     // the address space, or unaligned pointers).
                     Variants::Multiple {
-                        tag_encoding: TagEncoding::Niche { dataful_variant, .. },
+                        tag_encoding: TagEncoding::Niche { untagged_variant, .. },
                         tag_field,
                         ..
                     } if this.fields.offset(tag_field) == offset => {
-                        Some(this.for_variant(cx, dataful_variant))
+                        Some(this.for_variant(cx, untagged_variant))
                     }
                     _ => Some(this),
                 };
index a3f7880b9a5684f3a044ea44218be79ec3aec958..df72260597f9f5a5c63309a6a7268444098071b2 100644 (file)
@@ -41,6 +41,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
+use rustc_serialize::{Decodable, Encodable};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{ExpnId, Span};
@@ -50,6 +51,9 @@
 
 use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
+use std::mem;
+use std::num::NonZeroUsize;
 use std::ops::ControlFlow;
 use std::{fmt, str};
 
@@ -259,11 +263,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)]
-pub enum Visibility {
+pub enum Visibility<Id = LocalDefId> {
     /// Visible everywhere (including in other crates).
     Public,
     /// Visible only in the given crate-local module.
-    Restricted(DefId),
+    Restricted(Id),
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
@@ -354,28 +358,45 @@ fn opt_parent(self, id: DefId) -> Option<DefId> {
     }
 }
 
-impl Visibility {
-    /// Returns `true` if an item with this visibility is accessible from the given block.
-    pub fn is_accessible_from<T: DefIdTree>(self, module: DefId, tree: T) -> bool {
-        let restriction = match self {
-            // Public items are visible everywhere.
-            Visibility::Public => return true,
-            // Restricted items are visible in an arbitrary local module.
-            Visibility::Restricted(other) if other.krate != module.krate => return false,
-            Visibility::Restricted(module) => module,
-        };
+impl<Id> Visibility<Id> {
+    pub fn is_public(self) -> bool {
+        matches!(self, Visibility::Public)
+    }
 
-        tree.is_descendant_of(module, restriction)
+    pub fn map_id<OutId>(self, f: impl FnOnce(Id) -> OutId) -> Visibility<OutId> {
+        match self {
+            Visibility::Public => Visibility::Public,
+            Visibility::Restricted(id) => Visibility::Restricted(f(id)),
+        }
+    }
+}
+
+impl<Id: Into<DefId>> Visibility<Id> {
+    pub fn to_def_id(self) -> Visibility<DefId> {
+        self.map_id(Into::into)
+    }
+
+    /// Returns `true` if an item with this visibility is accessible from the given module.
+    pub fn is_accessible_from(self, module: impl Into<DefId>, tree: impl DefIdTree) -> bool {
+        match self {
+            // Public items are visible everywhere.
+            Visibility::Public => true,
+            Visibility::Restricted(id) => tree.is_descendant_of(module.into(), id.into()),
+        }
     }
 
     /// Returns `true` if this visibility is at least as accessible as the given visibility
-    pub fn is_at_least<T: DefIdTree>(self, vis: Visibility, tree: T) -> bool {
-        let vis_restriction = match vis {
-            Visibility::Public => return self == Visibility::Public,
-            Visibility::Restricted(module) => module,
-        };
+    pub fn is_at_least(self, vis: Visibility<impl Into<DefId>>, tree: impl DefIdTree) -> bool {
+        match vis {
+            Visibility::Public => self.is_public(),
+            Visibility::Restricted(id) => self.is_accessible_from(id, tree),
+        }
+    }
+}
 
-        self.is_accessible_from(vis_restriction, tree)
+impl Visibility<DefId> {
+    pub fn expect_local(self) -> Visibility {
+        self.map_id(|id| id.expect_local())
     }
 
     // Returns `true` if this item is visible anywhere in the local crate.
@@ -385,10 +406,6 @@ pub fn is_visible_locally(self) -> bool {
             Visibility::Restricted(def_id) => def_id.is_local(),
         }
     }
-
-    pub fn is_public(self) -> bool {
-        matches!(self, Visibility::Public)
-    }
 }
 
 /// The crate variances map is computed during typeck and contains the
@@ -459,15 +476,6 @@ pub(crate) struct TyS<'tcx> {
     outer_exclusive_binder: ty::DebruijnIndex,
 }
 
-// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(TyS<'_>, 40);
-
-// We are actually storing a stable hash cache next to the type, so let's
-// also check the full size
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(WithStableHash<TyS<'_>>, 56);
-
 /// Use this rather than `TyS`, whenever possible.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
 #[rustc_diagnostic_item = "Ty"]
@@ -524,10 +532,6 @@ pub(crate) struct PredicateS<'tcx> {
     outer_exclusive_binder: ty::DebruijnIndex,
 }
 
-// This type is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(PredicateS<'_>, 56);
-
 /// Use this rather than `PredicateS`, whenever possible.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 #[rustc_pass_by_value]
@@ -911,42 +915,135 @@ pub struct CoercePredicate<'tcx> {
 }
 pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
-pub enum Term<'tcx> {
-    Ty(Ty<'tcx>),
-    Const(Const<'tcx>),
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Term<'tcx> {
+    ptr: NonZeroUsize,
+    marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>,
+}
+
+impl Debug for Term<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let data = if let Some(ty) = self.ty() {
+            format!("Term::Ty({:?})", ty)
+        } else if let Some(ct) = self.ct() {
+            format!("Term::Ct({:?})", ct)
+        } else {
+            unreachable!()
+        };
+        f.write_str(&data)
+    }
 }
 
 impl<'tcx> From<Ty<'tcx>> for Term<'tcx> {
     fn from(ty: Ty<'tcx>) -> Self {
-        Term::Ty(ty)
+        TermKind::Ty(ty).pack()
     }
 }
 
 impl<'tcx> From<Const<'tcx>> for Term<'tcx> {
     fn from(c: Const<'tcx>) -> Self {
-        Term::Const(c)
+        TermKind::Const(c).pack()
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Term<'tcx> {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        self.unpack().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Term<'tcx> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(self.unpack().try_fold_with(folder)?.pack())
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Term<'tcx> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.unpack().visit_with(visitor)
+    }
+}
+
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for Term<'tcx> {
+    fn encode(&self, e: &mut E) {
+        self.unpack().encode(e)
+    }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Term<'tcx> {
+    fn decode(d: &mut D) -> Self {
+        let res: TermKind<'tcx> = Decodable::decode(d);
+        res.pack()
     }
 }
 
 impl<'tcx> Term<'tcx> {
+    #[inline]
+    pub fn unpack(self) -> TermKind<'tcx> {
+        let ptr = self.ptr.get();
+        // SAFETY: use of `Interned::new_unchecked` here is ok because these
+        // pointers were originally created from `Interned` types in `pack()`,
+        // and this is just going in the other direction.
+        unsafe {
+            match ptr & TAG_MASK {
+                TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked(
+                    &*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>),
+                ))),
+                CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
+                    &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
+                ))),
+                _ => core::intrinsics::unreachable(),
+            }
+        }
+    }
+
     pub fn ty(&self) -> Option<Ty<'tcx>> {
-        if let Term::Ty(ty) = self { Some(*ty) } else { None }
+        if let TermKind::Ty(ty) = self.unpack() { Some(ty) } else { None }
     }
 
     pub fn ct(&self) -> Option<Const<'tcx>> {
-        if let Term::Const(c) = self { Some(*c) } else { None }
+        if let TermKind::Const(c) = self.unpack() { Some(c) } else { None }
     }
 
     pub fn into_arg(self) -> GenericArg<'tcx> {
-        match self {
-            Term::Ty(ty) => ty.into(),
-            Term::Const(c) => c.into(),
+        match self.unpack() {
+            TermKind::Ty(ty) => ty.into(),
+            TermKind::Const(c) => c.into(),
         }
     }
 }
 
+const TAG_MASK: usize = 0b11;
+const TYPE_TAG: usize = 0b00;
+const CONST_TAG: usize = 0b01;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+pub enum TermKind<'tcx> {
+    Ty(Ty<'tcx>),
+    Const(Const<'tcx>),
+}
+
+impl<'tcx> TermKind<'tcx> {
+    #[inline]
+    fn pack(self) -> Term<'tcx> {
+        let (tag, ptr) = match self {
+            TermKind::Ty(ty) => {
+                // Ensure we can use the tag bits.
+                assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
+                (TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize)
+            }
+            TermKind::Const(ct) => {
+                // Ensure we can use the tag bits.
+                assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
+                (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize)
+            }
+        };
+
+        Term { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData }
+    }
+}
+
 /// This kind of predicate has no *direct* correspondent in the
 /// syntax, but it roughly corresponds to the syntactic forms:
 ///
@@ -1790,7 +1887,7 @@ pub enum VariantDiscr {
 pub struct FieldDef {
     pub did: DefId,
     pub name: Symbol,
-    pub vis: Visibility,
+    pub vis: Visibility<DefId>,
 }
 
 impl PartialEq for FieldDef {
@@ -2387,6 +2484,14 @@ pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
     pub fn is_const_default_method(self, def_id: DefId) -> bool {
         matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait))
     }
+
+    pub fn impl_trait_in_trait_parent(self, mut def_id: DefId) -> DefId {
+        while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn {
+            debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder);
+            def_id = self.parent(def_id);
+        }
+        def_id
+    }
 }
 
 /// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition.
@@ -2531,3 +2636,14 @@ pub struct DestructuredConst<'tcx> {
     pub variant: Option<VariantIdx>,
     pub fields: &'tcx [ty::Const<'tcx>],
 }
+
+// Some types are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    use rustc_data_structures::static_assert_size;
+    // These are in alphabetical order, which is easy to maintain.
+    static_assert_size!(PredicateS<'_>, 48);
+    static_assert_size!(TyS<'_>, 40);
+    static_assert_size!(WithStableHash<TyS<'_>>, 56);
+}
index ca24c0d1ce386fc5801be18526395b68e3589677..9c8dc30e2db3fa0c55723b19576a2feaf74c32f2 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, DefIndex};
 use rustc_index::vec::{Idx, IndexVec};
 
 use crate::middle::exported_symbols::ExportedSymbol;
@@ -60,7 +60,7 @@ impl $crate::ty::ParameterizedOverTcx for $ty {
     ty::ImplPolarity,
     ty::ReprOptions,
     ty::TraitDef,
-    ty::Visibility,
+    ty::Visibility<DefIndex>,
     ty::adjustment::CoerceUnsizedInfo,
     ty::fast_reject::SimplifiedTypeGen<DefId>,
     rustc_ast::Attribute,
index 329478f27b73c80ec2846f4b7e2e6a89a986b41d..5166372878fe958c3e7aa94bb2a8136e7ab48b10 100644 (file)
@@ -1,7 +1,7 @@
 use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
 use crate::ty::{
-    self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable,
+    self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable,
     TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
 };
 use rustc_apfloat::ieee::{Double, Single};
@@ -632,7 +632,13 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
             ty::Foreign(def_id) => {
                 p!(print_def_path(def_id, &[]));
             }
-            ty::Projection(ref data) => p!(print(data)),
+            ty::Projection(ref data) => {
+                if self.tcx().def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder {
+                    return self.pretty_print_opaque_impl_type(data.item_def_id, data.substs);
+                } else {
+                    p!(print(data))
+                }
+            }
             ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
             ty::Opaque(def_id, substs) => {
                 // FIXME(eddyb) print this with `print_def_path`.
@@ -855,7 +861,7 @@ fn pretty_print_opaque_impl_type(
                         }
 
                         p!(")");
-                        if let Term::Ty(ty) = return_ty.skip_binder() {
+                        if let Some(ty) = return_ty.skip_binder().ty() {
                             if !ty.is_unit() {
                                 p!(" -> ", print(return_ty));
                             }
@@ -916,12 +922,14 @@ fn pretty_print_opaque_impl_type(
                         // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks,
                         // unless we can find out what generator return type it comes from.
                         let term = if let Some(ty) = term.skip_binder().ty()
-                            && let ty::Projection(ty::ProjectionTy { item_def_id, substs }) = ty.kind()
-                            && Some(*item_def_id) == tcx.lang_items().generator_return()
+                            && let ty::Projection(proj) = ty.kind()
+                            && let assoc = tcx.associated_item(proj.item_def_id)
+                            && assoc.trait_container(tcx) == tcx.lang_items().gen_trait()
+                            && assoc.name == rustc_span::sym::Return
                         {
                             if let ty::Generator(_, substs, _) = substs.type_at(0).kind() {
                                 let return_ty = substs.as_generator().return_ty();
-                                if !return_ty.is_ty_infer() {
+                                if !return_ty.is_ty_var() {
                                     return_ty.into()
                                 } else {
                                     continue;
@@ -942,13 +950,9 @@ fn pretty_print_opaque_impl_type(
 
                         p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name));
 
-                        match term {
-                            Term::Ty(ty) => {
-                                p!(print(ty))
-                            }
-                            Term::Const(c) => {
-                                p!(print(c));
-                            }
+                        match term.unpack() {
+                            TermKind::Ty(ty) => p!(print(ty)),
+                            TermKind::Const(c) => p!(print(c)),
                         };
                     }
 
@@ -2608,9 +2612,9 @@ pub struct PrintClosureAsImpl<'tcx> {
     }
 
     ty::Term<'tcx> {
-      match self {
-        ty::Term::Ty(ty) => p!(print(ty)),
-        ty::Term::Const(c) => p!(print(c)),
+      match self.unpack() {
+        ty::TermKind::Ty(ty) => p!(print(ty)),
+        ty::TermKind::Const(c) => p!(print(c)),
       }
     }
 
index 818affa7113a17c5abb644ad7ab36db2692b1854..81476195d29958009beeb9f8b0512d8ada8ae0ab 100644 (file)
@@ -6,7 +6,7 @@
 
 use crate::ty::error::{ExpectedFound, TypeError};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
-use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as ast;
 use rustc_hir::def_id::DefId;
 use rustc_span::DUMMY_SP;
@@ -594,10 +594,6 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
         );
     }
 
-    let eagerly_eval = |x: ty::Const<'tcx>| x.eval(tcx, relation.param_env());
-    let a = eagerly_eval(a);
-    let b = eagerly_eval(b);
-
     // Currently, the values that can be unified are primitive types,
     // and those that derive both `PartialEq` and `Eq`, corresponding
     // to structural-match types.
@@ -803,15 +799,15 @@ fn relate<R: TypeRelation<'tcx>>(
     }
 }
 
-impl<'tcx> Relate<'tcx> for ty::Term<'tcx> {
+impl<'tcx> Relate<'tcx> for Term<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
         a: Self,
         b: Self,
     ) -> RelateResult<'tcx, Self> {
-        Ok(match (a, b) {
-            (Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(),
-            (Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(),
+        Ok(match (a.unpack(), b.unpack()) {
+            (TermKind::Ty(a), TermKind::Ty(b)) => relation.relate(a, b)?.into(),
+            (TermKind::Const(a), TermKind::Const(b)) => relation.relate(a, b)?.into(),
             _ => return Err(TypeError::Mismatch),
         })
     }
index 57555433f55b745b54247219bbd1846116c16463..e6bd2eed565a15d96c34306b60b0556f0990b4fe 100644 (file)
@@ -7,7 +7,7 @@
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt};
+use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
 use rustc_data_structures::functor::IdFunctor;
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
@@ -344,10 +344,13 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
 impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
     type Lifted = ty::Term<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        Some(match self {
-            Term::Ty(ty) => Term::Ty(tcx.lift(ty)?),
-            Term::Const(c) => Term::Const(tcx.lift(c)?),
-        })
+        Some(
+            match self.unpack() {
+                TermKind::Ty(ty) => TermKind::Ty(tcx.lift(ty)?),
+                TermKind::Const(c) => TermKind::Const(tcx.lift(c)?),
+            }
+            .pack(),
+        )
     }
 }
 
index 9fb91b5fe8700032585acf97aaf3b88d4a38c116..c5c5d3473418c3f9c5397d540feb844a88615a1c 100644 (file)
@@ -11,6 +11,7 @@
     TypeVisitor,
 };
 use crate::ty::{List, ParamEnv};
+use hir::def::DefKind;
 use polonius_engine::Atom;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::intern::Interned;
@@ -1196,7 +1197,9 @@ pub struct ProjectionTy<'tcx> {
 
 impl<'tcx> ProjectionTy<'tcx> {
     pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
-        tcx.parent(self.item_def_id)
+        let parent = tcx.parent(self.item_def_id);
+        assert_eq!(tcx.def_kind(parent), DefKind::Trait);
+        parent
     }
 
     /// Extracts the underlying trait reference and own substs from this projection.
index a3837512bce2652c1155ca2672e06bcb1cd07bdb..0c73ae54bc31af83084703c146ea490d889b2a75 100644 (file)
@@ -651,6 +651,13 @@ pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
         ty::EarlyBinder(self.type_of(def_id))
     }
 
+    pub fn bound_trait_impl_trait_tys(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>> {
+        ty::EarlyBinder(self.compare_predicates_and_trait_impl_trait_tys(def_id))
+    }
+
     pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
         ty::EarlyBinder(self.fn_sig(def_id))
     }
index 5e042c3acfce25897621b4b4215df93554a266ed..5f8cb578202103e26f38aca5f58639f022af4913 100644 (file)
@@ -666,7 +666,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         // ignore the inputs to a projection, as they may not appear
         // in the normalized form
         if self.just_constrained {
-            if let ty::Projection(..) = t.kind() {
+            if let ty::Projection(..) | ty::Opaque(..) = t.kind() {
                 return ControlFlow::CONTINUE;
             }
         }
index 02fe1f3a7bded3f801ff8a02caced7c5a7c23e76..831724bc4b09bec92079c2d999ac5e648da5570f 100644 (file)
@@ -165,9 +165,9 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
                         }
                     };
 
-                    substs.iter().rev().chain(opt_ty.map(|term| match term {
-                        ty::Term::Ty(ty) => ty.into(),
-                        ty::Term::Const(ct) => ct.into(),
+                    substs.iter().rev().chain(opt_ty.map(|term| match term.unpack() {
+                        ty::TermKind::Ty(ty) => ty.into(),
+                        ty::TermKind::Const(ct) => ct.into(),
                     }))
                 }));
             }
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
new file mode 100644 (file)
index 0000000..7fbe9ae
--- /dev/null
@@ -0,0 +1,54 @@
+use rustc_middle::ty::{self, AdtSizedConstraint, Ty, TyCtxt};
+use rustc_query_system::Value;
+
+impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
+        // SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
+        // FIXME: Represent the above fact in the trait system somehow.
+        unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error()) }
+    }
+}
+
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
+        // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
+        // FIXME: Represent the above fact in the trait system somehow.
+        unsafe {
+            std::mem::transmute::<ty::SymbolName<'tcx>, ty::SymbolName<'_>>(ty::SymbolName::new(
+                tcx, "<error>",
+            ))
+        }
+    }
+}
+
+impl<'tcx> Value<TyCtxt<'tcx>> for AdtSizedConstraint<'_> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
+        // SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`.
+        // FIXME: Represent the above fact in the trait system somehow.
+        unsafe {
+            std::mem::transmute::<AdtSizedConstraint<'tcx>, AdtSizedConstraint<'_>>(
+                AdtSizedConstraint(tcx.intern_type_list(&[tcx.ty_error()])),
+            )
+        }
+    }
+}
+
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
+        let err = tcx.ty_error();
+        // FIXME(compiler-errors): It would be nice if we could get the
+        // query key, so we could at least generate a fn signature that
+        // has the right arity.
+        let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig(
+            [].into_iter(),
+            err,
+            false,
+            rustc_hir::Unsafety::Normal,
+            rustc_target::spec::abi::Abi::Rust,
+        ));
+
+        // SAFETY: This is never called when `Self` is not `ty::Binder<'tcx, ty::FnSig<'tcx>>`.
+        // FIXME: Represent the above fact in the trait system somehow.
+        unsafe { std::mem::transmute::<ty::PolyFnSig<'tcx>, ty::Binder<'_, ty::FnSig<'_>>>(fn_sig) }
+    }
+}
index 763038c52d7fab8d54a003b1e94cc5fda9d47605..7f992c18a18e4ce7bd3f87cb1090e13d0bc8f0a1 100644 (file)
@@ -1036,7 +1036,7 @@ fn args_and_body(
                             VarBindingForm {
                                 binding_mode,
                                 opt_ty_info,
-                                opt_match_place: Some((Some(place), span)),
+                                opt_match_place: Some((None, span)),
                                 pat_span: span,
                             },
                         )))))
index d2f93b679acc596a89525e118f23a06dfcc385eb..4968032b416b0ce1fdc4785b59d61e3319dff357 100644 (file)
@@ -202,6 +202,7 @@ fn normalize_range_pattern_ends(
 
     fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
         let mut ty = self.typeck_results.node_type(pat.hir_id);
+        let mut span = pat.span;
 
         let kind = match pat.kind {
             hir::PatKind::Wild => PatKind::Wild,
@@ -262,6 +263,10 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
             }
 
             hir::PatKind::Binding(_, id, ident, ref sub) => {
+                if let Some(ident_span) = ident.span.find_ancestor_inside(span) {
+                    span = span.with_hi(ident_span.hi());
+                }
+
                 let bm = *self
                     .typeck_results
                     .pat_binding_modes()
@@ -326,14 +331,14 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
             hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) },
         };
 
-        Box::new(Pat { span: pat.span, ty, kind })
+        Box::new(Pat { span, ty, kind })
     }
 
     fn lower_tuple_subpats(
         &mut self,
         pats: &'tcx [hir::Pat<'tcx>],
         expected_len: usize,
-        gap_pos: Option<usize>,
+        gap_pos: hir::DotDotPos,
     ) -> Vec<FieldPat<'tcx>> {
         pats.iter()
             .enumerate_and_adjust(expected_len, gap_pos)
index 483c1e274aa7809d6b3cffeb5ab5be003072d642..3e08a8799ef9aadacd88614c862367ee9c3d34c8 100644 (file)
@@ -270,7 +270,7 @@ fn apply_statement_effect(
             | StatementKind::Retag(..)
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => None,
         };
         if let Some(destination) = destination {
index f6b5af90a85c8e6e97300a7b5d35633397711b75..18760b6c6fa543328b69ec269cc9c3c4a265afd2 100644 (file)
@@ -142,7 +142,7 @@ fn before_statement_effect(
             | StatementKind::FakeRead(..)
             | StatementKind::Nop
             | StatementKind::Retag(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::StorageLive(..) => {}
         }
     }
index c325838622399e7c32d16b2e9ca1fe49df42068c..f46fd118bde5d165106bfcb047dd7d2d5f494232 100644 (file)
@@ -330,7 +330,7 @@ fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
             StatementKind::Retag { .. }
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {}
         }
     }
index 0f5fd77f7ab164368e67dda28392af2c125ebc6a..beff19a3ab2e1d908f8a09a4848c8ddeb5065c33 100644 (file)
@@ -105,7 +105,8 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 // safe (at least as emitted during MIR construction)
             }
 
-            StatementKind::CopyNonOverlapping(..) => unreachable!(),
+            // Move to above list once mir construction uses it.
+            StatementKind::Intrinsic(..) => unreachable!(),
         }
         self.super_statement(statement, location);
     }
index 423e78317aadbc1f21639b2a6ea0f7af77f6b28b..9f842c929dc2478034f6962b05a8c4b63ac05419 100644 (file)
@@ -825,7 +825,7 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
 
         // Retain spans from all other statements
         StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
-        | StatementKind::CopyNonOverlapping(..)
+        | StatementKind::Intrinsic(..)
         | StatementKind::Assign(_)
         | StatementKind::SetDiscriminant { .. }
         | StatementKind::Deinit(..)
index 9163672f570396113e372faf60addc21b5e3278d..3f3870cc7bad2f0d0a866518a7cab212bc195586 100644 (file)
@@ -52,7 +52,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
                 | StatementKind::StorageLive(_)
                 | StatementKind::StorageDead(_)
                 | StatementKind::Coverage(_)
-                | StatementKind::CopyNonOverlapping(_)
+                | StatementKind::Intrinsic(_)
                 | StatementKind::Nop => (),
 
                 StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
index da55510920e12ec6eaf3de10dd0bbfebcd2170b3..9bc47613e4c67885075bc43cf62725b3428644b7 100644 (file)
@@ -537,7 +537,7 @@ fn record_statement_conflicts(&mut self, stmt: &Statement<'_>) {
             | StatementKind::FakeRead(..)
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {}
         }
     }
index dbff4a6bd696e01df9595a630fd99fe625efa71b..705cf776fb29ef6be0c283d4beeaafe20042430d 100644 (file)
@@ -1452,7 +1452,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             | StatementKind::Retag(..)
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {}
         }
     }
index b7ba616510c28874b2356f294ba7155b6a7f8bb7..9892580e63dcb4f1655ce08c463e1e47d32c79b3 100644 (file)
@@ -46,12 +46,31 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                         let mut args = args.drain(..);
                         block.statements.push(Statement {
                             source_info: terminator.source_info,
-                            kind: StatementKind::CopyNonOverlapping(Box::new(
-                                rustc_middle::mir::CopyNonOverlapping {
-                                    src: args.next().unwrap(),
-                                    dst: args.next().unwrap(),
-                                    count: args.next().unwrap(),
-                                },
+                            kind: StatementKind::Intrinsic(Box::new(
+                                NonDivergingIntrinsic::CopyNonOverlapping(
+                                    rustc_middle::mir::CopyNonOverlapping {
+                                        src: args.next().unwrap(),
+                                        dst: args.next().unwrap(),
+                                        count: args.next().unwrap(),
+                                    },
+                                ),
+                            )),
+                        });
+                        assert_eq!(
+                            args.next(),
+                            None,
+                            "Extra argument for copy_non_overlapping intrinsic"
+                        );
+                        drop(args);
+                        terminator.kind = TerminatorKind::Goto { target };
+                    }
+                    sym::assume => {
+                        let target = target.unwrap();
+                        let mut args = args.drain(..);
+                        block.statements.push(Statement {
+                            source_info: terminator.source_info,
+                            kind: StatementKind::Intrinsic(Box::new(
+                                NonDivergingIntrinsic::Assume(args.next().unwrap()),
                             )),
                         });
                         assert_eq!(
index 67ea5cfdb3c006a038bd9fffc4ae1d2842ef1f87..67dae71468f9079ba0be9df85bc8f6940a9be5f4 100644 (file)
@@ -103,7 +103,7 @@ fn run_passes_inner<'tcx>(
         let name = pass.name();
 
         // Gather information about what we should be doing for this pass
-        let overriden =
+        let overridden =
             overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| {
                 trace!(
                     pass = %name,
@@ -112,7 +112,7 @@ fn run_passes_inner<'tcx>(
                 );
                 *polarity
             });
-        let is_enabled = overriden.unwrap_or_else(|| pass.is_enabled(&tcx.sess));
+        let is_enabled = overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess));
         let new_phase = pass.phase_change();
         let dump_enabled = (is_enabled && pass.is_mir_dump_enabled()) || new_phase.is_some();
         let validate = (validate && is_enabled)
index 41a0bfac41aed2151cf9771f906fc693d25e4951..f1bbf2ea7e8ea3aaf7b40307ba110dcd7346b4a3 100644 (file)
@@ -51,7 +51,7 @@ fn is_nop_landing_pad(
                 StatementKind::Assign { .. }
                 | StatementKind::SetDiscriminant { .. }
                 | StatementKind::Deinit(..)
-                | StatementKind::CopyNonOverlapping(..)
+                | StatementKind::Intrinsic(..)
                 | StatementKind::Retag { .. } => {
                     return false;
                 }
index 190f9c1ac158c39bea8b48beb819ad5f0595e4e9..2f116aaa95849bd075b94179109e2bc1a210d1d9 100644 (file)
@@ -249,7 +249,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
             | StatementKind::AscribeUserType(_, _)
             | StatementKind::Coverage(_)
             | StatementKind::StorageDead(_)
-            | StatementKind::CopyNonOverlapping(_)
+            | StatementKind::Intrinsic(_)
             | StatementKind::Nop => {}
         }
     }
@@ -317,7 +317,7 @@ fn find_determining_place<'tcx>(
             | StatementKind::Retag(_, _)
             | StatementKind::AscribeUserType(_, _)
             | StatementKind::Coverage(_)
-            | StatementKind::CopyNonOverlapping(_)
+            | StatementKind::Intrinsic(_)
             | StatementKind::Nop => {}
 
             // If the discriminant is set, it is always set
index bed48db959a53a2e7b9e289c975c6bb41cfcc434..57d372fda5697f508c9a799d06f8cac051f18af9 100644 (file)
@@ -499,7 +499,7 @@ fn visit_lhs(&mut self, place: &Place<'_>, location: Location) {
 impl<'tcx> Visitor<'tcx> for UsedLocals {
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         match statement.kind {
-            StatementKind::CopyNonOverlapping(..)
+            StatementKind::Intrinsic(..)
             | StatementKind::Retag(..)
             | StatementKind::Coverage(..)
             | StatementKind::FakeRead(..)
index d64de44705bb2eaf7ea037a87af7516da3fac17c..3afff7bcabf7de1cbfe2fc8dc48810290c7c41f4 100644 (file)
@@ -35,7 +35,7 @@ fn custom_coerce_unsize_info<'tcx>(
         substs: tcx.mk_substs_trait(source_ty, &[target_ty.into()]),
     });
 
-    match tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref)) {
+    match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) {
         Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData {
             impl_def_id,
             ..
index af4b35db3bace8bbaefb9b7808e01bd05aaf75ed..98156a94ec4b4c1f11dc6c146a8d439f4dbb55a2 100644 (file)
@@ -170,6 +170,7 @@ fn mark_used_by_default_parameters<'tcx>(
         | DefKind::AnonConst
         | DefKind::InlineConst
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::Field
         | DefKind::LifetimeParam
         | DefKind::GlobalAsm
index ad49227222b2c1772de880e45f7de602503749c6..be524db785bc0bfd84d87371d28ab1e7625879a3 100644 (file)
@@ -713,6 +713,14 @@ pub(crate) struct RemoveLet {
     pub span: Span,
 }
 
+#[derive(SessionDiagnostic)]
+#[diag(parser::use_eq_instead)]
+pub(crate) struct UseEqInstead {
+    #[primary_span]
+    #[suggestion_short(applicability = "machine-applicable", code = "=")]
+    pub span: Span,
+}
+
 // SnapshotParser is used to create a snapshot of the parser
 // without causing duplicate errors being emitted when the `Parser`
 // is dropped.
@@ -957,6 +965,14 @@ fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
             }
         }
 
+        if self.token.kind == TokenKind::EqEq
+            && self.prev_token.is_ident()
+            && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq)))
+        {
+            // Likely typo: `=` → `==` in let expr or enum item
+            return Err(self.sess.create_err(UseEqInstead { span: self.token.span }));
+        }
+
         let expect = tokens_to_string(&expected);
         let actual = super::token_descr(&self.token);
         let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
index 7addf519872f03f82332881aad134a28edd4bb11..ed37ede65d514bf992c4e3fe9bb9a7b33054db58 100644 (file)
@@ -1977,6 +1977,9 @@ fn suggest_missing_semicolon_before_array(
         open_delim_span: Span,
     ) -> PResult<'a, ()> {
         if self.token.kind == token::Comma {
+            if !self.sess.source_map().is_multiline(prev_span.until(self.token.span)) {
+                return Ok(());
+            }
             let mut snapshot = self.create_snapshot_for_diagnostic();
             snapshot.bump();
             match snapshot.parse_seq_to_before_end(
index a63af4159e8cbd075bae75ff2f6a6be653bc0663..bb684e784c58a65d854c37fea989baa6b55799c6 100644 (file)
@@ -661,6 +661,7 @@ fn check_doc_alias_value(
             | Target::GlobalAsm
             | Target::TyAlias
             | Target::OpaqueTy
+            | Target::ImplTraitPlaceholder
             | Target::Enum
             | Target::Variant
             | Target::Struct
@@ -1651,6 +1652,7 @@ fn check_repr(
                         E0552,
                         "unrecognized representation hint"
                     )
+                    .help("valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`")
                     .emit();
 
                     continue;
index 625c854ea77a5dd7363aff05d995751edc5bf220..f141d7beeb921b895bc4903e5bc3995eac043416 100644 (file)
@@ -226,19 +226,16 @@ fn handle_tuple_field_pattern_match(
         lhs: &hir::Pat<'_>,
         res: Res,
         pats: &[hir::Pat<'_>],
-        dotdot: Option<usize>,
+        dotdot: hir::DotDotPos,
     ) {
         let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
             ty::Adt(adt, _) => adt.variant_of_res(res),
             _ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"),
         };
-        let first_n = pats.iter().enumerate().take(dotdot.unwrap_or(pats.len()));
+        let dotdot = dotdot.as_opt_usize().unwrap_or(pats.len());
+        let first_n = pats.iter().enumerate().take(dotdot);
         let missing = variant.fields.len() - pats.len();
-        let last_n = pats
-            .iter()
-            .enumerate()
-            .skip(dotdot.unwrap_or(pats.len()))
-            .map(|(idx, pat)| (idx + missing, pat));
+        let last_n = pats.iter().enumerate().skip(dotdot).map(|(idx, pat)| (idx + missing, pat));
         for (idx, pat) in first_n.chain(last_n) {
             if let PatKind::Wild = pat.kind {
                 continue;
@@ -450,7 +447,7 @@ fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-        if let TyKind::OpaqueDef(item_id, _) = ty.kind {
+        if let TyKind::OpaqueDef(item_id, _, _) = ty.kind {
             let item = self.tcx.hir().item(item_id);
             intravisit::walk_item(self, item);
         }
index 212ea9e57a37b5badcf63151f87b220c108fefa8..3bb8c0bb48c5f3b00771355529f517a7686296b0 100644 (file)
@@ -103,7 +103,7 @@ fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: LocalDefId,
             self.error(|| {
                 format!(
                     "ItemLocalIds not assigned densely in {}. \
-                Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
+                Max ItemLocalId = {}, missing IDs = {:#?}; seens IDs = {:#?}",
                     self.hir_map.def_path(owner).to_string_no_crate_verbose(),
                     max,
                     missing_items,
index 81ac0e1b6d445a5455a69a9e9782ff788a62728b..075069feb52d5661f97c16fd338b02bc2852270d 100644 (file)
@@ -437,6 +437,11 @@ fn visit_generic_arg(&mut self, ga: &'v hir::GenericArg<'v>) {
         }
     }
 
+    fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
+        self.record("Lifetime", Id::Node(lifetime.hir_id), lifetime);
+        hir_visit::walk_lifetime(self, lifetime)
+    }
+
     fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
         self.record("Path", Id::None, path);
         hir_visit::walk_path(self, path)
index ba69bc23118b2527921188cdf8f7a595a97bef8b..afd423dc5fa1abfa29dcdd83cd14a14c134903e2 100644 (file)
@@ -1,6 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(associated_type_defaults)]
 #![feature(control_flow_enum)]
+#![feature(let_else)]
 #![feature(rustc_private)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
@@ -334,7 +335,9 @@ fn visit_def_id(
         _kind: &str,
         _descr: &dyn fmt::Display,
     ) -> ControlFlow<Self::BreakTy> {
-        self.min = VL::new_min(self, def_id);
+        if let Some(def_id) = def_id.as_local() {
+            self.min = VL::new_min(self, def_id);
+        }
         ControlFlow::CONTINUE
     }
 }
@@ -342,7 +345,7 @@ fn visit_def_id(
 trait VisibilityLike: Sized {
     const MAX: Self;
     const SHALLOW: bool = false;
-    fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self;
+    fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self;
 
     // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
     // associated types for which we can't determine visibility precisely.
@@ -357,8 +360,8 @@ fn of_impl(def_id: LocalDefId, tcx: TyCtxt<'_>, access_levels: &AccessLevels) ->
 }
 impl VisibilityLike for ty::Visibility {
     const MAX: Self = ty::Visibility::Public;
-    fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self {
-        min(find.tcx.visibility(def_id), find.min, find.tcx)
+    fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
+        min(find.tcx.local_visibility(def_id), find.min, find.tcx)
     }
 }
 impl VisibilityLike for Option<AccessLevel> {
@@ -373,15 +376,8 @@ impl VisibilityLike for Option<AccessLevel> {
     // both "shallow" version of its self type and "shallow" version of its trait if it exists
     // (which require reaching the `DefId`s in them).
     const SHALLOW: bool = true;
-    fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self {
-        cmp::min(
-            if let Some(def_id) = def_id.as_local() {
-                find.access_levels.map.get(&def_id).copied()
-            } else {
-                Self::MAX
-            },
-            find.min,
-        )
+    fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
+        cmp::min(find.access_levels.map.get(&def_id).copied(), find.min)
     }
 }
 
@@ -511,15 +507,15 @@ fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod
         let module = self.tcx.hir().get_module(module_def_id).0;
         for item_id in module.item_ids {
             let def_kind = self.tcx.def_kind(item_id.def_id);
-            let vis = self.tcx.visibility(item_id.def_id);
+            let vis = self.tcx.local_visibility(item_id.def_id);
             self.update_macro_reachable_def(item_id.def_id, def_kind, vis, defining_mod);
         }
         if let Some(exports) = self.tcx.module_reexports(module_def_id) {
             for export in exports {
-                if export.vis.is_accessible_from(defining_mod.to_def_id(), self.tcx) {
+                if export.vis.is_accessible_from(defining_mod, self.tcx) {
                     if let Res::Def(def_kind, def_id) = export.res {
                         if let Some(def_id) = def_id.as_local() {
-                            let vis = self.tcx.visibility(def_id.to_def_id());
+                            let vis = self.tcx.local_visibility(def_id);
                             self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod);
                         }
                     }
@@ -542,7 +538,7 @@ fn update_macro_reachable_def(
         match def_kind {
             // No type privacy, so can be directly marked as reachable.
             DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => {
-                if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                if vis.is_accessible_from(module, self.tcx) {
                     self.update(def_id, level);
                 }
             }
@@ -554,7 +550,7 @@ fn update_macro_reachable_def(
             DefKind::Macro(_) => {
                 let item = self.tcx.hir().expect_item(def_id);
                 if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind {
-                    if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                    if vis.is_accessible_from(module, self.tcx) {
                         self.update(def_id, level);
                     }
                 }
@@ -565,7 +561,7 @@ fn update_macro_reachable_def(
             // hygiene these don't need to be marked reachable. The contents of
             // the module, however may be reachable.
             DefKind::Mod => {
-                if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                if vis.is_accessible_from(module, self.tcx) {
                     self.update_macro_reachable(def_id, module);
                 }
             }
@@ -579,8 +575,8 @@ fn update_macro_reachable_def(
                     {
                         for field in struct_def.fields() {
                             let def_id = self.tcx.hir().local_def_id(field.hir_id);
-                            let field_vis = self.tcx.visibility(def_id);
-                            if field_vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                            let field_vis = self.tcx.local_visibility(def_id);
+                            if field_vis.is_accessible_from(module, self.tcx) {
                                 self.reach(def_id, level).ty();
                             }
                         }
@@ -600,6 +596,7 @@ fn update_macro_reachable_def(
             | DefKind::ForeignTy
             | DefKind::Fn
             | DefKind::OpaqueTy
+            | DefKind::ImplTraitPlaceholder
             | DefKind::AssocFn
             | DefKind::Trait
             | DefKind::TyParam
@@ -654,7 +651,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             hir::ItemKind::Impl(ref impl_) => {
                 for impl_item_ref in impl_.items {
                     if impl_.of_trait.is_some()
-                        || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public
+                        || self.tcx.visibility(impl_item_ref.id.def_id).is_public()
                     {
                         self.update(impl_item_ref.id.def_id, item_level);
                     }
@@ -682,7 +679,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             }
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    if self.tcx.visibility(foreign_item.id.def_id) == ty::Visibility::Public {
+                    if self.tcx.visibility(foreign_item.id.def_id).is_public() {
                         self.update(foreign_item.id.def_id, item_level);
                     }
                 }
@@ -710,12 +707,12 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             hir::ItemKind::Use(..) => {}
             // The interface is empty.
             hir::ItemKind::GlobalAsm(..) => {}
-            hir::ItemKind::OpaqueTy(..) => {
+            hir::ItemKind::OpaqueTy(ref opaque) => {
                 // HACK(jynelson): trying to infer the type of `impl trait` breaks `async-std` (and `pub async fn` in general)
                 // Since rustdoc never needs to do codegen and doesn't care about link-time reachability,
                 // mark this as unreachable.
                 // See https://github.com/rust-lang/rust/issues/75100
-                if !self.tcx.sess.opts.actually_rustdoc {
+                if !opaque.in_trait && !self.tcx.sess.opts.actually_rustdoc {
                     // FIXME: This is some serious pessimization intended to workaround deficiencies
                     // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
                     // reachable if they are returned via `impl Trait`, even from private functions.
@@ -1117,7 +1114,7 @@ fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
     }
 
     fn item_is_accessible(&self, did: DefId) -> bool {
-        self.tcx.visibility(did).is_accessible_from(self.current_item.to_def_id(), self.tcx)
+        self.tcx.visibility(did).is_accessible_from(self.current_item, self.tcx)
     }
 
     // Take node-id of an expression or pattern and check its type for privacy.
@@ -1609,8 +1606,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     let mut found_pub_static = false;
                     for impl_item_ref in impl_.items {
                         if self.access_levels.is_reachable(impl_item_ref.id.def_id)
-                            || self.tcx.visibility(impl_item_ref.id.def_id)
-                                == ty::Visibility::Public
+                            || self.tcx.visibility(impl_item_ref.id.def_id).is_public()
                         {
                             let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                             match impl_item_ref.kind {
@@ -1780,17 +1776,17 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
             );
         }
 
-        let hir_id = match def_id.as_local() {
-            Some(def_id) => self.tcx.hir().local_def_id_to_hir_id(def_id),
-            None => return false,
+        let Some(local_def_id) = def_id.as_local() else {
+            return false;
         };
 
-        let vis = self.tcx.visibility(def_id);
+        let vis = self.tcx.local_visibility(local_def_id);
         if !vis.is_at_least(self.required_visibility, self.tcx) {
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
             let vis_descr = match vis {
                 ty::Visibility::Public => "public",
                 ty::Visibility::Restricted(vis_def_id) => {
-                    if vis_def_id == self.tcx.parent_module(hir_id).to_def_id() {
+                    if vis_def_id == self.tcx.parent_module(hir_id) {
                         "private"
                     } else if vis_def_id.is_top_level_module() {
                         "crate-private"
@@ -1906,7 +1902,7 @@ fn check_assoc_item(
 
     pub fn check_item(&mut self, id: ItemId) {
         let tcx = self.tcx;
-        let item_visibility = tcx.visibility(id.def_id);
+        let item_visibility = tcx.local_visibility(id.def_id);
         let def_kind = tcx.def_kind(id.def_id);
 
         match def_kind {
@@ -1957,7 +1953,7 @@ pub fn check_item(&mut self, id: ItemId) {
                 let item = tcx.hir().item(id);
                 if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
                     for foreign_item in items {
-                        let vis = tcx.visibility(foreign_item.id.def_id);
+                        let vis = tcx.local_visibility(foreign_item.id.def_id);
                         self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
                     }
                 }
@@ -1972,7 +1968,7 @@ pub fn check_item(&mut self, id: ItemId) {
 
                     for field in struct_def.fields() {
                         let def_id = tcx.hir().local_def_id(field.hir_id);
-                        let field_visibility = tcx.visibility(def_id);
+                        let field_visibility = tcx.local_visibility(def_id);
                         self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
                     }
                 }
@@ -1992,7 +1988,7 @@ pub fn check_item(&mut self, id: ItemId) {
                     }
                     for impl_item_ref in impl_.items {
                         let impl_item_vis = if impl_.of_trait.is_none() {
-                            min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
+                            min(tcx.local_visibility(impl_item_ref.id.def_id), impl_vis, tcx)
                         } else {
                             impl_vis
                         };
@@ -2019,8 +2015,11 @@ pub fn provide(providers: &mut Providers) {
     };
 }
 
-fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
-    let def_id = def_id.expect_local();
+fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility<DefId> {
+    local_visibility(tcx, def_id.expect_local()).to_def_id()
+}
+
+fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility {
     match tcx.resolutions(()).visibilities.get(&def_id) {
         Some(vis) => *vis,
         None => {
@@ -2035,9 +2034,10 @@ fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
                 //   Visibility on them should have no effect, but to avoid the visibility
                 //   query failing on some items, we provide it for opaque types as well.
                 | Node::Item(hir::Item {
-                    kind: hir::ItemKind::Use(_, hir::UseKind::ListStem) | hir::ItemKind::OpaqueTy(..),
+                    kind: hir::ItemKind::Use(_, hir::UseKind::ListStem)
+                        | hir::ItemKind::OpaqueTy(..),
                     ..
-                }) => ty::Visibility::Restricted(tcx.parent_module(hir_id).to_def_id()),
+                }) => ty::Visibility::Restricted(tcx.parent_module(hir_id)),
                 // Visibilities of trait impl items are inherited from their traits
                 // and are not filled in resolve.
                 Node::ImplItem(impl_item) => {
@@ -2050,7 +2050,7 @@ fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
                                 tcx.sess.delay_span_bug(tr.path.span, "trait without a def-id");
                                 ty::Visibility::Public
                             },
-                            |def_id| tcx.visibility(def_id),
+                            |def_id| tcx.visibility(def_id).expect_local(),
                         ),
                         _ => span_bug!(impl_item.span, "the parent is not a trait impl"),
                     }
index 8ea09880694eab7e4f57dbd735cf6d56322d0080..26d397f70e0ce83eb725bd09b03b88f40236ef54 100644 (file)
@@ -34,9 +34,6 @@
 mod keys;
 use keys::Key;
 
-mod values;
-use self::values::Value;
-
 pub use rustc_query_system::query::QueryConfig;
 pub(crate) use rustc_query_system::query::{QueryDescription, QueryVTable};
 
index f8e165a1fd509c2bf8f2229cad74170317339151..96679281f07ec6c73335d4a516916f3583b849b3 100644 (file)
@@ -18,6 +18,7 @@
     force_query, QueryConfig, QueryContext, QueryDescription, QueryJobId, QueryMap,
     QuerySideEffects, QueryStackFrame,
 };
+use rustc_query_system::Value;
 use std::any::Any;
 use std::num::NonZeroU64;
 use thin_vec::ThinVec;
@@ -174,21 +175,17 @@ pub fn try_print_query_stack(
 }
 
 macro_rules! handle_cycle_error {
-    ([][$tcx: expr, $error:expr]) => {{
-        $error.emit();
-        Value::from_cycle_error($tcx)
+    ([]) => {{
+        rustc_query_system::HandleCycleError::Error
     }};
-    ([(fatal_cycle) $($rest:tt)*][$tcx:expr, $error:expr]) => {{
-        $error.emit();
-        $tcx.sess.abort_if_errors();
-        unreachable!()
+    ([(fatal_cycle) $($rest:tt)*]) => {{
+        rustc_query_system::HandleCycleError::Fatal
     }};
-    ([(cycle_delay_bug) $($rest:tt)*][$tcx:expr, $error:expr]) => {{
-        $error.delay_as_bug();
-        Value::from_cycle_error($tcx)
+    ([(cycle_delay_bug) $($rest:tt)*]) => {{
+        rustc_query_system::HandleCycleError::DelayBug
     }};
-    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
-        handle_cycle_error!([$($modifiers)*][$($args)*])
+    ([$other:tt $($modifiers:tt)*]) => {
+        handle_cycle_error!([$($modifiers)*])
     };
 }
 
@@ -320,6 +317,7 @@ fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool
 where
     Q: QueryDescription<QueryCtxt<'tcx>>,
     Q::Key: DepNodeParams<TyCtxt<'tcx>>,
+    Q::Value: Value<TyCtxt<'tcx>>,
 {
     if let Some(key) = Q::Key::recover(tcx, &dep_node) {
         #[cfg(debug_assertions)]
@@ -418,7 +416,7 @@ fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
                     depth_limit: depth_limit!([$($modifiers)*]),
                     dep_kind: dep_graph::DepKind::$name,
                     hash_result: hash_result!([$($modifiers)*]),
-                    handle_cycle_error: |tcx, mut error| handle_cycle_error!([$($modifiers)*][tcx, error]),
+                    handle_cycle_error: handle_cycle_error!([$($modifiers)*]),
                     compute,
                     cache_on_disk,
                     try_load_from_disk: Self::TRY_LOAD_FROM_DISK,
diff --git a/compiler/rustc_query_impl/src/values.rs b/compiler/rustc_query_impl/src/values.rs
deleted file mode 100644 (file)
index 0ed48f8..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-use super::QueryCtxt;
-use rustc_middle::ty::{self, AdtSizedConstraint, Ty};
-
-pub(super) trait Value<'tcx>: Sized {
-    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self;
-}
-
-impl<'tcx, T> Value<'tcx> for T {
-    default fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> T {
-        tcx.sess.abort_if_errors();
-        bug!("Value::from_cycle_error called without errors");
-    }
-}
-
-impl<'tcx> Value<'tcx> for Ty<'_> {
-    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
-        // SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
-        // FIXME: Represent the above fact in the trait system somehow.
-        unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error()) }
-    }
-}
-
-impl<'tcx> Value<'tcx> for ty::SymbolName<'_> {
-    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
-        // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
-        // FIXME: Represent the above fact in the trait system somehow.
-        unsafe {
-            std::mem::transmute::<ty::SymbolName<'tcx>, ty::SymbolName<'_>>(ty::SymbolName::new(
-                *tcx, "<error>",
-            ))
-        }
-    }
-}
-
-impl<'tcx> Value<'tcx> for AdtSizedConstraint<'_> {
-    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
-        // SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`.
-        // FIXME: Represent the above fact in the trait system somehow.
-        unsafe {
-            std::mem::transmute::<AdtSizedConstraint<'tcx>, AdtSizedConstraint<'_>>(
-                AdtSizedConstraint(tcx.intern_type_list(&[tcx.ty_error()])),
-            )
-        }
-    }
-}
-
-impl<'tcx> Value<'tcx> for ty::Binder<'_, ty::FnSig<'_>> {
-    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
-        let err = tcx.ty_error();
-        // FIXME(compiler-errors): It would be nice if we could get the
-        // query key, so we could at least generate a fn signature that
-        // has the right arity.
-        let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig(
-            [].into_iter(),
-            err,
-            false,
-            rustc_hir::Unsafety::Normal,
-            rustc_target::spec::abi::Abi::Rust,
-        ));
-
-        // SAFETY: This is never called when `Self` is not `ty::Binder<'tcx, ty::FnSig<'tcx>>`.
-        // FIXME: Represent the above fact in the trait system somehow.
-        unsafe { std::mem::transmute::<ty::PolyFnSig<'tcx>, ty::Binder<'_, ty::FnSig<'_>>>(fn_sig) }
-    }
-}
index bafc6b0a082334826d40a6c0aa9980b05b91c3e7..d7599a56c0b66972b42df897c1d4767adfd915ea 100644 (file)
@@ -21,6 +21,7 @@ rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
+rustc_type_ir = { path = "../rustc_type_ir" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 thin-vec = "0.2.8"
 tracing = "0.1"
index 5f992ec9e21ea85987addb5f9beb465b074850ce..3fb06cbedbd507f6f5d0d04f684d8fc418553518 100644 (file)
@@ -12,6 +12,13 @@ fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
     }
 }
 
+#[derive(Copy, Clone)]
+pub enum HandleCycleError {
+    Error,
+    Fatal,
+    DelayBug,
+}
+
 #[derive(SessionSubdiagnostic)]
 pub enum StackCount {
     #[note(query_system::cycle_stack_single)]
index d7732cb1825b111610f79223dfe0b8fa69bc8c95..0bc811eb04412544d2d783c0ca2400490bf081c8 100644 (file)
@@ -148,3 +148,5 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableH
         });
     }
 }
+
+impl<'ctx> rustc_type_ir::HashStableContext for StableHashingContext<'ctx> {}
index 7067bc5f09cfc07229179036d4042896b836611b..8a88b5c334078b77941997efbcdf0ed97c805d23 100644 (file)
@@ -20,3 +20,7 @@
 mod error;
 pub mod ich;
 pub mod query;
+mod values;
+
+pub use error::HandleCycleError;
+pub use values::Value;
index ea38df836cbf1e4a0f9b98b8cad319644a4ad8b6..c63e110a62e3935fb301b0f0e10e7edb8fe616a8 100644 (file)
@@ -2,12 +2,12 @@
 
 use crate::dep_graph::DepNode;
 use crate::dep_graph::SerializedDepNodeIndex;
+use crate::error::HandleCycleError;
 use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
 use crate::query::{QueryContext, QueryState};
 
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
 use std::fmt::Debug;
 use std::hash::Hash;
 
@@ -19,6 +19,7 @@ pub trait QueryConfig {
     type Stored: Clone;
 }
 
+#[derive(Copy, Clone)]
 pub struct QueryVTable<CTX: QueryContext, K, V> {
     pub anon: bool,
     pub dep_kind: CTX::DepKind,
@@ -28,7 +29,7 @@ pub struct QueryVTable<CTX: QueryContext, K, V> {
 
     pub compute: fn(CTX::DepContext, K) -> V,
     pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
-    pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_, ErrorGuaranteed>) -> V,
+    pub handle_cycle_error: HandleCycleError,
     pub try_load_from_disk: Option<fn(CTX, SerializedDepNodeIndex) -> Option<V>>,
 }
 
index 7bbc22e8293a566ab9e2103ef9137bb5c07b359d..e39e39860cbb8d09cb8b2712d8fa2e7f293cca92 100644 (file)
@@ -7,6 +7,8 @@
 use crate::query::config::{QueryDescription, QueryVTable};
 use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
 use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
+use crate::values::Value;
+use crate::HandleCycleError;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 #[cfg(parallel_compiler)]
@@ -118,19 +120,46 @@ struct JobOwner<'tcx, K>
 fn mk_cycle<CTX, V, R>(
     tcx: CTX,
     error: CycleError,
-    handle_cycle_error: fn(CTX, DiagnosticBuilder<'_, ErrorGuaranteed>) -> V,
+    handler: HandleCycleError,
     cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
 ) -> R
 where
     CTX: QueryContext,
-    V: std::fmt::Debug,
+    V: std::fmt::Debug + Value<CTX::DepContext>,
     R: Clone,
 {
     let error = report_cycle(tcx.dep_context().sess(), error);
-    let value = handle_cycle_error(tcx, error);
+    let value = handle_cycle_error(*tcx.dep_context(), error, handler);
     cache.store_nocache(value)
 }
 
+fn handle_cycle_error<CTX, V>(
+    tcx: CTX,
+    mut error: DiagnosticBuilder<'_, ErrorGuaranteed>,
+    handler: HandleCycleError,
+) -> V
+where
+    CTX: DepContext,
+    V: Value<CTX>,
+{
+    use HandleCycleError::*;
+    match handler {
+        Error => {
+            error.emit();
+            Value::from_cycle_error(tcx)
+        }
+        Fatal => {
+            error.emit();
+            tcx.sess().abort_if_errors();
+            unreachable!()
+        }
+        DelayBug => {
+            error.delay_as_bug();
+            Value::from_cycle_error(tcx)
+        }
+    }
+}
+
 impl<'tcx, K> JobOwner<'tcx, K>
 where
     K: Eq + Hash + Clone,
@@ -336,6 +365,7 @@ fn try_execute_query<CTX, C>(
 where
     C: QueryCache,
     C::Key: Clone + DepNodeParams<CTX::DepContext>,
+    C::Value: Value<CTX::DepContext>,
     CTX: QueryContext,
 {
     match JobOwner::<'_, C::Key>::try_start(&tcx, state, span, key.clone()) {
@@ -686,6 +716,7 @@ pub fn get_query<Q, CTX>(tcx: CTX, span: Span, key: Q::Key, mode: QueryMode) ->
 where
     Q: QueryDescription<CTX>,
     Q::Key: DepNodeParams<CTX::DepContext>,
+    Q::Value: Value<CTX::DepContext>,
     CTX: QueryContext,
 {
     let query = Q::make_vtable(tcx, &key);
@@ -718,6 +749,7 @@ pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, dep_node: DepNode<CTX::DepKind
 where
     Q: QueryDescription<CTX>,
     Q::Key: DepNodeParams<CTX::DepContext>,
+    Q::Value: Value<CTX::DepContext>,
     CTX: QueryContext,
 {
     // We may be concurrently trying both execute and force a query.
diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs
new file mode 100644 (file)
index 0000000..aeef66f
--- /dev/null
@@ -0,0 +1,14 @@
+use crate::dep_graph::DepContext;
+
+pub trait Value<CTX: DepContext>: Sized {
+    fn from_cycle_error(tcx: CTX) -> Self;
+}
+
+impl<CTX: DepContext, T> Value<CTX> for T {
+    default fn from_cycle_error(tcx: CTX) -> T {
+        tcx.sess().abort_if_errors();
+        // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
+        // non-trivial to define it earlier.
+        panic!("Value::from_cycle_error called without errors");
+    }
+}
index 51e8c24b9c25a51066088753bf4ec5b00a261798..81b67b758f7e12393262b31a362252a180032a29 100644 (file)
 
 type Res = def::Res<NodeId>;
 
-impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, LocalExpnId) {
+impl<'a, Id: Into<DefId>> ToNameBinding<'a>
+    for (Module<'a>, ty::Visibility<Id>, Span, LocalExpnId)
+{
     fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
         arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Module(self.0),
             ambiguity: None,
-            vis: self.1,
+            vis: self.1.to_def_id(),
             span: self.2,
             expansion: self.3,
         })
     }
 }
 
-impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId) {
+impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span, LocalExpnId) {
     fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
         arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Res(self.0, false),
             ambiguity: None,
-            vis: self.1,
+            vis: self.1.to_def_id(),
             span: self.2,
             expansion: self.3,
         })
@@ -70,7 +72,7 @@ fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a>
         arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Res(self.0, true),
             ambiguity: None,
-            vis: self.1,
+            vis: self.1.to_def_id(),
             span: self.2,
             expansion: self.3,
         })
@@ -260,7 +262,9 @@ fn try_resolve_visibility<'ast>(
                         self.r.visibilities[&def_id.expect_local()]
                     }
                     // Otherwise, the visibility is restricted to the nearest parent `mod` item.
-                    _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()),
+                    _ => ty::Visibility::Restricted(
+                        self.parent_scope.module.nearest_parent_mod().expect_local(),
+                    ),
                 })
             }
             ast::VisibilityKind::Restricted { ref path, id, .. } => {
@@ -311,7 +315,7 @@ fn try_resolve_visibility<'ast>(
                             } else {
                                 let vis = ty::Visibility::Restricted(res.def_id());
                                 if self.r.is_accessible_from(vis, parent_scope.module) {
-                                    Ok(vis)
+                                    Ok(vis.expect_local())
                                 } else {
                                     Err(VisResolutionError::AncestorOnly(path.span))
                                 }
@@ -649,7 +653,9 @@ fn build_reduced_graph_for_use_tree(
                         true,
                         // The whole `use` item
                         item,
-                        ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()),
+                        ty::Visibility::Restricted(
+                            self.parent_scope.module.nearest_parent_mod().expect_local(),
+                        ),
                         root_span,
                     );
                 }
@@ -765,10 +771,10 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
                 if let Some(ctor_node_id) = vdata.ctor_id() {
                     // If the structure is marked as non_exhaustive then lower the visibility
                     // to within the crate.
-                    let mut ctor_vis = if vis == ty::Visibility::Public
+                    let mut ctor_vis = if vis.is_public()
                         && self.r.session.contains_name(&item.attrs, sym::non_exhaustive)
                     {
-                        ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
+                        ty::Visibility::Restricted(CRATE_DEF_ID)
                     } else {
                         vis
                     };
@@ -785,7 +791,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
                         if ctor_vis.is_at_least(field_vis, &*self.r) {
                             ctor_vis = field_vis;
                         }
-                        ret_fields.push(field_vis);
+                        ret_fields.push(field_vis.to_def_id());
                     }
                     let ctor_def_id = self.r.local_def_id(ctor_node_id);
                     let ctor_res = Res::Def(
@@ -795,7 +801,9 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
                     self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
                     self.r.visibilities.insert(ctor_def_id, ctor_vis);
 
-                    self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis, ret_fields));
+                    self.r
+                        .struct_constructors
+                        .insert(def_id, (ctor_res, ctor_vis.to_def_id(), ret_fields));
                 }
             }
 
@@ -867,8 +875,8 @@ fn build_reduced_graph_for_extern_crate(
         }
         .map(|module| {
             let used = self.process_macro_use_imports(item, module);
-            let binding =
-                (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas);
+            let vis = ty::Visibility::<LocalDefId>::Public;
+            let binding = (module, vis, sp, expansion).to_name_binding(self.r.arenas);
             (used, Some(ModuleOrUniformRoot::Module(module)), binding)
         })
         .unwrap_or((true, None, self.r.dummy_binding));
@@ -964,6 +972,7 @@ fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) {
                 | DefKind::TyAlias
                 | DefKind::ForeignTy
                 | DefKind::OpaqueTy
+                | DefKind::ImplTraitPlaceholder
                 | DefKind::TraitAlias
                 | DefKind::AssocTy,
                 _,
@@ -1117,7 +1126,7 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'a>) -> bool
                 root_span: span,
                 span,
                 module_path: Vec::new(),
-                vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()))),
+                vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID))),
                 used: Cell::new(false),
             })
         };
@@ -1263,7 +1272,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> {
             let vis = if is_macro_export {
                 ty::Visibility::Public
             } else {
-                ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
+                ty::Visibility::Restricted(CRATE_DEF_ID)
             };
             let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
             self.r.set_binding_parent_module(binding, parent_scope.module);
@@ -1294,7 +1303,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> {
                 }
                 _ => self.resolve_visibility(&item.vis),
             };
-            if vis != ty::Visibility::Public {
+            if !vis.is_public() {
                 self.insert_unused_macro(ident, def_id, item.id, &rule_spans);
             }
             self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
@@ -1507,10 +1516,10 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) {
         self.r.visibilities.insert(def_id, vis);
 
         // If the variant is marked as non_exhaustive then lower the visibility to within the crate.
-        let ctor_vis = if vis == ty::Visibility::Public
+        let ctor_vis = if vis.is_public()
             && self.r.session.contains_name(&variant.attrs, sym::non_exhaustive)
         {
-            ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
+            ty::Visibility::Restricted(CRATE_DEF_ID)
         } else {
             vis
         };
index b84a610833ddf6a8faa398d6e070d0ef93b25136..2287aa1eb2567691517b93d569b4a2934dacde84 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_middle::ty;
 use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
 use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_span::def_id::LocalDefId;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
 use rustc_span::symbol::{kw, Ident};
@@ -26,6 +27,8 @@
 use Namespace::*;
 use RibKind::*;
 
+type Visibility = ty::Visibility<LocalDefId>;
+
 impl<'a> Resolver<'a> {
     /// A generic scope visitor.
     /// Visits scopes in order to resolve some identifier in them or perform other actions.
@@ -424,8 +427,7 @@ struct Flags: u8 {
                 let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt));
                 let ok = |res, span, arenas| {
                     Ok((
-                        (res, ty::Visibility::Public, span, LocalExpnId::ROOT)
-                            .to_name_binding(arenas),
+                        (res, Visibility::Public, span, LocalExpnId::ROOT).to_name_binding(arenas),
                         Flags::empty(),
                     ))
                 };
@@ -438,7 +440,7 @@ struct Flags: u8 {
                         {
                             let binding = (
                                 Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
-                                ty::Visibility::Public,
+                                Visibility::Public,
                                 attr.span,
                                 expn_id,
                             )
@@ -841,9 +843,8 @@ fn resolve_ident_in_module_unadjusted_ext(
                 if ns == TypeNS {
                     if ident.name == kw::Crate || ident.name == kw::DollarCrate {
                         let module = self.resolve_crate_root(ident);
-                        let binding =
-                            (module, ty::Visibility::Public, module.span, LocalExpnId::ROOT)
-                                .to_name_binding(self.arenas);
+                        let binding = (module, Visibility::Public, module.span, LocalExpnId::ROOT)
+                            .to_name_binding(self.arenas);
                         return Ok(binding);
                     } else if ident.name == kw::Super || ident.name == kw::SelfLower {
                         // FIXME: Implement these with renaming requirements so that e.g.
index 27745cee52df7f3243630d103984205ecbb9db78..c133c272bac275e48625704d76255cbfc414c824 100644 (file)
@@ -214,7 +214,7 @@ pub(crate) fn import(
         binding: &'a NameBinding<'a>,
         import: &'a Import<'a>,
     ) -> &'a NameBinding<'a> {
-        let import_vis = import.expect_vis();
+        let import_vis = import.expect_vis().to_def_id();
         let vis = if binding.vis.is_at_least(import_vis, self)
             || pub_use_of_private_extern_crate_hack(import, binding)
         {
@@ -227,7 +227,7 @@ pub(crate) fn import(
             if vis == import_vis
                 || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self))
             {
-                max_vis.set(Some(vis))
+                max_vis.set(Some(vis.expect_local()))
             }
         }
 
index b37feb15890ba22ff080b55f34c231a67318536f..2d6e76c451bfa3ea1a525e167f187874338f06f9 100644 (file)
@@ -851,7 +851,7 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
                         // We include all lifetime parameters, either named or "Fresh".
                         // The order of those parameters does not matter, as long as it is
                         // deterministic.
-                        if let Some(async_node_id) = async_node_id {
+                        if let Some((async_node_id, _)) = async_node_id {
                             let mut extra_lifetime_params = this
                                 .r
                                 .extra_lifetime_params_map
index c72981ed96f6788b0c840ff7c420349aace8e42d..6ff56f9a89114cd4367d7a18d0e8b71b3e98d912 100644 (file)
@@ -525,6 +525,7 @@ fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         match &item.kind {
             hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
@@ -714,7 +715,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                 };
                 self.with(scope, |this| this.visit_ty(&mt.ty));
             }
-            hir::TyKind::OpaqueDef(item_id, lifetimes) => {
+            hir::TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => {
                 // Resolve the lifetimes in the bounds to the lifetime defs in the generics.
                 // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
                 // `type MyAnonTy<'b> = impl MyTrait<'b>;`
@@ -839,6 +840,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         use self::hir::TraitItemKind::*;
         match trait_item.kind {
@@ -888,6 +890,7 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         use self::hir::ImplItemKind::*;
         match impl_item.kind {
index aaa9ae6f32513cc639378f7a704d04e27d25ec46..749a78a7552ed366f9463672d1c59d4df3bf5ccd 100644 (file)
@@ -57,7 +57,7 @@
 use smallvec::{smallvec, SmallVec};
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
-use std::{cmp, fmt, ptr};
+use std::{fmt, ptr};
 
 use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
 use imports::{Import, ImportKind, ImportResolver, NameResolution};
@@ -163,7 +163,6 @@ enum ImplTraitContext {
     Universal(LocalDefId),
 }
 
-#[derive(Eq)]
 struct BindingError {
     name: Symbol,
     origin: BTreeSet<Span>,
@@ -171,24 +170,6 @@ struct BindingError {
     could_be_path: bool,
 }
 
-impl PartialOrd for BindingError {
-    fn partial_cmp(&self, other: &BindingError) -> Option<cmp::Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl PartialEq for BindingError {
-    fn eq(&self, other: &BindingError) -> bool {
-        self.name == other.name
-    }
-}
-
-impl Ord for BindingError {
-    fn cmp(&self, other: &BindingError) -> cmp::Ordering {
-        self.name.cmp(&other.name)
-    }
-}
-
 enum ResolutionError<'a> {
     /// Error E0401: can't use type or const parameters from outer function.
     GenericParamsFromOuterFunction(Res, HasGenericParams),
@@ -648,7 +629,7 @@ pub struct NameBinding<'a> {
     ambiguity: Option<(&'a NameBinding<'a>, AmbiguityKind)>,
     expansion: LocalExpnId,
     span: Span,
-    vis: ty::Visibility,
+    vis: ty::Visibility<DefId>,
 }
 
 pub trait ToNameBinding<'a> {
@@ -845,7 +826,7 @@ fn may_appear_after(
     }
 }
 
-#[derive(Debug, Default, Clone)]
+#[derive(Default, Clone)]
 pub struct ExternPreludeEntry<'a> {
     extern_crate_item: Option<&'a NameBinding<'a>>,
     pub introduced_by_item: bool,
@@ -1012,7 +993,7 @@ pub struct Resolver<'a> {
     /// Table for mapping struct IDs into struct constructor IDs,
     /// it's not used during normal resolution, only for better error reporting.
     /// Also includes of list of each fields visibility
-    struct_constructors: DefIdMap<(Res, ty::Visibility, Vec<ty::Visibility>)>,
+    struct_constructors: DefIdMap<(Res, ty::Visibility<DefId>, Vec<ty::Visibility<DefId>>)>,
 
     /// Features enabled for this crate.
     active_features: FxHashSet<Symbol>,
@@ -1808,7 +1789,11 @@ fn record_pat_span(&mut self, node: NodeId, span: Span) {
         self.pat_span_map.insert(node, span);
     }
 
-    fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
+    fn is_accessible_from(
+        &self,
+        vis: ty::Visibility<impl Into<DefId>>,
+        module: Module<'a>,
+    ) -> bool {
         vis.is_accessible_from(module.nearest_parent_mod(), self)
     }
 
@@ -1862,10 +1847,8 @@ fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<&'a Nam
                     self.crate_loader.maybe_process_path_extern(ident.name)?
                 };
                 let crate_root = self.expect_module(crate_id.as_def_id());
-                Some(
-                    (crate_root, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT)
-                        .to_name_binding(self.arenas),
-                )
+                let vis = ty::Visibility::<LocalDefId>::Public;
+                Some((crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas))
             }
         })
     }
index 6658892881d4b9bbf365734f6d83a9e938890c2c..94f222251d3dc7b0787ccbdd26698d10925d93a3 100644 (file)
@@ -1321,7 +1321,7 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
                         }),
                 }
             }
-            hir::TyKind::OpaqueDef(item_id, _) => {
+            hir::TyKind::OpaqueDef(item_id, _, _) => {
                 let item = self.tcx.hir().item(item_id);
                 self.nest_typeck_results(item_id.def_id, |v| v.visit_item(item));
             }
index 89bca39512f52554250cab4ad0894128cae84752..ebe44a56449d32ec5b75ac6578f921316250759e 100644 (file)
@@ -685,6 +685,7 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
                 | HirDefKind::AssocTy
                 | HirDefKind::Trait
                 | HirDefKind::OpaqueTy
+                | HirDefKind::ImplTraitPlaceholder
                 | HirDefKind::TyParam,
                 def_id,
             ) => Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(def_id) }),
index d1286c9b8b0dfeb083a4e2585f57aa3d4d8eb1a5..bae1828cd182df3f7f6380c4c325ed01e6cd30b7 100644 (file)
@@ -316,7 +316,7 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
                 let text = format!("[{}; {}]", nested_ty.text, expr);
                 Ok(replace_text(nested_ty, text))
             }
-            hir::TyKind::OpaqueDef(item_id, _) => {
+            hir::TyKind::OpaqueDef(item_id, _, _) => {
                 let item = scx.tcx.hir().item(item_id);
                 item.make(offset, Some(item_id.hir_id()), scx)
             }
@@ -561,7 +561,13 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
             hir::ItemKind::ForeignMod { .. } => Err("extern mod"),
             hir::ItemKind::GlobalAsm(_) => Err("global asm"),
             hir::ItemKind::ExternCrate(_) => Err("extern crate"),
-            hir::ItemKind::OpaqueTy(..) => Err("opaque type"),
+            hir::ItemKind::OpaqueTy(ref opaque) => {
+                if opaque.in_trait {
+                    Err("opaque type in trait")
+                } else {
+                    Err("opaque type")
+                }
+            }
             // FIXME should implement this (e.g., pub use).
             hir::ItemKind::Use(..) => Err("import"),
         }
index 04bd685f19001ed99d9bb01e4ba4cd55389ba3c7..8bb3878fbbb4752c8d7f4371cab537ba6b39a658 100644 (file)
@@ -898,7 +898,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
     let max_atomic_width = sess.target.max_atomic_width();
     let atomic_cas = sess.target.atomic_cas;
     let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
-        sess.fatal(&err);
+        sess.emit_fatal(err);
     });
 
     let mut ret = CrateConfig::default();
index 7252f1799dac178297ebcb0d024fea2444256e2f..3c93cfab183d24206e796c2ebd9e0e808fc00e0a 100644 (file)
@@ -1,10 +1,12 @@
 use std::num::NonZeroU32;
 
-use crate as rustc_session;
 use crate::cgu_reuse_tracker::CguReuse;
-use rustc_errors::MultiSpan;
+use crate::{self as rustc_session, SessionDiagnostic};
+use rustc_errors::{fluent, DiagnosticBuilder, Handler, MultiSpan};
 use rustc_macros::SessionDiagnostic;
 use rustc_span::{Span, Symbol};
+use rustc_target::abi::TargetDataLayoutErrors;
+use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
 
 #[derive(SessionDiagnostic)]
 #[diag(session::incorrect_cgu_reuse_type)]
@@ -43,3 +45,128 @@ pub struct FeatureDiagnosticForIssue {
 pub struct FeatureDiagnosticHelp {
     pub feature: Symbol,
 }
+
+impl SessionDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
+    fn into_diagnostic(self, sess: &Handler) -> DiagnosticBuilder<'_, !> {
+        let mut diag;
+        match self {
+            TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
+                diag = sess.struct_fatal(fluent::session::target_invalid_address_space);
+                diag.set_arg("addr_space", addr_space);
+                diag.set_arg("cause", cause);
+                diag.set_arg("err", err);
+                diag
+            }
+            TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
+                diag = sess.struct_fatal(fluent::session::target_invalid_bits);
+                diag.set_arg("kind", kind);
+                diag.set_arg("bit", bit);
+                diag.set_arg("cause", cause);
+                diag.set_arg("err", err);
+                diag
+            }
+            TargetDataLayoutErrors::MissingAlignment { cause } => {
+                diag = sess.struct_fatal(fluent::session::target_missing_alignment);
+                diag.set_arg("cause", cause);
+                diag
+            }
+            TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
+                diag = sess.struct_fatal(fluent::session::target_invalid_alignment);
+                diag.set_arg("cause", cause);
+                diag.set_arg("err", err);
+                diag
+            }
+            TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
+                diag = sess.struct_fatal(fluent::session::target_inconsistent_architecture);
+                diag.set_arg("dl", dl);
+                diag.set_arg("target", target);
+                diag
+            }
+            TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
+                diag = sess.struct_fatal(fluent::session::target_inconsistent_pointer_width);
+                diag.set_arg("pointer_size", pointer_size);
+                diag.set_arg("target", target);
+                diag
+            }
+            TargetDataLayoutErrors::InvalidBitsSize { err } => {
+                diag = sess.struct_fatal(fluent::session::target_invalid_bits_size);
+                diag.set_arg("err", err);
+                diag
+            }
+        }
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::not_circumvent_feature)]
+pub struct NotCircumventFeature;
+
+#[derive(SessionDiagnostic)]
+#[diag(session::linker_plugin_lto_windows_not_supported)]
+pub struct LinkerPluginToWindowsNotSupported;
+
+#[derive(SessionDiagnostic)]
+#[diag(session::profile_use_file_does_not_exist)]
+pub struct ProfileUseFileDoesNotExist<'a> {
+    pub path: &'a std::path::Path,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::profile_sample_use_file_does_not_exist)]
+pub struct ProfileSampleUseFileDoesNotExist<'a> {
+    pub path: &'a std::path::Path,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::target_requires_unwind_tables)]
+pub struct TargetRequiresUnwindTables;
+
+#[derive(SessionDiagnostic)]
+#[diag(session::sanitizer_not_supported)]
+pub struct SanitizerNotSupported {
+    pub us: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::sanitizers_not_supported)]
+pub struct SanitizersNotSupported {
+    pub us: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::cannot_mix_and_match_sanitizers)]
+pub struct CannotMixAndMatchSanitizers {
+    pub first: String,
+    pub second: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::cannot_enable_crt_static_linux)]
+pub struct CannotEnableCrtStaticLinux;
+
+#[derive(SessionDiagnostic)]
+#[diag(session::sanitizer_cfi_enabled)]
+pub struct SanitizerCfiEnabled;
+
+#[derive(SessionDiagnostic)]
+#[diag(session::unstable_virtual_function_elimination)]
+pub struct UnstableVirtualFunctionElimination;
+
+#[derive(SessionDiagnostic)]
+#[diag(session::unsupported_dwarf_version)]
+pub struct UnsupportedDwarfVersion {
+    pub dwarf_version: u32,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::target_stack_protector_not_supported)]
+pub struct StackProtectorNotSupportedForTarget<'a> {
+    pub stack_protector: StackProtector,
+    pub target_triple: &'a TargetTriple,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::split_debuginfo_unstable_platform)]
+pub struct SplitDebugInfoUnstablePlatform {
+    pub debuginfo: SplitDebuginfo,
+}
index 557edad548c64a2a3b0de2679bf7e65e41391b1c..caf9d582ab09970db94218b3da91b47994f89fe6 100644 (file)
@@ -2,6 +2,13 @@
 use crate::code_stats::CodeStats;
 pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
 use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath};
+use crate::errors::{
+    CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported,
+    NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist,
+    SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported,
+    SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget,
+    TargetRequiresUnwindTables, UnstableVirtualFunctionElimination, UnsupportedDwarfVersion,
+};
 use crate::parse::{add_feature_diagnostics, ParseSess};
 use crate::search_paths::{PathKind, SearchPath};
 use crate::{filesearch, lint};
@@ -235,6 +242,9 @@ fn check_miri_unleashed_features(&self) {
         if !unleashed_features.is_empty() {
             let mut must_err = false;
             // Create a diagnostic pointing at where things got unleashed.
+            // FIXME(#100717): needs eager translation/lists
+            #[allow(rustc::untranslatable_diagnostic)]
+            #[allow(rustc::diagnostic_outside_of_impl)]
             let mut diag = self.struct_warn("skipping const checks");
             for &(span, feature_gate) in unleashed_features.iter() {
                 // FIXME: `span_label` doesn't do anything, so we use "help" as a hack.
@@ -250,10 +260,7 @@ fn check_miri_unleashed_features(&self) {
             // If we should err, make sure we did.
             if must_err && self.has_errors().is_none() {
                 // We have skipped a feature gate, and not run into other errors... reject.
-                self.err(
-                    "`-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature \
-                     gates, except when testing error paths in the CTFE engine",
-                );
+                self.emit_err(NotCircumventFeature);
             }
         }
     }
@@ -534,9 +541,13 @@ pub fn track_errors<F, T>(&self, f: F) -> Result<T, ErrorGuaranteed>
             Err(ErrorGuaranteed::unchecked_claim_error_was_emitted())
         }
     }
+    #[allow(rustc::untranslatable_diagnostic)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
         self.diagnostic().span_warn(sp, msg)
     }
+    #[allow(rustc::untranslatable_diagnostic)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn span_warn_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -585,6 +596,8 @@ pub fn span_note_without_error<S: Into<MultiSpan>>(
     ) {
         self.diagnostic().span_note_without_error(sp, msg)
     }
+    #[allow(rustc::untranslatable_diagnostic)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_note_without_error(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -1469,40 +1482,28 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         && sess.opts.cg.prefer_dynamic
         && sess.target.is_like_windows
     {
-        sess.err(
-            "Linker plugin based LTO is not supported together with \
-                  `-C prefer-dynamic` when targeting Windows-like targets",
-        );
+        sess.emit_err(LinkerPluginToWindowsNotSupported);
     }
 
     // Make sure that any given profiling data actually exists so LLVM can't
     // decide to silently skip PGO.
     if let Some(ref path) = sess.opts.cg.profile_use {
         if !path.exists() {
-            sess.err(&format!(
-                "File `{}` passed to `-C profile-use` does not exist.",
-                path.display()
-            ));
+            sess.emit_err(ProfileUseFileDoesNotExist { path });
         }
     }
 
     // Do the same for sample profile data.
     if let Some(ref path) = sess.opts.unstable_opts.profile_sample_use {
         if !path.exists() {
-            sess.err(&format!(
-                "File `{}` passed to `-C profile-sample-use` does not exist.",
-                path.display()
-            ));
+            sess.emit_err(ProfileSampleUseFileDoesNotExist { path });
         }
     }
 
     // Unwind tables cannot be disabled if the target requires them.
     if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables {
         if sess.target.requires_uwtable && !include_uwtables {
-            sess.err(
-                "target requires unwind tables, they cannot be disabled with \
-                     `-C force-unwind-tables=no`.",
-            );
+            sess.emit_err(TargetRequiresUnwindTables);
         }
     }
 
@@ -1512,64 +1513,55 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     match unsupported_sanitizers.into_iter().count() {
         0 => {}
         1 => {
-            sess.err(&format!(
-                "{} sanitizer is not supported for this target",
-                unsupported_sanitizers
-            ));
+            sess.emit_err(SanitizerNotSupported { us: unsupported_sanitizers.to_string() });
         }
         _ => {
-            sess.err(&format!(
-                "{} sanitizers are not supported for this target",
-                unsupported_sanitizers
-            ));
+            sess.emit_err(SanitizersNotSupported { us: unsupported_sanitizers.to_string() });
         }
     }
     // Cannot mix and match sanitizers.
     let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter();
     if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
-        sess.err(&format!("`-Zsanitizer={first}` is incompatible with `-Zsanitizer={second}`"));
+        sess.emit_err(CannotMixAndMatchSanitizers {
+            first: first.to_string(),
+            second: second.to_string(),
+        });
     }
 
     // Cannot enable crt-static with sanitizers on Linux
     if sess.crt_static(None) && !sess.opts.unstable_opts.sanitizer.is_empty() {
-        sess.err(
-            "sanitizer is incompatible with statically linked libc, \
-                                disable it using `-C target-feature=-crt-static`",
-        );
+        sess.emit_err(CannotEnableCrtStaticLinux);
     }
 
     // LLVM CFI and VFE both require LTO.
     if sess.lto() != config::Lto::Fat {
         if sess.is_sanitizer_cfi_enabled() {
-            sess.err("`-Zsanitizer=cfi` requires `-Clto`");
+            sess.emit_err(SanitizerCfiEnabled);
         }
         if sess.opts.unstable_opts.virtual_function_elimination {
-            sess.err("`-Zvirtual-function-elimination` requires `-Clto`");
+            sess.emit_err(UnstableVirtualFunctionElimination);
         }
     }
 
     if sess.opts.unstable_opts.stack_protector != StackProtector::None {
         if !sess.target.options.supports_stack_protector {
-            sess.warn(&format!(
-                "`-Z stack-protector={}` is not supported for target {} and will be ignored",
-                sess.opts.unstable_opts.stack_protector, sess.opts.target_triple
-            ))
+            sess.emit_warning(StackProtectorNotSupportedForTarget {
+                stack_protector: sess.opts.unstable_opts.stack_protector,
+                target_triple: &sess.opts.target_triple,
+            });
         }
     }
 
     if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version {
         if dwarf_version > 5 {
-            sess.err(&format!("requested DWARF version {} is greater than 5", dwarf_version));
+            sess.emit_err(UnsupportedDwarfVersion { dwarf_version });
         }
     }
 
     if !sess.target.options.supported_split_debuginfo.contains(&sess.split_debuginfo())
         && !sess.opts.unstable_opts.unstable_options
     {
-        sess.err(&format!(
-            "`-Csplit-debuginfo={}` is unstable on this platform",
-            sess.split_debuginfo()
-        ));
+        sess.emit_err(SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() });
     }
 }
 
@@ -1614,14 +1606,20 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler
     rustc_errors::Handler::with_emitter(true, None, emitter)
 }
 
+#[allow(rustc::untranslatable_diagnostic)]
+#[allow(rustc::diagnostic_outside_of_impl)]
 pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed {
     early_error_handler(output).struct_err(msg).emit()
 }
 
+#[allow(rustc::untranslatable_diagnostic)]
+#[allow(rustc::diagnostic_outside_of_impl)]
 pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
     early_error_handler(output).struct_fatal(msg).emit()
 }
 
+#[allow(rustc::untranslatable_diagnostic)]
+#[allow(rustc::diagnostic_outside_of_impl)]
 pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
     early_error_handler(output).struct_warn(msg).emit()
 }
index a1533fe46b3ef6e5b828c46fc7ed7f48bc07cddf..ceb6b6c68b0551cae87f27896980089a095ac310 100644 (file)
@@ -305,6 +305,12 @@ pub fn is_top_level_module(self) -> bool {
     }
 }
 
+impl From<LocalDefId> for DefId {
+    fn from(local: LocalDefId) -> DefId {
+        local.to_def_id()
+    }
+}
+
 impl<E: Encoder> Encodable<E> for DefId {
     default fn encode(&self, s: &mut E) {
         self.krate.encode(s);
index 75b1dfc856ac715c0877b252b45df38dbf01dd25..9c3d99deae06d5b1de3332074f7061f02c327fc7 100644 (file)
         gen_future,
         gen_kill,
         generator,
-        generator_return,
         generator_state,
         generators,
         generic_arg_infer,
         profiler_builtins,
         profiler_runtime,
         ptr,
-        ptr_guaranteed_eq,
-        ptr_guaranteed_ne,
+        ptr_guaranteed_cmp,
         ptr_mask,
         ptr_null,
         ptr_null_mut,
         require,
         residual,
         result,
+        return_position_impl_trait_in_trait,
         rhs,
         rintf32,
         rintf64,
index cb61f76af1d73669c5b05086aa9a19713255499b..b1de979e8f8ec4f82f4c83b61930923b2e4fd4c8 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{
     self, Binder, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind,
-    Term, Ty, TyCtxt, UintTy,
+    TermKind, Ty, TyCtxt, UintTy,
 };
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::sym;
@@ -243,13 +243,9 @@ fn encode_predicate<'tcx>(
             let name = encode_ty_name(tcx, projection.item_def_id);
             let _ = write!(s, "u{}{}", name.len(), &name);
             s.push_str(&encode_substs(tcx, projection.substs, dict, options));
-            match projection.term {
-                Term::Ty(ty) => {
-                    s.push_str(&encode_ty(tcx, ty, dict, options));
-                }
-                Term::Const(c) => {
-                    s.push_str(&encode_const(tcx, c, dict, options));
-                }
+            match projection.term.unpack() {
+                TermKind::Ty(ty) => s.push_str(&encode_ty(tcx, ty, dict, options)),
+                TermKind::Const(c) => s.push_str(&encode_const(tcx, c, dict, options)),
             }
         }
         ty::ExistentialPredicate::AutoTrait(def_id) => {
index 71fa5a44887082048871a594d10214acbef1117a..cfb8d47e54534d3b2b1187652b2e71cf30aaff7d 100644 (file)
@@ -543,9 +543,9 @@ fn print_dyn_existential(
                         let name = cx.tcx.associated_item(projection.item_def_id).name;
                         cx.push("p");
                         cx.push_ident(name.as_str());
-                        cx = match projection.term {
-                            ty::Term::Ty(ty) => ty.print(cx),
-                            ty::Term::Const(c) => c.print(cx),
+                        cx = match projection.term.unpack() {
+                            ty::TermKind::Ty(ty) => ty.print(cx),
+                            ty::TermKind::Const(c) => c.print(cx),
                         }?;
                     }
                     ty::ExistentialPredicate::AutoTrait(def_id) => {
index 92ce4d91d84d1baeaf9288d034066107c2b908cb..ec334e5887ab765bfcacababdd2823bfe026a7f1 100644 (file)
@@ -7,7 +7,7 @@
 use std::convert::{TryFrom, TryInto};
 use std::fmt;
 use std::iter::Step;
-use std::num::NonZeroUsize;
+use std::num::{NonZeroUsize, ParseIntError};
 use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
 use std::str::FromStr;
 
@@ -69,34 +69,46 @@ fn default() -> TargetDataLayout {
     }
 }
 
+pub enum TargetDataLayoutErrors<'a> {
+    InvalidAddressSpace { addr_space: &'a str, cause: &'a str, err: ParseIntError },
+    InvalidBits { kind: &'a str, bit: &'a str, cause: &'a str, err: ParseIntError },
+    MissingAlignment { cause: &'a str },
+    InvalidAlignment { cause: &'a str, err: String },
+    InconsistentTargetArchitecture { dl: &'a str, target: &'a str },
+    InconsistentTargetPointerWidth { pointer_size: u64, target: u32 },
+    InvalidBitsSize { err: String },
+}
+
 impl TargetDataLayout {
-    pub fn parse(target: &Target) -> Result<TargetDataLayout, String> {
+    pub fn parse<'a>(target: &'a Target) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
         // Parse an address space index from a string.
-        let parse_address_space = |s: &str, cause: &str| {
+        let parse_address_space = |s: &'a str, cause: &'a str| {
             s.parse::<u32>().map(AddressSpace).map_err(|err| {
-                format!("invalid address space `{}` for `{}` in \"data-layout\": {}", s, cause, err)
+                TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err }
             })
         };
 
         // Parse a bit count from a string.
-        let parse_bits = |s: &str, kind: &str, cause: &str| {
-            s.parse::<u64>().map_err(|err| {
-                format!("invalid {} `{}` for `{}` in \"data-layout\": {}", kind, s, cause, err)
+        let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| {
+            s.parse::<u64>().map_err(|err| TargetDataLayoutErrors::InvalidBits {
+                kind,
+                bit: s,
+                cause,
+                err,
             })
         };
 
         // Parse a size string.
-        let size = |s: &str, cause: &str| parse_bits(s, "size", cause).map(Size::from_bits);
+        let size = |s: &'a str, cause: &'a str| parse_bits(s, "size", cause).map(Size::from_bits);
 
         // Parse an alignment string.
-        let align = |s: &[&str], cause: &str| {
+        let align = |s: &[&'a str], cause: &'a str| {
             if s.is_empty() {
-                return Err(format!("missing alignment for `{}` in \"data-layout\"", cause));
+                return Err(TargetDataLayoutErrors::MissingAlignment { cause });
             }
             let align_from_bits = |bits| {
-                Align::from_bits(bits).map_err(|err| {
-                    format!("invalid alignment for `{}` in \"data-layout\": {}", cause, err)
-                })
+                Align::from_bits(bits)
+                    .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err })
             };
             let abi = parse_bits(s[0], "alignment", cause)?;
             let pref = s.get(1).map_or(Ok(abi), |pref| parse_bits(pref, "alignment", cause))?;
@@ -158,25 +170,24 @@ pub fn parse(target: &Target) -> Result<TargetDataLayout, String> {
 
         // Perform consistency checks against the Target information.
         if dl.endian != target.endian {
-            return Err(format!(
-                "inconsistent target specification: \"data-layout\" claims \
-                 architecture is {}-endian, while \"target-endian\" is `{}`",
-                dl.endian.as_str(),
-                target.endian.as_str(),
-            ));
+            return Err(TargetDataLayoutErrors::InconsistentTargetArchitecture {
+                dl: dl.endian.as_str(),
+                target: target.endian.as_str(),
+            });
         }
 
         let target_pointer_width: u64 = target.pointer_width.into();
         if dl.pointer_size.bits() != target_pointer_width {
-            return Err(format!(
-                "inconsistent target specification: \"data-layout\" claims \
-                 pointers are {}-bit, while \"target-pointer-width\" is `{}`",
-                dl.pointer_size.bits(),
-                target.pointer_width
-            ));
+            return Err(TargetDataLayoutErrors::InconsistentTargetPointerWidth {
+                pointer_size: dl.pointer_size.bits(),
+                target: target.pointer_width,
+            });
         }
 
-        dl.c_enum_min_size = Integer::from_size(Size::from_bits(target.c_enum_min_bits))?;
+        dl.c_enum_min_size = match Integer::from_size(Size::from_bits(target.c_enum_min_bits)) {
+            Ok(bits) => bits,
+            Err(err) => return Err(TargetDataLayoutErrors::InvalidBitsSize { err }),
+        };
 
         Ok(dl)
     }
@@ -1130,7 +1141,7 @@ pub enum TagEncoding {
 
     /// Niche (values invalid for a type) encoding the discriminant:
     /// Discriminant and variant index coincide.
-    /// The variant `dataful_variant` contains a niche at an arbitrary
+    /// The variant `untagged_variant` contains a niche at an arbitrary
     /// offset (field `tag_field` of the enum), which for a variant with
     /// discriminant `d` is set to
     /// `(d - niche_variants.start).wrapping_add(niche_start)`.
@@ -1139,7 +1150,7 @@ pub enum TagEncoding {
     /// `None` has a null pointer for the second tuple field, and
     /// `Some` is the identity function (with a non-null reference).
     Niche {
-        dataful_variant: VariantIdx,
+        untagged_variant: VariantIdx,
         niche_variants: RangeInclusive<VariantIdx>,
         niche_start: u128,
     },
index d03f959076de0c0ab5fe7691c1f70daf5756d2ab..0af599916a999429b33f434b2ad50575b7498401 100644 (file)
@@ -146,7 +146,8 @@ fn check_consistency(&self, triple: &str) {
         if self.position_independent_executables && !triple.ends_with("-linuxkernel") {
             assert_eq!(self.relocation_model, RelocModel::Pic);
         }
-        if self.relocation_model == RelocModel::Pic {
+        // The UEFI targets do not support dynamic linking but still require PIC (#101377).
+        if self.relocation_model == RelocModel::Pic && self.os != "uefi" {
             assert!(self.dynamic_linking || self.position_independent_executables);
         }
         if self.static_position_independent_executables {
index 250da03cbd2b656af8fa21df4a369f6a33c82f2d..99af7d85e1d0235313033f9ef4651362e3d263b6 100644 (file)
@@ -10,7 +10,7 @@
 // code runs in the same environment, no process separation is supported.
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy};
-use crate::spec::{RelocModel, StackProbeType, TargetOptions};
+use crate::spec::{StackProbeType, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     let mut base = super::msvc_base::opts();
@@ -47,7 +47,6 @@ pub fn opts() -> TargetOptions {
         stack_probes: StackProbeType::Call,
         singlethread: true,
         linker: Some("rust-lld".into()),
-        relocation_model: RelocModel::Static,
         ..base
     }
 }
index 1223c7ced7abcb9e04bdaeb1b879ec240092bcf7..98e93ad3fc5046fdd8b38c4f91bffed2ba49a8d4 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{Region, RegionVid, Term};
+use rustc_middle::ty::{Region, RegionVid};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 
@@ -612,7 +612,7 @@ pub fn is_of_param(&self, ty: Ty<'_>) -> bool {
     }
 
     fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
-        if let Term::Ty(ty) = p.term().skip_binder() {
+        if let Some(ty) = p.term().skip_binder().ty() {
             matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
         } else {
             false
index 26f8e7d34c6eac056f1b06a4563b0e7c33497906..08adbcbd410c679ac9c444831ab594185a14c0ae 100644 (file)
@@ -18,7 +18,7 @@
 /// obligations *could be* resolved if we wanted to.
 ///
 /// This also expects that `trait_ref` is fully normalized.
-pub fn codegen_fulfill_obligation<'tcx>(
+pub fn codegen_select_candidate<'tcx>(
     tcx: TyCtxt<'tcx>,
     (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
 ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
index 9b8bb9e36201c4b72dc9f857660a37cee7bcf64b..efdb1ace1399294c498313512c5ec1f0a554f68a 100644 (file)
@@ -1895,9 +1895,7 @@ fn report_similar_impl_candidates(
                         // FIXME(compiler-errors): This could be generalized, both to
                         // be more granular, and probably look past other `#[fundamental]`
                         // types, too.
-                        self.tcx
-                            .visibility(def.did())
-                            .is_accessible_from(body_id.owner.to_def_id(), self.tcx)
+                        self.tcx.visibility(def.did()).is_accessible_from(body_id.owner, self.tcx)
                     } else {
                         true
                     }
index b012073f7719d2d4270ea7363483b9c393b75fcb..ecbeb9d79b118923057e35e56b48e91f911e1de2 100644 (file)
@@ -25,8 +25,7 @@
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
     GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable,
-    ProjectionPredicate, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitable,
+    ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_session::Limit;
@@ -174,7 +173,7 @@ fn suggest_restricting_param_bound(
         &self,
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
-        proj_pred: Option<ty::PolyProjectionPredicate<'tcx>>,
+        associated_item: Option<(&'static str, Ty<'tcx>)>,
         body_id: hir::HirId,
     );
 
@@ -467,7 +466,7 @@ fn suggest_restricting_param_bound(
         &self,
         mut err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
-        proj_pred: Option<ty::PolyProjectionPredicate<'tcx>>,
+        associated_ty: Option<(&'static str, Ty<'tcx>)>,
         body_id: hir::HirId,
     ) {
         let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
@@ -604,21 +603,18 @@ fn suggest_restricting_param_bound(
                         trait_pred.print_modifiers_and_trait_path().to_string()
                     );
 
-                    if let Some(proj_pred) = proj_pred {
-                        let ProjectionPredicate { projection_ty, term } = proj_pred.skip_binder();
-                        let item = self.tcx.associated_item(projection_ty.item_def_id);
-
+                    if let Some((name, term)) = associated_ty {
                         // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err.
                         // That should be extracted into a helper function.
                         if constraint.ends_with('>') {
                             constraint = format!(
-                                "{}, {}={}>",
+                                "{}, {} = {}>",
                                 &constraint[..constraint.len() - 1],
-                                item.name,
+                                name,
                                 term
                             );
                         } else {
-                            constraint.push_str(&format!("<{}={}>", item.name, term));
+                            constraint.push_str(&format!("<{} = {}>", name, term));
                         }
                     }
 
@@ -648,7 +644,13 @@ fn suggest_restricting_param_bound(
                     ..
                 }) if !param_ty => {
                     // Missing generic type parameter bound.
-                    if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) {
+                    if suggest_arbitrary_trait_bound(
+                        self.tcx,
+                        generics,
+                        &mut err,
+                        trait_pred,
+                        associated_ty,
+                    ) {
                         return;
                     }
                 }
index 14e078096783e39239cdb186325910f9df61dd8b..40596078f0414f551e862d702cecd21df0ece38e 100644 (file)
@@ -971,7 +971,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
         specialization_graph_of: specialize::specialization_graph_provider,
         specializes: specialize::specializes,
-        codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
+        codegen_select_candidate: codegen::codegen_select_candidate,
         own_existential_vtable_entries,
         vtable_entries,
         vtable_trait_upcasting_coercion_new_vptr_slot,
index 398635674abcfd19a69c7de02f88af6787e209f9..8a65262a007230d0858e43ecf1a35f02512b3463 100644 (file)
@@ -32,6 +32,7 @@
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable};
+use rustc_middle::ty::DefIdTree;
 use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 
@@ -70,6 +71,8 @@ enum ProjectionCandidate<'tcx> {
 
     /// From an "impl" (or a "pseudo-impl" returned by select)
     Select(Selection<'tcx>),
+
+    ImplTraitInTrait(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>),
 }
 
 enum ProjectionCandidateSet<'tcx> {
@@ -552,7 +555,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                     )
                     .ok()
                     .flatten()
-                    .unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self)))
+                    .unwrap_or_else(|| ty.super_fold_with(self).into())
                 };
                 // For cases like #95134 we would like to catch overflows early
                 // otherwise they slip away away and cause ICE.
@@ -635,13 +638,18 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
 
     #[instrument(skip(self), level = "debug")]
     fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement {
+        let tcx = self.selcx.tcx();
+        if tcx.lazy_normalization() {
             constant
         } else {
             let constant = constant.super_fold_with(self);
-            debug!(?constant);
-            debug!("self.param_env: {:?}", self.param_env);
-            constant.eval(self.selcx.tcx(), self.param_env)
+            debug!(?constant, ?self.param_env);
+            with_replaced_escaping_bound_vars(
+                self.selcx.infcx(),
+                &mut self.universes,
+                constant,
+                |constant| constant.eval(tcx, self.param_env),
+            )
         }
     }
 
@@ -671,6 +679,41 @@ pub struct BoundVarReplacer<'me, 'tcx> {
     universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
 }
 
+/// Executes `f` on `value` after replacing all escaping bound variables with placeholders
+/// and then replaces these placeholders with the original bound variables in the result.
+///
+/// In most places, bound variables should be replaced right when entering a binder, making
+/// this function unnecessary. However, normalization currently does not do that, so we have
+/// to do this lazily.
+///
+/// You should not add any additional uses of this function, at least not without first
+/// discussing it with t-types.
+///
+/// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during
+/// normalization as well, at which point this function will be unnecessary and can be removed.
+pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: TypeFoldable<'tcx>>(
+    infcx: &'a InferCtxt<'a, 'tcx>,
+    universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
+    value: T,
+    f: impl FnOnce(T) -> R,
+) -> R {
+    if value.has_escaping_bound_vars() {
+        let (value, mapped_regions, mapped_types, mapped_consts) =
+            BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value);
+        let result = f(value);
+        PlaceholderReplacer::replace_placeholders(
+            infcx,
+            mapped_regions,
+            mapped_types,
+            mapped_consts,
+            universe_indices,
+            result,
+        )
+    } else {
+        f(value)
+    }
+}
+
 impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
     /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
     /// use a binding level above `universe_indices.len()`, we fail.
@@ -1225,6 +1268,8 @@ fn project<'cx, 'tcx>(
 
     let mut candidates = ProjectionCandidateSet::None;
 
+    assemble_candidate_for_impl_trait_in_trait(selcx, obligation, &mut candidates);
+
     // Make sure that the following procedures are kept in order. ParamEnv
     // needs to be first because it has highest priority, and Select checks
     // the return value of push_candidate which assumes it's ran at last.
@@ -1263,6 +1308,48 @@ fn project<'cx, 'tcx>(
     }
 }
 
+/// If the predicate's item is an `ImplTraitPlaceholder`, we do a select on the
+/// corresponding trait ref. If this yields an `impl`, then we're able to project
+/// to a concrete type, since we have an `impl`'s method  to provide the RPITIT.
+fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    candidate_set: &mut ProjectionCandidateSet<'tcx>,
+) {
+    let tcx = selcx.tcx();
+    if tcx.def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
+        let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id);
+        let trait_def_id = tcx.parent(trait_fn_def_id);
+        let trait_substs =
+            obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
+        // FIXME(named-returns): Binders
+        let trait_predicate =
+            ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs })
+                .to_poly_trait_predicate();
+
+        let _ =
+            selcx.infcx().commit_if_ok(|_| match selcx.select(&obligation.with(trait_predicate)) {
+                Ok(Some(super::ImplSource::UserDefined(data))) => {
+                    candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
+                    Ok(())
+                }
+                Ok(None) => {
+                    candidate_set.mark_ambiguous();
+                    return Err(());
+                }
+                Ok(Some(_)) => {
+                    // Don't know enough about the impl to provide a useful signature
+                    return Err(());
+                }
+                Err(e) => {
+                    debug!(error = ?e, "selection error");
+                    candidate_set.mark_error(e);
+                    return Err(());
+                }
+            });
+    }
+}
+
 /// The first thing we have to do is scan through the parameter
 /// environment to see whether there are any projection predicates
 /// there that can answer this question.
@@ -1425,6 +1512,11 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
     obligation: &ProjectionTyObligation<'tcx>,
     candidate_set: &mut ProjectionCandidateSet<'tcx>,
 ) {
+    // Can't assemble candidate from impl for RPITIT
+    if selcx.tcx().def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
+        return;
+    }
+
     // If we are resolving `<T as TraitRef<...>>::Item == Type`,
     // start out by selecting the predicate `T as TraitRef<...>`:
     let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx()));
@@ -1700,6 +1792,9 @@ fn confirm_candidate<'cx, 'tcx>(
         ProjectionCandidate::Select(impl_source) => {
             confirm_select_candidate(selcx, obligation, impl_source)
         }
+        ProjectionCandidate::ImplTraitInTrait(data) => {
+            confirm_impl_trait_in_trait_candidate(selcx, obligation, data)
+        }
     };
 
     // When checking for cycle during evaluation, we compare predicates with
@@ -2062,6 +2157,72 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     }
 }
 
+fn confirm_impl_trait_in_trait_candidate<'tcx>(
+    selcx: &mut SelectionContext<'_, 'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    data: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>,
+) -> Progress<'tcx> {
+    let tcx = selcx.tcx();
+    let mut obligations = data.nested;
+
+    let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id);
+    let Ok(leaf_def) = assoc_def(selcx, data.impl_def_id, trait_fn_def_id) else {
+        return Progress { term: tcx.ty_error().into(), obligations };
+    };
+    if !leaf_def.item.defaultness(tcx).has_value() {
+        return Progress { term: tcx.ty_error().into(), obligations };
+    }
+
+    let impl_fn_def_id = leaf_def.item.def_id;
+    let impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs);
+
+    let cause = ObligationCause::new(
+        obligation.cause.span,
+        obligation.cause.body_id,
+        super::ItemObligation(impl_fn_def_id),
+    );
+    let predicates = normalize_with_depth_to(
+        selcx,
+        obligation.param_env,
+        cause.clone(),
+        obligation.recursion_depth + 1,
+        tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs),
+        &mut obligations,
+    );
+    obligations.extend(std::iter::zip(predicates.predicates, predicates.spans).map(
+        |(pred, span)| {
+            Obligation::with_depth(
+                ObligationCause::new(
+                    obligation.cause.span,
+                    obligation.cause.body_id,
+                    if span.is_dummy() {
+                        super::ItemObligation(impl_fn_def_id)
+                    } else {
+                        super::BindingObligation(impl_fn_def_id, span)
+                    },
+                ),
+                obligation.recursion_depth + 1,
+                obligation.param_env,
+                pred,
+            )
+        },
+    ));
+
+    let ty = super::normalize_to(
+        selcx,
+        obligation.param_env,
+        cause.clone(),
+        tcx.bound_trait_impl_trait_tys(impl_fn_def_id)
+            .map_bound(|tys| {
+                tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.item_def_id])
+            })
+            .subst(tcx, impl_fn_substs),
+        &mut obligations,
+    );
+
+    Progress { term: ty.into(), obligations }
+}
+
 // Get obligations corresponding to the predicates from the where-clause of the
 // associated type itself.
 // Note: `feature(generic_associated_types)` is required to write such
index 61c556b726d6ce40a26317d9175d6e731bc378fa..f65fc5bad0d9184144b37fa1fe0a3a41d2f6611d 100644 (file)
@@ -6,7 +6,7 @@
 use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::error_reporting::InferCtxtExt;
-use crate::traits::project::needs_normalization;
+use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
 use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -283,11 +283,7 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                 let tcx = self.infcx.tcx;
                 let infcx = self.infcx;
                 let (data, mapped_regions, mapped_types, mapped_consts) =
-                    crate::traits::project::BoundVarReplacer::replace_bound_vars(
-                        infcx,
-                        &mut self.universes,
-                        data,
-                    );
+                    BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
                 let data = data.try_fold_with(self)?;
 
                 let mut orig_values = OriginalQueryValues::default();
@@ -313,8 +309,7 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                 debug!("QueryNormalizer: result = {:#?}", result);
                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
                 self.obligations.extend(obligations);
-
-                let res = crate::traits::project::PlaceholderReplacer::replace_placeholders(
+                let res = PlaceholderReplacer::replace_placeholders(
                     infcx,
                     mapped_regions,
                     mapped_types,
@@ -343,7 +338,13 @@ fn try_fold_const(
         constant: ty::Const<'tcx>,
     ) -> Result<ty::Const<'tcx>, Self::Error> {
         let constant = constant.try_super_fold_with(self)?;
-        Ok(constant.eval(self.infcx.tcx, self.param_env))
+        debug!(?constant, ?self.param_env);
+        Ok(crate::traits::project::with_replaced_escaping_bound_vars(
+            self.infcx,
+            &mut self.universes,
+            constant,
+            |constant| constant.eval(self.infcx.tcx, self.param_env),
+        ))
     }
 
     fn try_fold_mir_const(
index bb6009cb22a37b2df733bb9019e164eae8d5288b..9a571837e9f5a04521b7aeaa9553af7d18e41003 100644 (file)
@@ -129,9 +129,9 @@ pub fn predicate_obligations<'a, 'tcx>(
         }
         ty::PredicateKind::Projection(t) => {
             wf.compute_projection(t.projection_ty);
-            wf.compute(match t.term {
-                ty::Term::Ty(ty) => ty.into(),
-                ty::Term::Const(c) => c.into(),
+            wf.compute(match t.term.unpack() {
+                ty::TermKind::Ty(ty) => ty.into(),
+                ty::TermKind::Const(c) => c.into(),
             })
         }
         ty::PredicateKind::WellFormed(arg) => {
@@ -434,6 +434,7 @@ fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<
     }
 
     /// Pushes all the predicates needed to validate that `ty` is WF into `out`.
+    #[instrument(level = "debug", skip(self))]
     fn compute(&mut self, arg: GenericArg<'tcx>) {
         let mut walker = arg.walk();
         let param_env = self.param_env;
@@ -488,6 +489,8 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                 }
             };
 
+            debug!("wf bounds for ty={:?} ty.kind={:#?}", ty, ty.kind());
+
             match *ty.kind() {
                 ty::Bool
                 | ty::Char
index a77ea440aaaea90fb02f9d27c333a82eb8468c47..f0d8c240ea588bbcdde326ef58e5c240de00e5bc 100644 (file)
@@ -51,6 +51,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx ty::List<Ty
         | DefKind::AnonConst
         | DefKind::InlineConst
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::Field
         | DefKind::LifetimeParam
         | DefKind::GlobalAsm
index 661e413fc5b8170defb0d06724fc0b62710b4573..b55302de2a733891ad6d72010240747a68559acf 100644 (file)
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::traits::CodegenObligationError;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{
-    self, Binder, Instance, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
-};
+use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitable};
 use rustc_span::{sym, DUMMY_SP};
 use rustc_trait_selection::traits;
 use traits::{translate_substs, Reveal};
 
-use rustc_data_structures::sso::SsoHashSet;
-use std::collections::btree_map::Entry;
-use std::collections::BTreeMap;
-use std::ops::ControlFlow;
-
-// FIXME(#86795): `BoundVarsCollector` here should **NOT** be used
-// outside of `resolve_associated_item`. It's just to address #64494,
-// #83765, and #85848 which are creating bound types/regions that lose
-// their `Binder` *unintentionally*.
-// It's ideal to remove `BoundVarsCollector` and just use
-// `ty::Binder::*` methods but we use this stopgap until we figure out
-// the "real" fix.
-struct BoundVarsCollector<'tcx> {
-    binder_index: ty::DebruijnIndex,
-    vars: BTreeMap<u32, ty::BoundVariableKind>,
-    // We may encounter the same variable at different levels of binding, so
-    // this can't just be `Ty`
-    visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
-}
-
-impl<'tcx> BoundVarsCollector<'tcx> {
-    fn new() -> Self {
-        BoundVarsCollector {
-            binder_index: ty::INNERMOST,
-            vars: BTreeMap::new(),
-            visited: SsoHashSet::default(),
-        }
-    }
-
-    fn into_vars(self, tcx: TyCtxt<'tcx>) -> &'tcx ty::List<ty::BoundVariableKind> {
-        let max = self.vars.iter().map(|(k, _)| *k).max().unwrap_or(0);
-        for i in 0..max {
-            if let None = self.vars.get(&i) {
-                panic!("Unknown variable: {:?}", i);
-            }
-        }
-
-        tcx.mk_bound_variable_kinds(self.vars.into_iter().map(|(_, v)| v))
-    }
-}
-
-impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
-    type BreakTy = ();
-
-    fn visit_binder<T: TypeVisitable<'tcx>>(
-        &mut self,
-        t: &Binder<'tcx, T>,
-    ) -> ControlFlow<Self::BreakTy> {
-        self.binder_index.shift_in(1);
-        let result = t.super_visit_with(self);
-        self.binder_index.shift_out(1);
-        result
-    }
-
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if t.outer_exclusive_binder() < self.binder_index
-            || !self.visited.insert((self.binder_index, t))
-        {
-            return ControlFlow::CONTINUE;
-        }
-        match *t.kind() {
-            ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
-                match self.vars.entry(bound_ty.var.as_u32()) {
-                    Entry::Vacant(entry) => {
-                        entry.insert(ty::BoundVariableKind::Ty(bound_ty.kind));
-                    }
-                    Entry::Occupied(entry) => match entry.get() {
-                        ty::BoundVariableKind::Ty(_) => {}
-                        _ => bug!("Conflicting bound vars"),
-                    },
-                }
-            }
-
-            _ => (),
-        };
-
-        t.super_visit_with(self)
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match *r {
-            ty::ReLateBound(index, br) if index == self.binder_index => {
-                match self.vars.entry(br.var.as_u32()) {
-                    Entry::Vacant(entry) => {
-                        entry.insert(ty::BoundVariableKind::Region(br.kind));
-                    }
-                    Entry::Occupied(entry) => match entry.get() {
-                        ty::BoundVariableKind::Region(_) => {}
-                        _ => bug!("Conflicting bound vars"),
-                    },
-                }
-            }
-
-            _ => (),
-        };
-
-        r.super_visit_with(self)
-    }
-}
-
 fn resolve_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>,
@@ -201,19 +99,14 @@ fn resolve_associated_item<'tcx>(
 
     let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
 
-    // See FIXME on `BoundVarsCollector`.
-    let mut bound_vars_collector = BoundVarsCollector::new();
-    trait_ref.visit_with(&mut bound_vars_collector);
-    let trait_binder = ty::Binder::bind_with_vars(trait_ref, bound_vars_collector.into_vars(tcx));
-    let vtbl = match tcx.codegen_fulfill_obligation((param_env, trait_binder)) {
+    let vtbl = match tcx.codegen_select_candidate((param_env, ty::Binder::dummy(trait_ref))) {
         Ok(vtbl) => vtbl,
         Err(CodegenObligationError::Ambiguity) => {
             let reported = tcx.sess.delay_span_bug(
                 tcx.def_span(trait_item_id),
                 &format!(
-                    "encountered ambiguity selecting `{:?}` during codegen, presuming due to \
+                    "encountered ambiguity selecting `{trait_ref:?}` during codegen, presuming due to \
                      overflow or prior type error",
-                    trait_binder
                 ),
             );
             return Err(reported);
index 5488bca8f471dd32e04b8456bfab6b5e983b4ea0..da30344ef7ec090de63092ac9c795f3c1cf42c68 100644 (file)
@@ -23,6 +23,9 @@
 pub use codec::*;
 pub use sty::*;
 
+/// Needed so we can use #[derive(HashStable_Generic)]
+pub trait HashStableContext {}
+
 pub trait Interner {
     type AdtDef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
     type SubstsRef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
@@ -295,6 +298,7 @@ pub struct TypeFlags: u32 {
     /// is the outer fn.
     ///
     /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index
+    #[derive(HashStable_Generic)]
     pub struct DebruijnIndex {
         DEBUG_FORMAT = "DebruijnIndex({})",
         const INNERMOST = 0,
@@ -366,7 +370,7 @@ pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(Encodable, Decodable)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum IntTy {
     Isize,
     I8,
@@ -413,7 +417,7 @@ pub fn normalize(&self, target_width: u32) -> Self {
 }
 
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)]
-#[derive(Encodable, Decodable)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum UintTy {
     Usize,
     U8,
@@ -460,7 +464,7 @@ pub fn normalize(&self, target_width: u32) -> Self {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(Encodable, Decodable)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum FloatTy {
     F32,
     F64,
@@ -597,7 +601,7 @@ fn tag() -> &'static str {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash)]
+#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash, HashStable_Generic)]
 #[rustc_pass_by_value]
 pub enum Variance {
     Covariant,     // T<A> <: T<B> iff A <: B -- e.g., function return type
@@ -666,30 +670,6 @@ pub fn xform(self, v: Variance) -> Variance {
     }
 }
 
-impl<CTX> HashStable<CTX> for DebruijnIndex {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        self.as_u32().hash_stable(ctx, hasher);
-    }
-}
-
-impl<CTX> HashStable<CTX> for IntTy {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        discriminant(self).hash_stable(ctx, hasher);
-    }
-}
-
-impl<CTX> HashStable<CTX> for UintTy {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        discriminant(self).hash_stable(ctx, hasher);
-    }
-}
-
-impl<CTX> HashStable<CTX> for FloatTy {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        discriminant(self).hash_stable(ctx, hasher);
-    }
-}
-
 impl<CTX> HashStable<CTX> for InferTy {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         use InferTy::*;
@@ -703,12 +683,6 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
     }
 }
 
-impl<CTX> HashStable<CTX> for Variance {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        discriminant(self).hash_stable(ctx, hasher);
-    }
-}
-
 impl fmt::Debug for IntVarValue {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
@@ -811,6 +785,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     /// declared, but a type name in a non-zero universe is a placeholder
     /// type -- an idealized representative of "types in general" that we
     /// use for checking generic functions.
+    #[derive(HashStable_Generic)]
     pub struct UniverseIndex {
         DEBUG_FORMAT = "U{}",
     }
@@ -850,9 +825,3 @@ pub fn cannot_name(self, other: UniverseIndex) -> bool {
         self.private < other.private
     }
 }
-
-impl<CTX> HashStable<CTX> for UniverseIndex {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        self.private.hash_stable(ctx, hasher);
-    }
-}
index 74737e30bb4d35a78c3adb1214276ba0bc2fb2eb..26e48d2d2147e9370433db2a081b56255e5e75ad 100644 (file)
@@ -3,7 +3,6 @@
 use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
 use std::{fmt, hash};
 
-use crate::DebruijnIndex;
 use crate::FloatTy;
 use crate::IntTy;
 use crate::Interner;
@@ -11,6 +10,7 @@
 use crate::TyEncoder;
 use crate::UintTy;
 use crate::UniverseIndex;
+use crate::{DebruijnIndex, HashStableContext};
 
 use self::RegionKind::*;
 use self::TyKind::*;
@@ -774,7 +774,7 @@ fn decode(d: &mut D) -> Self {
 
 // This is not a derived impl because a derive would require `I: HashStable`
 #[allow(rustc::usage_of_ty_tykind)]
-impl<CTX, I: Interner> HashStable<CTX> for TyKind<I>
+impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for TyKind<I>
 where
     I::AdtDef: HashStable<CTX>,
     I::DefId: HashStable<CTX>,
@@ -1286,7 +1286,7 @@ fn decode(d: &mut D) -> Self {
 }
 
 // This is not a derived impl because a derive would require `I: HashStable`
-impl<CTX, I: Interner> HashStable<CTX> for RegionKind<I>
+impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for RegionKind<I>
 where
     I::EarlyBoundRegion: HashStable<CTX>,
     I::BoundRegion: HashStable<CTX>,
index 14f04ddc8688bc2ae9b44b7ffa7e6e9ec61812c2..d9789d5aaf0312e9be5018dc95e1f5810d77c410 100644 (file)
@@ -1183,11 +1183,11 @@ fn add_predicates_for_ast_type_binding(
                 // `<T as Iterator>::Item = u32`
                 let assoc_item_def_id = projection_ty.skip_binder().item_def_id;
                 let def_kind = tcx.def_kind(assoc_item_def_id);
-                match (def_kind, term) {
-                    (hir::def::DefKind::AssocTy, ty::Term::Ty(_))
-                    | (hir::def::DefKind::AssocConst, ty::Term::Const(_)) => (),
+                match (def_kind, term.unpack()) {
+                    (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_))
+                    | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (),
                     (_, _) => {
-                        let got = if let ty::Term::Ty(_) = term { "type" } else { "constant" };
+                        let got = if let Some(_) = term.ty() { "type" } else { "constant" };
                         let expected = def_kind.descr(assoc_item_def_id);
                         tcx.sess
                             .struct_span_err(
@@ -1375,9 +1375,11 @@ trait here instead: `trait NewTrait: {} {{}}`",
                         let pred = bound_predicate.rebind(pred);
                         // A `Self` within the original bound will be substituted with a
                         // `trait_object_dummy_self`, so check for that.
-                        let references_self = match pred.skip_binder().term {
-                            ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
-                            ty::Term::Const(c) => c.ty().walk().any(|arg| arg == dummy_self.into()),
+                        let references_self = match pred.skip_binder().term.unpack() {
+                            ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
+                            ty::TermKind::Const(c) => {
+                                c.ty().walk().any(|arg| arg == dummy_self.into())
+                            }
                         };
 
                         // If the projection output contains `Self`, force the user to
@@ -2358,7 +2360,7 @@ pub fn res_to_ty(
 
         let span = path.span;
         match path.res {
-            Res::Def(DefKind::OpaqueTy, did) => {
+            Res::Def(DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder, did) => {
                 // Check for desugared `impl Trait`.
                 assert!(ty::is_impl_trait_defn(tcx, did).is_none());
                 let item_segment = path.segments.split_last().unwrap();
@@ -2625,13 +2627,13 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself));
                 self.res_to_ty(opt_self_ty, path, false)
             }
-            hir::TyKind::OpaqueDef(item_id, lifetimes) => {
+            hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
                 let opaque_ty = tcx.hir().item(item_id);
                 let def_id = item_id.def_id.to_def_id();
 
                 match opaque_ty.kind {
                     hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
-                        self.impl_trait_ty_to_ty(def_id, lifetimes, origin)
+                        self.impl_trait_ty_to_ty(def_id, lifetimes, origin, in_trait)
                     }
                     ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
                 }
@@ -2695,11 +2697,13 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
         result_ty
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
     fn impl_trait_ty_to_ty(
         &self,
         def_id: DefId,
         lifetimes: &[hir::GenericArg<'_>],
         origin: OpaqueTyOrigin,
+        in_trait: bool,
     ) -> Ty<'tcx> {
         debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes);
         let tcx = self.tcx();
@@ -2743,9 +2747,7 @@ fn impl_trait_ty_to_ty(
         });
         debug!("impl_trait_ty_to_ty: substs={:?}", substs);
 
-        let ty = tcx.mk_opaque(def_id, substs);
-        debug!("impl_trait_ty_to_ty: {}", ty);
-        ty
+        if in_trait { tcx.mk_projection(def_id, substs) } else { tcx.mk_opaque(def_id, substs) }
     }
 
     pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
@@ -2939,8 +2941,9 @@ fn validate_late_bound_regions(
                 // though we can easily give a hint that ought to be
                 // relevant.
                 err.note(
-                    "lifetimes appearing in an associated type are not considered constrained",
+                    "lifetimes appearing in an associated or opaque type are not considered constrained",
                 );
+                err.note("consider introducing a named lifetime parameter");
             }
 
             err.emit();
index bc3fec6e7d66a371dc57dfb0fd8a0039a30838fa..55cbaf71e7cfdd9b8f49a257fde93e89318e6df1 100644 (file)
@@ -4,6 +4,7 @@
 
 use crate::astconv::AstConv;
 use crate::rustc_middle::ty::subst::Subst;
+use hir::def::DefKind;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
@@ -680,9 +681,18 @@ fn deduce_future_output_from_obligations(
                 .map(|e| e.map_bound(|e| *e).transpose_tuple2())
                 .find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0))?,
             ty::Error(_) => return None,
+            ty::Projection(proj)
+                if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
+            {
+                self.tcx
+                    .bound_explicit_item_bounds(proj.item_def_id)
+                    .transpose_iter()
+                    .map(|e| e.map_bound(|e| *e).transpose_tuple2())
+                    .find_map(|(p, s)| get_future_output(p.subst(self.tcx, proj.substs), s.0))?
+            }
             _ => span_bug!(
                 self.tcx.def_span(expr_def_id),
-                "async fn generator return type not an inference variable"
+                "async fn generator return type not an inference variable: {ret_ty}"
             ),
         };
 
index b6bc244d2b14447a5c3d4a96c942a87f8ca0f58a..13a96df77b69d51699496629a0e0d9731540fa90 100644 (file)
@@ -1,18 +1,22 @@
 use super::potentially_plural_count;
 use crate::errors::LifetimesOrBoundsMismatchOnTrait;
-use rustc_data_structures::fx::FxHashSet;
+use hir::def_id::DefId;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit;
 use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{self, TyCtxtInferExt};
 use rustc_infer::traits::util;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::{self, DefIdTree};
+use rustc_middle::ty::{
+    self, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
+};
 use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
 use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
@@ -64,10 +68,7 @@ pub(crate) fn compare_impl_method<'tcx>(
         return;
     }
 
-    if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
-    {
-        return;
-    }
+    tcx.ensure().compare_predicates_and_trait_impl_trait_tys(impl_m.def_id);
 }
 
 /// This function is best explained by example. Consider a trait:
@@ -136,13 +137,15 @@ pub(crate) fn compare_impl_method<'tcx>(
 ///
 /// Finally we register each of these predicates as an obligation and check that
 /// they hold.
-fn compare_predicate_entailment<'tcx>(
+pub(super) fn compare_predicates_and_trait_impl_trait_tys<'tcx>(
     tcx: TyCtxt<'tcx>,
-    impl_m: &ty::AssocItem,
-    impl_m_span: Span,
-    trait_m: &ty::AssocItem,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-) -> Result<(), ErrorGuaranteed> {
+    def_id: DefId,
+) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
+    let impl_m = tcx.opt_associated_item(def_id).unwrap();
+    let impl_m_span = tcx.def_span(def_id);
+    let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
+    let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
+
     let trait_to_impl_substs = impl_trait_ref.substs;
 
     // This node-id should be used for the `body_id` field on each
@@ -161,6 +164,7 @@ fn compare_predicate_entailment<'tcx>(
             kind: impl_m.kind,
         },
     );
+    let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
 
     // Create mapping from impl to placeholder.
     let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
@@ -266,6 +270,13 @@ fn compare_predicate_entailment<'tcx>(
 
         let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
         let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
+        let mut collector =
+            ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
+        // FIXME(RPITIT): This should only be needed on the output type, but
+        // RPITIT placeholders shouldn't show up anywhere except for there,
+        // so I think this is fine.
+        let trait_sig = trait_sig.fold_with(&mut collector);
+
         // Next, add all inputs and output as well-formed tys. Importantly,
         // we have to do this before normalization, since the normalized ty may
         // not contain the input parameters. See issue #87748.
@@ -284,12 +295,26 @@ fn compare_predicate_entailment<'tcx>(
         // type would be more appropriate. In other places we have a `Vec<Span>`
         // corresponding to their `Vec<Predicate>`, but we don't have that here.
         // Fixing this would improve the output of test `issue-83765.rs`.
-        let sub_result = infcx
+        let mut result = infcx
             .at(&cause, param_env)
             .sup(trait_fty, impl_fty)
             .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok));
 
-        if let Err(terr) = sub_result {
+        // HACK(RPITIT): #101614. When we are trying to infer the hidden types for
+        // RPITITs, we need to equate the output tys instead of just subtyping. If
+        // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes
+        // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets
+        // fixed up to `ReEmpty`, and which is certainly not what we want.
+        if trait_fty.has_infer_types() {
+            result = result.and_then(|()| {
+                infcx
+                    .at(&cause, param_env)
+                    .eq(trait_sig.output(), impl_sig.output())
+                    .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok))
+            });
+        }
+
+        if let Err(terr) = result {
             debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
 
             let (impl_err_span, trait_err_span) =
@@ -411,10 +436,116 @@ fn compare_predicate_entailment<'tcx>(
             &outlives_environment,
         );
 
-        Ok(())
+        let mut collected_tys = FxHashMap::default();
+        for (def_id, (ty, substs)) in collector.types {
+            match infcx.fully_resolve(ty) {
+                Ok(ty) => {
+                    // `ty` contains free regions that we created earlier while liberating the
+                    // trait fn signature.  However, projection normalization expects `ty` to
+                    // contains `def_id`'s early-bound regions.
+                    let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
+                    debug!(?id_substs, ?substs);
+                    let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> = substs
+                        .iter()
+                        .enumerate()
+                        .map(|(index, arg)| (arg, id_substs[index]))
+                        .collect();
+                    debug!(?map);
+
+                    let ty = tcx.fold_regions(ty, |region, _| {
+                        if let ty::ReFree(_) = region.kind() {
+                            map[&region.into()].expect_region()
+                        } else {
+                            region
+                        }
+                    });
+                    debug!(%ty);
+                    collected_tys.insert(def_id, ty);
+                }
+                Err(err) => {
+                    tcx.sess.delay_span_bug(
+                        return_span,
+                        format!("could not fully resolve: {ty} => {err:?}"),
+                    );
+                    collected_tys.insert(def_id, tcx.ty_error());
+                }
+            }
+        }
+
+        Ok(&*tcx.arena.alloc(collected_tys))
     })
 }
 
+struct ImplTraitInTraitCollector<'a, 'tcx> {
+    ocx: &'a ObligationCtxt<'a, 'tcx>,
+    types: FxHashMap<DefId, (Ty<'tcx>, ty::SubstsRef<'tcx>)>,
+    span: Span,
+    param_env: ty::ParamEnv<'tcx>,
+    body_id: hir::HirId,
+}
+
+impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> {
+    fn new(
+        ocx: &'a ObligationCtxt<'a, 'tcx>,
+        span: Span,
+        param_env: ty::ParamEnv<'tcx>,
+        body_id: hir::HirId,
+    ) -> Self {
+        ImplTraitInTraitCollector { ocx, types: FxHashMap::default(), span, param_env, body_id }
+    }
+}
+
+impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
+    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+        self.ocx.infcx.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if let ty::Projection(proj) = ty.kind()
+            && self.tcx().def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
+        {
+            if let Some((ty, _)) = self.types.get(&proj.item_def_id) {
+                return *ty;
+            }
+            //FIXME(RPITIT): Deny nested RPITIT in substs too
+            if proj.substs.has_escaping_bound_vars() {
+                bug!("FIXME(RPITIT): error here");
+            }
+            // Replace with infer var
+            let infer_ty = self.ocx.infcx.next_ty_var(TypeVariableOrigin {
+                span: self.span,
+                kind: TypeVariableOriginKind::MiscVariable,
+            });
+            self.types.insert(proj.item_def_id, (infer_ty, proj.substs));
+            // Recurse into bounds
+            for pred in self.tcx().bound_explicit_item_bounds(proj.item_def_id).transpose_iter() {
+                let pred_span = pred.0.1;
+
+                let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx(), proj.substs);
+                let pred = pred.fold_with(self);
+                let pred = self.ocx.normalize(
+                    ObligationCause::misc(self.span, self.body_id),
+                    self.param_env,
+                    pred,
+                );
+
+                self.ocx.register_obligation(traits::Obligation::new(
+                    ObligationCause::new(
+                        self.span,
+                        self.body_id,
+                        ObligationCauseCode::BindingObligation(proj.item_def_id, pred_span),
+                    ),
+                    self.param_env,
+                    pred,
+                ));
+            }
+            infer_ty
+        } else {
+            ty.super_fold_with(self)
+        }
+    }
+}
+
 fn check_region_bounds_on_impl_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: &ty::AssocItem,
@@ -1191,7 +1322,7 @@ pub(crate) fn compare_ty_impl<'tcx>(
     })();
 }
 
-/// The equivalent of [compare_predicate_entailment], but for associated types
+/// The equivalent of [compare_predicates_and_trait_impl_trait_tys], but for associated types
 /// instead of associated functions.
 fn compare_type_predicate_entailment<'tcx>(
     tcx: TyCtxt<'tcx>,
index d078252ebd4e2fadf6b9ce12eb9ac305706c7c61..e1d55ff82cbadf12320e977c2152934f32302092 100644 (file)
@@ -375,7 +375,7 @@ fn suggest_compatible_variants(
 
                     let field_is_local = sole_field.did.is_local();
                     let field_is_accessible =
-                        sole_field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx)
+                        sole_field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
                         // Skip suggestions for unstable public fields (for example `Pin::pointer`)
                         && matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked);
 
index e4141647d7d2df66fd8b99a8e83ce89a68def8f9..21392001364138f601c5c42b30aa6a8c9a4a7c1b 100644 (file)
@@ -1305,31 +1305,30 @@ fn check_expr_array(
     }
 
     fn suggest_array_len(&self, expr: &'tcx hir::Expr<'tcx>, array_len: u64) {
-        if let Some(parent_hir_id) = self.tcx.hir().find_parent_node(expr.hir_id) {
-            let ty = match self.tcx.hir().find(parent_hir_id) {
-                Some(
-                    hir::Node::Local(hir::Local { ty: Some(ty), .. })
-                    | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. }),
-                ) => Some(ty),
-                _ => None,
-            };
-            if let Some(ty) = ty
-                && let hir::TyKind::Array(_, length) = ty.kind
-                && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
-                && let Some(span) = self.tcx.hir().opt_span(hir_id)
-            {
-                match self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) {
-                    Some(mut err) => {
-                        err.span_suggestion(
-                            span,
-                            "consider specifying the array length",
-                            array_len,
-                            Applicability::MaybeIncorrect,
-                        );
-                        err.emit();
-                    }
-                    None => ()
+        let parent_node = self.tcx.hir().parent_iter(expr.hir_id).find(|(_, node)| {
+            !matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::AddrOf(..), .. }))
+        });
+        let Some((_,
+            hir::Node::Local(hir::Local { ty: Some(ty), .. })
+            | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. }))
+        ) = parent_node else {
+            return
+        };
+        if let hir::TyKind::Array(_, length) = ty.peel_refs().kind
+            && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
+            && let Some(span) = self.tcx.hir().opt_span(hir_id)
+        {
+            match self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) {
+                Some(mut err) => {
+                    err.span_suggestion(
+                        span,
+                        "consider specifying the array length",
+                        array_len,
+                        Applicability::MaybeIncorrect,
+                    );
+                    err.emit();
                 }
+                None => ()
             }
         }
     }
@@ -1729,9 +1728,7 @@ fn check_expr_struct_fields(
             let private_fields: Vec<&ty::FieldDef> = variant
                 .fields
                 .iter()
-                .filter(|field| {
-                    !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
-                })
+                .filter(|field| !field.vis.is_accessible_from(tcx.parent_module(expr_id), tcx))
                 .collect();
 
             if !private_fields.is_empty() {
@@ -2343,7 +2340,7 @@ fn ban_nonexisting_field(
             if let ty::Adt(def, _) = output_ty.kind() && !def.is_enum() {
                 def.non_enum_variant().fields.iter().any(|field| {
                     field.ident(self.tcx) == ident
-                        && field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx)
+                        && field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
                 })
             } else if let ty::Tuple(tys) = output_ty.kind()
                 && let Ok(idx) = ident.as_str().parse::<usize>()
index c59638f5d6f9f77a6a98c0c4b6103342a0cad91b..a40478db96901719f5392fff5481c634f393aaaa 100644 (file)
@@ -409,7 +409,7 @@ pub(in super::super) fn normalize_op_associated_types_in_as_infer_ok<T>(
                     rhs_span: opt_input_expr.map(|expr| expr.span),
                     is_lit: opt_input_expr
                         .map_or(false, |expr| matches!(expr.kind, ExprKind::Lit(_))),
-                    output_pred: None,
+                    output_ty: None,
                 },
             ),
             self.param_env,
@@ -495,13 +495,10 @@ pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
 
     pub fn to_const(&self, ast_c: &hir::AnonConst) -> ty::Const<'tcx> {
         let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
+        let span = self.tcx.hir().span(ast_c.hir_id);
         let c = ty::Const::from_anon_const(self.tcx, const_def_id);
-        self.register_wf_obligation(
-            c.into(),
-            self.tcx.hir().span(ast_c.hir_id),
-            ObligationCauseCode::WellFormed(None),
-        );
-        c
+        self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
+        self.normalize_associated_types_in(span, c)
     }
 
     pub fn const_arg_to_const(
index 73dd7122e269a8008e07220447c277ec3c3e7996..4fa33da50c9e0b1e2e3dbc52dcf4646bd55ff4a9 100644 (file)
@@ -95,8 +95,7 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
         | sym::type_id
         | sym::likely
         | sym::unlikely
-        | sym::ptr_guaranteed_eq
-        | sym::ptr_guaranteed_ne
+        | sym::ptr_guaranteed_cmp
         | sym::minnumf32
         | sym::minnumf64
         | sym::maxnumf32
@@ -302,8 +301,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool]))
             }
 
-            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
-                (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
+            sym::ptr_guaranteed_cmp => {
+                (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.u8)
             }
 
             sym::const_allocate => {
index 721ebba6514779066e486d8214ebe3ab2bd76aea..d8fe63dbf084aee940e8bfb7a283a647c6e6b754 100644 (file)
@@ -333,10 +333,10 @@ fn check_asm_operand_type(
                         let mut err = lint.build(msg);
                         err.span_label(expr.span, "for this argument");
                         err.help(&format!(
-                            "use the `{suggested_modifier}` modifier to have the register formatted as `{suggested_result}`",
+                            "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`",
                         ));
                         err.help(&format!(
-                            "or use the `{default_modifier}` modifier to keep the default formatting of `{default_result}`",
+                            "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`",
                         ));
                         err.emit();
                     },
index a9071cd1fd949efe57c2bfd122425fb0b5277dd7..249e9c66ba72ad958334b0613d826abefdaee4a7 100644 (file)
 use rustc_infer::infer::{self, InferOk};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{
-    self, AssocKind, DefIdTree, GenericParamDefKind, ProjectionPredicate, ProjectionTy, Term,
-    ToPredicate, Ty, TypeVisitable,
-};
+use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
@@ -337,22 +334,7 @@ pub(super) fn obligation_for_op_method(
 
         // Construct an obligation
         let poly_trait_ref = ty::Binder::dummy(trait_ref);
-        let opt_output_ty =
-            expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty));
-        let opt_output_assoc_item = self.tcx.associated_items(trait_def_id).find_by_name_and_kind(
-            self.tcx,
-            Ident::from_str("Output"),
-            AssocKind::Type,
-            trait_def_id,
-        );
-        let output_pred =
-            opt_output_ty.zip(opt_output_assoc_item).map(|(output_ty, output_assoc_item)| {
-                ty::Binder::dummy(ty::PredicateKind::Projection(ProjectionPredicate {
-                    projection_ty: ProjectionTy { substs, item_def_id: output_assoc_item.def_id },
-                    term: Term::Ty(output_ty),
-                }))
-                .to_predicate(self.tcx)
-            });
+        let output_ty = expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty));
 
         (
             traits::Obligation::new(
@@ -363,7 +345,7 @@ pub(super) fn obligation_for_op_method(
                         rhs_span: opt_input_expr.map(|expr| expr.span),
                         is_lit: opt_input_expr
                             .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
-                        output_pred,
+                        output_ty,
                     },
                 ),
                 self.param_env,
@@ -518,7 +500,7 @@ fn construct_obligation_for_trait(
                     rhs_span: opt_input_expr.map(|expr| expr.span),
                     is_lit: opt_input_expr
                         .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
-                    output_pred: None,
+                    output_ty: None,
                 },
             )
         } else {
index 124ac5c24fa5cef0ae58199d2318a92a98b12446..8065b848ad6f88c6399a5c6f0f569b032223dca3 100644 (file)
@@ -1161,7 +1161,7 @@ fn suggest_field_call(
             _ => None,
         });
         if let Some((field, field_ty)) = field_receiver {
-            let scope = tcx.parent_module(self.body_id).to_def_id();
+            let scope = tcx.parent_module(self.body_id);
             let is_accessible = field.vis.is_accessible_from(scope, tcx);
 
             if is_accessible {
index 69eb34b5f802d25b6f5073377be737bf91893b7f..8811b38fc555afb364efbaa12868cebbb67c9adf 100644 (file)
 use crate::util::common::indenter;
 
 use self::coercion::DynamicCoerceMany;
+use self::compare_method::compare_predicates_and_trait_impl_trait_tys;
 use self::region::region_scope_tree;
 pub use self::Expectation::*;
 
@@ -249,6 +250,7 @@ pub fn provide(providers: &mut Providers) {
         used_trait_imports,
         check_mod_item_types,
         region_scope_tree,
+        compare_predicates_and_trait_impl_trait_tys,
         ..*providers
     };
 }
index 0d9dbb5bc11c24ece1ef00c329fff37c1cf5a55f..4754717c29aba777494a494f9822e8f7b9cfdad9 100644 (file)
@@ -11,9 +11,8 @@
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
-use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
-};
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -22,8 +21,6 @@
 use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
 use rustc_type_ir::sty::TyKind::*;
 
-use std::ops::ControlFlow;
-
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Checks a `a <op>= b`
     pub fn check_binop_assign(
@@ -313,8 +310,11 @@ fn check_overloaded_binop(
             // error types are considered "builtin"
             Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(),
             Err(errors) => {
-                let source_map = self.tcx.sess.source_map();
-                let (mut err, missing_trait, use_output) = match is_assign {
+                let (_, trait_def_id) =
+                    lang_item_for_op(self.tcx, Op::Binary(op, is_assign), op.span);
+                let missing_trait = trait_def_id
+                    .map(|def_id| with_no_trimmed_paths!(self.tcx.def_path_str(def_id)));
+                let (mut err, output_def_id) = match is_assign {
                     IsAssign::Yes => {
                         let mut err = struct_span_err!(
                             self.tcx.sess,
@@ -328,112 +328,63 @@ fn check_overloaded_binop(
                             lhs_expr.span,
                             format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty),
                         );
-                        let missing_trait = match op.node {
-                            hir::BinOpKind::Add => Some("std::ops::AddAssign"),
-                            hir::BinOpKind::Sub => Some("std::ops::SubAssign"),
-                            hir::BinOpKind::Mul => Some("std::ops::MulAssign"),
-                            hir::BinOpKind::Div => Some("std::ops::DivAssign"),
-                            hir::BinOpKind::Rem => Some("std::ops::RemAssign"),
-                            hir::BinOpKind::BitAnd => Some("std::ops::BitAndAssign"),
-                            hir::BinOpKind::BitXor => Some("std::ops::BitXorAssign"),
-                            hir::BinOpKind::BitOr => Some("std::ops::BitOrAssign"),
-                            hir::BinOpKind::Shl => Some("std::ops::ShlAssign"),
-                            hir::BinOpKind::Shr => Some("std::ops::ShrAssign"),
-                            _ => None,
-                        };
                         self.note_unmet_impls_on_type(&mut err, errors);
-                        (err, missing_trait, false)
+                        (err, None)
                     }
                     IsAssign::No => {
-                        let (message, missing_trait, use_output) = match op.node {
-                            hir::BinOpKind::Add => (
-                                format!("cannot add `{rhs_ty}` to `{lhs_ty}`"),
-                                Some("std::ops::Add"),
-                                true,
-                            ),
-                            hir::BinOpKind::Sub => (
-                                format!("cannot subtract `{rhs_ty}` from `{lhs_ty}`"),
-                                Some("std::ops::Sub"),
-                                true,
-                            ),
-                            hir::BinOpKind::Mul => (
-                                format!("cannot multiply `{lhs_ty}` by `{rhs_ty}`"),
-                                Some("std::ops::Mul"),
-                                true,
-                            ),
-                            hir::BinOpKind::Div => (
-                                format!("cannot divide `{lhs_ty}` by `{rhs_ty}`"),
-                                Some("std::ops::Div"),
-                                true,
-                            ),
-                            hir::BinOpKind::Rem => (
-                                format!("cannot mod `{lhs_ty}` by `{rhs_ty}`"),
-                                Some("std::ops::Rem"),
-                                true,
-                            ),
-                            hir::BinOpKind::BitAnd => (
-                                format!("no implementation for `{lhs_ty} & {rhs_ty}`"),
-                                Some("std::ops::BitAnd"),
-                                true,
-                            ),
-                            hir::BinOpKind::BitXor => (
-                                format!("no implementation for `{lhs_ty} ^ {rhs_ty}`"),
-                                Some("std::ops::BitXor"),
-                                true,
-                            ),
-                            hir::BinOpKind::BitOr => (
-                                format!("no implementation for `{lhs_ty} | {rhs_ty}`"),
-                                Some("std::ops::BitOr"),
-                                true,
-                            ),
-                            hir::BinOpKind::Shl => (
-                                format!("no implementation for `{lhs_ty} << {rhs_ty}`"),
-                                Some("std::ops::Shl"),
-                                true,
-                            ),
-                            hir::BinOpKind::Shr => (
-                                format!("no implementation for `{lhs_ty} >> {rhs_ty}`"),
-                                Some("std::ops::Shr"),
-                                true,
-                            ),
-                            hir::BinOpKind::Eq | hir::BinOpKind::Ne => (
-                                format!(
-                                    "binary operation `{}` cannot be applied to type `{}`",
-                                    op.node.as_str(),
-                                    lhs_ty
-                                ),
-                                Some("std::cmp::PartialEq"),
-                                false,
-                            ),
-                            hir::BinOpKind::Lt
-                            | hir::BinOpKind::Le
-                            | hir::BinOpKind::Gt
-                            | hir::BinOpKind::Ge => (
-                                format!(
-                                    "binary operation `{}` cannot be applied to type `{}`",
-                                    op.node.as_str(),
-                                    lhs_ty
-                                ),
-                                Some("std::cmp::PartialOrd"),
-                                false,
-                            ),
-                            _ => (
-                                format!(
-                                    "binary operation `{}` cannot be applied to type `{}`",
-                                    op.node.as_str(),
-                                    lhs_ty
-                                ),
-                                None,
-                                false,
+                        let message = match op.node {
+                            hir::BinOpKind::Add => {
+                                format!("cannot add `{rhs_ty}` to `{lhs_ty}`")
+                            }
+                            hir::BinOpKind::Sub => {
+                                format!("cannot subtract `{rhs_ty}` from `{lhs_ty}`")
+                            }
+                            hir::BinOpKind::Mul => {
+                                format!("cannot multiply `{lhs_ty}` by `{rhs_ty}`")
+                            }
+                            hir::BinOpKind::Div => {
+                                format!("cannot divide `{lhs_ty}` by `{rhs_ty}`")
+                            }
+                            hir::BinOpKind::Rem => {
+                                format!("cannot mod `{lhs_ty}` by `{rhs_ty}`")
+                            }
+                            hir::BinOpKind::BitAnd => {
+                                format!("no implementation for `{lhs_ty} & {rhs_ty}`")
+                            }
+                            hir::BinOpKind::BitXor => {
+                                format!("no implementation for `{lhs_ty} ^ {rhs_ty}`")
+                            }
+                            hir::BinOpKind::BitOr => {
+                                format!("no implementation for `{lhs_ty} | {rhs_ty}`")
+                            }
+                            hir::BinOpKind::Shl => {
+                                format!("no implementation for `{lhs_ty} << {rhs_ty}`")
+                            }
+                            hir::BinOpKind::Shr => {
+                                format!("no implementation for `{lhs_ty} >> {rhs_ty}`")
+                            }
+                            _ => format!(
+                                "binary operation `{}` cannot be applied to type `{}`",
+                                op.node.as_str(),
+                                lhs_ty
                             ),
                         };
+                        let output_def_id = trait_def_id.and_then(|def_id| {
+                            self.tcx
+                                .associated_item_def_ids(def_id)
+                                .iter()
+                                .find(|item_def_id| {
+                                    self.tcx.associated_item(*item_def_id).name == sym::Output
+                                })
+                                .cloned()
+                        });
                         let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "{message}");
                         if !lhs_expr.span.eq(&rhs_expr.span) {
                             err.span_label(lhs_expr.span, lhs_ty.to_string());
                             err.span_label(rhs_expr.span, rhs_ty.to_string());
                         }
                         self.note_unmet_impls_on_type(&mut err, errors);
-                        (err, missing_trait, use_output)
+                        (err, output_def_id)
                     }
                 };
 
@@ -448,24 +399,21 @@ fn check_overloaded_binop(
                         )
                         .is_ok()
                     {
-                        if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
-                            let msg = &format!(
-                                "`{}{}` can be used on `{}`, you can dereference `{}`",
-                                op.node.as_str(),
-                                match is_assign {
-                                    IsAssign::Yes => "=",
-                                    IsAssign::No => "",
-                                },
-                                lhs_deref_ty.peel_refs(),
-                                lstring,
-                            );
-                            err.span_suggestion_verbose(
-                                lhs_expr.span.shrink_to_lo(),
-                                msg,
-                                "*",
-                                rustc_errors::Applicability::MachineApplicable,
-                            );
-                        }
+                        let msg = &format!(
+                            "`{}{}` can be used on `{}` if you dereference the left-hand side",
+                            op.node.as_str(),
+                            match is_assign {
+                                IsAssign::Yes => "=",
+                                IsAssign::No => "",
+                            },
+                            lhs_deref_ty,
+                        );
+                        err.span_suggestion_verbose(
+                            lhs_expr.span.shrink_to_lo(),
+                            msg,
+                            "*",
+                            rustc_errors::Applicability::MachineApplicable,
+                        );
                     }
                 };
 
@@ -514,9 +462,6 @@ fn check_overloaded_binop(
                 }
 
                 if let Some(missing_trait) = missing_trait {
-                    let mut visitor = TypeParamVisitor(vec![]);
-                    visitor.visit_ty(lhs_ty);
-
                     if op.node == hir::BinOpKind::Add
                         && self.check_str_addition(
                             lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, is_assign, op,
@@ -525,7 +470,7 @@ fn check_overloaded_binop(
                         // This has nothing here because it means we did string
                         // concatenation (e.g., "Hello " + "World!"). This means
                         // we don't want the note in the else clause to be emitted
-                    } else if let [ty] = &visitor.0[..] {
+                    } else if lhs_ty.has_param_types_or_consts() {
                         // Look for a TraitPredicate in the Fulfillment errors,
                         // and use it to generate a suggestion.
                         //
@@ -547,12 +492,21 @@ fn check_overloaded_binop(
                                 if let Some(trait_pred) =
                                     error.obligation.predicate.to_opt_poly_trait_pred()
                                 {
-                                    let proj_pred = match error.obligation.cause.code() {
+                                    let output_associated_item = match error.obligation.cause.code()
+                                    {
                                         ObligationCauseCode::BinOp {
-                                            output_pred: Some(output_pred),
+                                            output_ty: Some(output_ty),
                                             ..
-                                        } if use_output => {
-                                            output_pred.to_opt_poly_projection_pred()
+                                        } => {
+                                            // Make sure that we're attaching `Output = ..` to the right trait predicate
+                                            if let Some(output_def_id) = output_def_id
+                                                && let Some(trait_def_id) = trait_def_id
+                                                && self.tcx.parent(output_def_id) == trait_def_id
+                                            {
+                                                Some(("Output", *output_ty))
+                                            } else {
+                                                None
+                                            }
                                         }
                                         _ => None,
                                     };
@@ -560,12 +514,12 @@ fn check_overloaded_binop(
                                     self.suggest_restricting_param_bound(
                                         &mut err,
                                         trait_pred,
-                                        proj_pred,
+                                        output_associated_item,
                                         self.body_id,
                                     );
                                 }
                             }
-                        } else if *ty != lhs_ty {
+                        } else {
                             // When we know that a missing bound is responsible, we don't show
                             // this note as it is redundant.
                             err.note(&format!(
@@ -702,14 +656,10 @@ pub fn check_user_unop(
                         format!("cannot apply unary operator `{}`", op.as_str()),
                     );
 
-                    let mut visitor = TypeParamVisitor(vec![]);
-                    visitor.visit_ty(operand_ty);
-                    if let [_] = &visitor.0[..] && let ty::Param(_) = *operand_ty.kind() {
-                        let predicates = errors
-                            .iter()
-                            .filter_map(|error| {
-                                error.obligation.predicate.to_opt_poly_trait_pred()
-                            });
+                    if operand_ty.has_param_types_or_consts() {
+                        let predicates = errors.iter().filter_map(|error| {
+                            error.obligation.predicate.to_opt_poly_trait_pred()
+                        });
                         for pred in predicates {
                             self.suggest_restricting_param_bound(
                                 &mut err,
@@ -777,64 +727,11 @@ fn lookup_op_method(
         op: Op,
         expected: Expectation<'tcx>,
     ) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>> {
-        let lang = self.tcx.lang_items();
-
         let span = match op {
             Op::Binary(op, _) => op.span,
             Op::Unary(_, span) => span,
         };
-        let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op {
-            match op.node {
-                hir::BinOpKind::Add => (sym::add_assign, lang.add_assign_trait()),
-                hir::BinOpKind::Sub => (sym::sub_assign, lang.sub_assign_trait()),
-                hir::BinOpKind::Mul => (sym::mul_assign, lang.mul_assign_trait()),
-                hir::BinOpKind::Div => (sym::div_assign, lang.div_assign_trait()),
-                hir::BinOpKind::Rem => (sym::rem_assign, lang.rem_assign_trait()),
-                hir::BinOpKind::BitXor => (sym::bitxor_assign, lang.bitxor_assign_trait()),
-                hir::BinOpKind::BitAnd => (sym::bitand_assign, lang.bitand_assign_trait()),
-                hir::BinOpKind::BitOr => (sym::bitor_assign, lang.bitor_assign_trait()),
-                hir::BinOpKind::Shl => (sym::shl_assign, lang.shl_assign_trait()),
-                hir::BinOpKind::Shr => (sym::shr_assign, lang.shr_assign_trait()),
-                hir::BinOpKind::Lt
-                | hir::BinOpKind::Le
-                | hir::BinOpKind::Ge
-                | hir::BinOpKind::Gt
-                | hir::BinOpKind::Eq
-                | hir::BinOpKind::Ne
-                | hir::BinOpKind::And
-                | hir::BinOpKind::Or => {
-                    span_bug!(span, "impossible assignment operation: {}=", op.node.as_str())
-                }
-            }
-        } else if let Op::Binary(op, IsAssign::No) = op {
-            match op.node {
-                hir::BinOpKind::Add => (sym::add, lang.add_trait()),
-                hir::BinOpKind::Sub => (sym::sub, lang.sub_trait()),
-                hir::BinOpKind::Mul => (sym::mul, lang.mul_trait()),
-                hir::BinOpKind::Div => (sym::div, lang.div_trait()),
-                hir::BinOpKind::Rem => (sym::rem, lang.rem_trait()),
-                hir::BinOpKind::BitXor => (sym::bitxor, lang.bitxor_trait()),
-                hir::BinOpKind::BitAnd => (sym::bitand, lang.bitand_trait()),
-                hir::BinOpKind::BitOr => (sym::bitor, lang.bitor_trait()),
-                hir::BinOpKind::Shl => (sym::shl, lang.shl_trait()),
-                hir::BinOpKind::Shr => (sym::shr, lang.shr_trait()),
-                hir::BinOpKind::Lt => (sym::lt, lang.partial_ord_trait()),
-                hir::BinOpKind::Le => (sym::le, lang.partial_ord_trait()),
-                hir::BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()),
-                hir::BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()),
-                hir::BinOpKind::Eq => (sym::eq, lang.eq_trait()),
-                hir::BinOpKind::Ne => (sym::ne, lang.eq_trait()),
-                hir::BinOpKind::And | hir::BinOpKind::Or => {
-                    span_bug!(span, "&& and || are not overloadable")
-                }
-            }
-        } else if let Op::Unary(hir::UnOp::Not, _) = op {
-            (sym::not, lang.not_trait())
-        } else if let Op::Unary(hir::UnOp::Neg, _) = op {
-            (sym::neg, lang.neg_trait())
-        } else {
-            bug!("lookup_op_method: op not supported: {:?}", op)
-        };
+        let (opname, trait_did) = lang_item_for_op(self.tcx, op, span);
 
         debug!(
             "lookup_op_method(lhs_ty={:?}, op={:?}, opname={:?}, trait_did={:?})",
@@ -895,6 +792,66 @@ fn lookup_op_method(
     }
 }
 
+fn lang_item_for_op(
+    tcx: TyCtxt<'_>,
+    op: Op,
+    span: Span,
+) -> (rustc_span::Symbol, Option<hir::def_id::DefId>) {
+    let lang = tcx.lang_items();
+    if let Op::Binary(op, IsAssign::Yes) = op {
+        match op.node {
+            hir::BinOpKind::Add => (sym::add_assign, lang.add_assign_trait()),
+            hir::BinOpKind::Sub => (sym::sub_assign, lang.sub_assign_trait()),
+            hir::BinOpKind::Mul => (sym::mul_assign, lang.mul_assign_trait()),
+            hir::BinOpKind::Div => (sym::div_assign, lang.div_assign_trait()),
+            hir::BinOpKind::Rem => (sym::rem_assign, lang.rem_assign_trait()),
+            hir::BinOpKind::BitXor => (sym::bitxor_assign, lang.bitxor_assign_trait()),
+            hir::BinOpKind::BitAnd => (sym::bitand_assign, lang.bitand_assign_trait()),
+            hir::BinOpKind::BitOr => (sym::bitor_assign, lang.bitor_assign_trait()),
+            hir::BinOpKind::Shl => (sym::shl_assign, lang.shl_assign_trait()),
+            hir::BinOpKind::Shr => (sym::shr_assign, lang.shr_assign_trait()),
+            hir::BinOpKind::Lt
+            | hir::BinOpKind::Le
+            | hir::BinOpKind::Ge
+            | hir::BinOpKind::Gt
+            | hir::BinOpKind::Eq
+            | hir::BinOpKind::Ne
+            | hir::BinOpKind::And
+            | hir::BinOpKind::Or => {
+                span_bug!(span, "impossible assignment operation: {}=", op.node.as_str())
+            }
+        }
+    } else if let Op::Binary(op, IsAssign::No) = op {
+        match op.node {
+            hir::BinOpKind::Add => (sym::add, lang.add_trait()),
+            hir::BinOpKind::Sub => (sym::sub, lang.sub_trait()),
+            hir::BinOpKind::Mul => (sym::mul, lang.mul_trait()),
+            hir::BinOpKind::Div => (sym::div, lang.div_trait()),
+            hir::BinOpKind::Rem => (sym::rem, lang.rem_trait()),
+            hir::BinOpKind::BitXor => (sym::bitxor, lang.bitxor_trait()),
+            hir::BinOpKind::BitAnd => (sym::bitand, lang.bitand_trait()),
+            hir::BinOpKind::BitOr => (sym::bitor, lang.bitor_trait()),
+            hir::BinOpKind::Shl => (sym::shl, lang.shl_trait()),
+            hir::BinOpKind::Shr => (sym::shr, lang.shr_trait()),
+            hir::BinOpKind::Lt => (sym::lt, lang.partial_ord_trait()),
+            hir::BinOpKind::Le => (sym::le, lang.partial_ord_trait()),
+            hir::BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()),
+            hir::BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()),
+            hir::BinOpKind::Eq => (sym::eq, lang.eq_trait()),
+            hir::BinOpKind::Ne => (sym::ne, lang.eq_trait()),
+            hir::BinOpKind::And | hir::BinOpKind::Or => {
+                span_bug!(span, "&& and || are not overloadable")
+            }
+        }
+    } else if let Op::Unary(hir::UnOp::Not, _) = op {
+        (sym::not, lang.not_trait())
+    } else if let Op::Unary(hir::UnOp::Neg, _) = op {
+        (sym::neg, lang.neg_trait())
+    } else {
+        bug!("lookup_op_method: op not supported: {:?}", op)
+    }
+}
+
 // Binary operator categories. These categories summarize the behavior
 // with respect to the builtin operations supported.
 enum BinOpCategory {
@@ -1017,17 +974,6 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool
     }
 }
 
-struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>);
-
-impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if let ty::Param(_) = ty.kind() {
-            self.0.push(ty);
-        }
-        ty.super_visit_with(self)
-    }
-}
-
 struct TypeParamEraser<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, Span);
 
 impl<'tcx> TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> {
index 9096fc442d49398e882f60ed458b4a99e644f65d..8906b622b68e4d8291ed407169e3fec202b5fabb 100644 (file)
@@ -981,7 +981,7 @@ fn check_pat_tuple_struct(
         pat: &'tcx Pat<'tcx>,
         qpath: &'tcx hir::QPath<'tcx>,
         subpats: &'tcx [Pat<'tcx>],
-        ddpos: Option<usize>,
+        ddpos: hir::DotDotPos,
         expected: Ty<'tcx>,
         def_bm: BindingMode,
         ti: TopInfo<'tcx>,
@@ -1066,7 +1066,7 @@ fn check_pat_tuple_struct(
 
         // Type-check subpatterns.
         if subpats.len() == variant.fields.len()
-            || subpats.len() < variant.fields.len() && ddpos.is_some()
+            || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
         {
             let ty::Adt(_, substs) = pat_ty.kind() else {
                 bug!("unexpected pattern type {:?}", pat_ty);
@@ -1254,14 +1254,14 @@ fn check_pat_tuple(
         &self,
         span: Span,
         elements: &'tcx [Pat<'tcx>],
-        ddpos: Option<usize>,
+        ddpos: hir::DotDotPos,
         expected: Ty<'tcx>,
         def_bm: BindingMode,
         ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let mut expected_len = elements.len();
-        if ddpos.is_some() {
+        if ddpos.as_opt_usize().is_some() {
             // Require known type only when `..` is present.
             if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() {
                 expected_len = tys.len();
@@ -1397,7 +1397,7 @@ fn check_struct_pat_fields(
                 .iter()
                 .copied()
                 .filter(|(field, _)| {
-                    field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
+                    field.vis.is_accessible_from(tcx.parent_module(pat.hir_id), tcx)
                         && !matches!(
                             tcx.eval_stability(field.did, None, DUMMY_SP, None),
                             EvalResult::Deny { .. }
index 6236ad370df60e1bcd30a14c92b70a2fbd498dac..f9c7c008fa484af94c431144085d7c29f8424f9e 100644 (file)
@@ -573,6 +573,7 @@ fn get_new_lifetime_name<'tcx>(
 
 /// Returns the predicates defined on `item_def_id` of the form
 /// `X: Foo` where `X` is the type parameter `def_id`.
+#[instrument(level = "trace", skip(tcx))]
 fn type_param_predicates(
     tcx: TyCtxt<'_>,
     (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
@@ -679,7 +680,7 @@ fn type_parameter_bounds_in_generics(
         assoc_name: Option<Ident>,
     ) -> Vec<(ty::Predicate<'tcx>, Span)> {
         let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
-        debug!(?param_def_id);
+        trace!(?param_def_id);
         ast_generics
             .predicates
             .iter()
@@ -708,9 +709,8 @@ fn type_parameter_bounds_in_generics(
             .collect()
     }
 
+    #[instrument(level = "trace", skip(self))]
     fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
-        debug!("bound_defines_assoc_item(b={:?}, assoc_name={:?})", b, assoc_name);
-
         match b {
             hir::GenericBound::Trait(poly_trait_ref, _) => {
                 let trait_ref = &poly_trait_ref.trait_ref;
@@ -1585,8 +1585,16 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             ItemKind::OpaqueTy(hir::OpaqueTy {
                 origin:
                     hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+                in_trait,
                 ..
-            }) => Some(fn_def_id.to_def_id()),
+            }) => {
+                if in_trait {
+                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
+                } else {
+                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
+                }
+                Some(fn_def_id.to_def_id())
+            }
             ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
                 let parent_id = tcx.hir().get_parent_item(hir_id);
                 assert_ne!(parent_id, CRATE_DEF_ID);
@@ -1787,7 +1795,7 @@ fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
         }
         Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
         Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
-        OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args),
+        OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
         Path(hir::QPath::TypeRelative(ty, segment)) => {
             is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args)
         }
@@ -2105,11 +2113,10 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
 
 /// Returns a list of user-specified type predicates for the definition with ID `def_id`.
 /// N.B., this does not include any implied/inferred constraints.
+#[instrument(level = "trace", skip(tcx), ret)]
 fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
     use rustc_hir::*;
 
-    debug!("explicit_predicates_of(def_id={:?})", def_id);
-
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
     let node = tcx.hir().get(hir_id);
 
@@ -2224,6 +2231,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
         + has_own_self as u32
         + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
 
+    trace!(?predicates);
+    trace!(?ast_generics);
+
     // Collect the predicates that were written inline by the user on each
     // type parameter (e.g., `<T: Foo>`).
     for param in ast_generics.params {
@@ -2244,7 +2254,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                     Some((param.hir_id, ast_generics.predicates)),
                     param.span,
                 );
+                trace!(?bounds);
                 predicates.extend(bounds.predicates(tcx, param_ty));
+                trace!(?predicates);
             }
             GenericParamKind::Const { .. } => {
                 // Bounds on const parameters are currently not possible.
@@ -2253,6 +2265,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
         }
     }
 
+    trace!(?predicates);
     // Add in the bounds that appear in the where-clause.
     for predicate in ast_generics.predicates {
         match predicate {
@@ -2338,12 +2351,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
         );
     }
 
-    let result = ty::GenericPredicates {
+    ty::GenericPredicates {
         parent: generics.parent,
         predicates: tcx.arena.alloc_from_iter(predicates),
-    };
-    debug!("explicit_predicates_of(def_id={:?}) = {:?}", def_id, result);
-    result
+    }
 }
 
 fn const_evaluatable_predicates_of<'tcx>(
@@ -3276,6 +3287,15 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 
 fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
     use rustc_ast::{Lit, LitIntType, LitKind};
+    if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
+        feature_err(
+            &tcx.sess.parse_sess,
+            sym::raw_dylib,
+            attr.span,
+            "`#[link_ordinal]` is unstable on x86",
+        )
+        .emit();
+    }
     let meta_item_list = attr.meta_item_list();
     let meta_item_list: Option<&[ast::NestedMetaItem]> = meta_item_list.as_ref().map(Vec::as_ref);
     let sole_meta_list = match meta_item_list {
index 0d2b75d3328fcc3bfb27b9ac27d48db7414b2a4d..0d34a8bfee333d3d457fd32e15cfc101eb5ad474 100644 (file)
@@ -53,20 +53,28 @@ fn associated_type_bounds<'tcx>(
 /// impl trait it isn't possible to write a suitable predicate on the
 /// containing function and for type-alias impl trait we don't have a backwards
 /// compatibility issue.
+#[instrument(level = "trace", skip(tcx), ret)]
 fn opaque_type_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     opaque_def_id: DefId,
     ast_bounds: &'tcx [hir::GenericBound<'tcx>],
     span: Span,
+    in_trait: bool,
 ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
     ty::print::with_no_queries!({
-        let item_ty =
-            tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id));
+        let substs = InternalSubsts::identity_for_item(tcx, opaque_def_id);
+        let item_ty = if in_trait {
+            tcx.mk_projection(opaque_def_id, substs)
+        } else {
+            tcx.mk_opaque(opaque_def_id, substs)
+        };
 
         let icx = ItemCtxt::new(tcx, opaque_def_id);
         let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
         // Opaque types are implicitly sized unless a `?Sized` bound is found
         <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
+        debug!(?bounds);
+
         tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
     })
 }
@@ -83,10 +91,10 @@ pub(super) fn explicit_item_bounds(
             ..
         }) => associated_type_bounds(tcx, def_id, bounds, *span),
         hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }),
+            kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait, .. }),
             span,
             ..
-        }) => opaque_type_bounds(tcx, def_id, bounds, *span),
+        }) => opaque_type_bounds(tcx, def_id, bounds, *span, *in_trait),
         _ => bug!("item_bounds called on {:?}", def_id),
     }
 }
index a0280ddca4bd8dbdeb47e99d4364b3873584ef69..70e259b46bf20c7c990d9fe9679c02064543bbf2 100644 (file)
@@ -65,8 +65,8 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
             let ty = item_ctxt.ast_ty_to_ty(hir_ty);
 
             // Iterate through the generics of the projection to find the one that corresponds to
-            // the def_id that this query was called with. We filter to only const args here as a
-            // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
+            // the def_id that this query was called with. We filter to only type and const args here
+            // as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
             // but it can't hurt to be safe ^^
             if let ty::Projection(projection) = ty.kind() {
                 let generics = tcx.generics_of(projection.item_def_id);
@@ -333,8 +333,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     find_opaque_ty_constraints_for_tait(tcx, def_id)
                 }
                 // Opaque types desugared from `impl Trait`.
-                ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), .. }) => {
-                    find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
+                ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), in_trait, .. }) => {
+                    if in_trait {
+                        span_bug!(item.span, "impl-trait in trait has no default")
+                    } else {
+                        find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
+                    }
                 }
                 ItemKind::Trait(..)
                 | ItemKind::TraitAlias(..)
index d79450e1ae707c30a171f85ee0277df03aca63bc..4fe213ffeea35bcf69026b18a67b9177dadf188b 100644 (file)
@@ -271,11 +271,11 @@ fn add_constraints_from_ty(
                 }
 
                 for projection in data.projection_bounds() {
-                    match projection.skip_binder().term {
-                        ty::Term::Ty(ty) => {
+                    match projection.skip_binder().term.unpack() {
+                        ty::TermKind::Ty(ty) => {
                             self.add_constraints_from_ty(current, ty, self.invariant);
                         }
-                        ty::Term::Const(c) => {
+                        ty::TermKind::Const(c) => {
                             self.add_constraints_from_const(current, c, self.invariant)
                         }
                     }
index 9d3e9abf557792c9c490f969e7da5d798af8dce6..905212eb372b12f8dfe185691abd435563c6deb1 100644 (file)
@@ -1819,7 +1819,7 @@ pub fn precision(&self) -> Option<usize> {
     ///             write!(formatter,
     ///                    "Foo({}{})",
     ///                    if self.0 < 0 { '-' } else { '+' },
-    ///                    self.0)
+    ///                    self.0.abs())
     ///         } else {
     ///             write!(formatter, "Foo({})", self.0)
     ///         }
@@ -1827,6 +1827,7 @@ pub fn precision(&self) -> Option<usize> {
     /// }
     ///
     /// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)");
+    /// assert_eq!(&format!("{:+}", Foo(-23)), "Foo(-23)");
     /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
     /// ```
     #[must_use]
index 20340d42962efbbf1caf5fd8bb06f4b6515d1b91..764e2796202c9ef72626e8cdda1a9ccdfc2b14e0 100644 (file)
 #[inline]
 #[stable(feature = "renamed_spin_loop", since = "1.49.0")]
 pub fn spin_loop() {
-    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
+    #[cfg(target_arch = "x86")]
     {
-        #[cfg(target_arch = "x86")]
-        {
-            // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
-            unsafe { crate::arch::x86::_mm_pause() };
-        }
+        // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
+        unsafe { crate::arch::x86::_mm_pause() };
+    }
 
-        #[cfg(target_arch = "x86_64")]
-        {
-            // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
-            unsafe { crate::arch::x86_64::_mm_pause() };
-        }
+    #[cfg(target_arch = "x86_64")]
+    {
+        // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
+        unsafe { crate::arch::x86_64::_mm_pause() };
     }
 
     // RISC-V platform spin loop hint implementation
index 56f5824efd4ca15e7fe9a705e929435af890a604..11c75e2c912412181236d55e5267154fef642fe9 100644 (file)
@@ -2013,21 +2013,24 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     pub fn ptr_offset_from_unsigned<T>(ptr: *const T, base: *const T) -> usize;
 
     /// See documentation of `<*const T>::guaranteed_eq` for details.
+    /// Returns `2` if the result is unknown.
+    /// Returns `1` if the pointers are guaranteed equal
+    /// Returns `0` if the pointers are guaranteed inequal
     ///
     /// Note that, unlike most intrinsics, this is safe to call;
     /// it does not require an `unsafe` block.
     /// Therefore, implementations must not require the user to uphold
     /// any safety invariants.
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[cfg(not(bootstrap))]
+    pub fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8;
+
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[cfg(bootstrap)]
     pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;
 
-    /// See documentation of `<*const T>::guaranteed_ne` for details.
-    ///
-    /// Note that, unlike most intrinsics, this is safe to call;
-    /// it does not require an `unsafe` block.
-    /// Therefore, implementations must not require the user to uphold
-    /// any safety invariants.
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[cfg(bootstrap)]
     pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
 
     /// Allocates a block of memory at compile time.
@@ -2213,6 +2216,16 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
     diff >= size
 }
 
+#[cfg(bootstrap)]
+pub const fn ptr_guaranteed_cmp(a: *const (), b: *const ()) -> u8 {
+    match (ptr_guaranteed_eq(a, b), ptr_guaranteed_ne(a, b)) {
+        (false, false) => 2,
+        (true, false) => 1,
+        (false, true) => 0,
+        (true, true) => unreachable!(),
+    }
+}
+
 /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
 /// and destination must *not* overlap.
 ///
index 92b12ed33528db86c9cf897d785bc6347bf72353..e7deb728d15d893cce10a6a96909a258f11a0365 100644 (file)
@@ -1518,6 +1518,51 @@ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
             (a as Self, b)
         }
 
+        /// Calculates `self + rhs + carry` without the ability to overflow.
+        ///
+        /// Performs "signed ternary addition" which takes in an extra bit to add, and may return an
+        /// additional bit of overflow. This signed function is used only on the highest-ordered data,
+        /// for which the signed overflow result indicates whether the big integer overflowed or not.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (", stringify!($SelfT), "::MIN, true));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (", stringify!($SelfT), "::MIN, true));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (", stringify!($SelfT), "::MIN + 1, true));")]
+        #[doc = concat!("assert_eq!(",
+            stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ",
+            "(-1, true));"
+        )]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.carrying_add(-1, true), (", stringify!($SelfT), "::MIN, false));")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".carrying_add(", stringify!($SelfT), "::MAX, true), (", stringify!($SelfT), "::MIN, true));")]
+        /// ```
+        ///
+        /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add):
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")]
+        /// ```
+        #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+        #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
+            // note: longer-term this should be done via an intrinsic.
+            // note: no intermediate overflow is required (https://github.com/rust-lang/rust/issues/85532#issuecomment-1032214946).
+            let (a, b) = self.overflowing_add(rhs);
+            let (c, d) = a.overflowing_add(carry as $SelfT);
+            (c, b != d)
+        }
+
         /// Calculates `self` + `rhs` with an unsigned `rhs`
         ///
         /// Returns a tuple of the addition along with a boolean indicating
@@ -1569,6 +1614,39 @@ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
             (a as Self, b)
         }
 
+        /// Calculates `self - rhs - borrow` without the ability to overflow.
+        ///
+        /// Performs "signed ternary subtraction" which takes in an extra bit to subtract, and may return an
+        /// additional bit of overflow. This signed function is used only on the highest-ordered data,
+        /// for which the signed overflow result indicates whether the big integer overflowed or not.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, false), (-1, false));")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, true), (-2, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, true));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, false), (", stringify!($SelfT), "::MIN, true));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, true), (", stringify!($SelfT), "::MAX, false));")]
+        /// ```
+        #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+        #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
+            // note: longer-term this should be done via an intrinsic.
+            // note: no intermediate overflow is required (https://github.com/rust-lang/rust/issues/85532#issuecomment-1032214946).
+            let (a, b) = self.overflowing_sub(rhs);
+            let (c, d) = a.overflowing_sub(borrow as $SelfT);
+            (c, b != d)
+        }
+
         /// Calculates `self` - `rhs` with an unsigned `rhs`
         ///
         /// Returns a tuple of the subtraction along with a boolean indicating
index b651b7b233edeabc4e9afed2ce676a4f21d9f4cc..3ebd6f8cdbdc03e598b2d2c0a1d55c2b05a1533f 100644 (file)
@@ -83,7 +83,7 @@ pub trait Generator<R = ()> {
     /// `return` statement or implicitly as the last expression of a generator
     /// literal. For example futures would use this as `Result<T, E>` as it
     /// represents a completed future.
-    #[lang = "generator_return"]
+    #[cfg_attr(bootstrap, lang = "generator_return")]
     type Return;
 
     /// Resumes the execution of this generator.
index 80bff74f3e9f4712c8d7e26ab320655a32e081cd..fcdf69a7aaa40026e72ae3de3a8936ee54e86d7e 100644 (file)
@@ -36,7 +36,10 @@ impl<T: ?Sized> *const T {
     pub const fn is_null(self) -> bool {
         // Compare via a cast to a thin pointer, so fat pointers are only
         // considering their "data" part for null-ness.
-        (self as *const u8).guaranteed_eq(null())
+        match (self as *const u8).guaranteed_eq(null()) {
+            None => false,
+            Some(res) => res,
+        }
     }
 
     /// Casts to a pointer of another type.
@@ -770,20 +773,16 @@ pub fn mask(self, mask: usize) -> *const T {
 
     /// Returns whether two pointers are guaranteed to be equal.
     ///
-    /// At runtime this function behaves like `self == other`.
+    /// At runtime this function behaves like `Some(self == other)`.
     /// However, in some contexts (e.g., compile-time evaluation),
     /// it is not always possible to determine equality of two pointers, so this function may
-    /// spuriously return `false` for pointers that later actually turn out to be equal.
-    /// But when it returns `true`, the pointers are guaranteed to be equal.
-    ///
-    /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
-    /// comparisons for which both functions return `false`.
+    /// spuriously return `None` for pointers that later actually turn out to have its equality known.
+    /// But when it returns `Some`, the pointers' equality is guaranteed to be known.
     ///
-    /// [`guaranteed_ne`]: #method.guaranteed_ne
-    ///
-    /// The return value may change depending on the compiler version and unsafe code must not
+    /// The return value may change from `Some` to `None` and vice versa depending on the compiler
+    /// version and unsafe code must not
     /// rely on the result of this function for soundness. It is suggested to only use this function
-    /// for performance optimizations where spurious `false` return values by this function do not
+    /// for performance optimizations where spurious `None` return values by this function do not
     /// affect the outcome, but just the performance.
     /// The consequences of using this method to make runtime and compile-time code behave
     /// differently have not been explored. This method should not be used to introduce such
@@ -792,29 +791,28 @@ pub fn mask(self, mask: usize) -> *const T {
     #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[inline]
-    pub const fn guaranteed_eq(self, other: *const T) -> bool
+    pub const fn guaranteed_eq(self, other: *const T) -> Option<bool>
     where
         T: Sized,
     {
-        intrinsics::ptr_guaranteed_eq(self, other)
+        match intrinsics::ptr_guaranteed_cmp(self as _, other as _) {
+            2 => None,
+            other => Some(other == 1),
+        }
     }
 
-    /// Returns whether two pointers are guaranteed to be unequal.
+    /// Returns whether two pointers are guaranteed to be inequal.
     ///
-    /// At runtime this function behaves like `self != other`.
+    /// At runtime this function behaves like `Some(self == other)`.
     /// However, in some contexts (e.g., compile-time evaluation),
-    /// it is not always possible to determine the inequality of two pointers, so this function may
-    /// spuriously return `false` for pointers that later actually turn out to be unequal.
-    /// But when it returns `true`, the pointers are guaranteed to be unequal.
+    /// it is not always possible to determine inequality of two pointers, so this function may
+    /// spuriously return `None` for pointers that later actually turn out to have its inequality known.
+    /// But when it returns `Some`, the pointers' inequality is guaranteed to be known.
     ///
-    /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
-    /// comparisons for which both functions return `false`.
-    ///
-    /// [`guaranteed_eq`]: #method.guaranteed_eq
-    ///
-    /// The return value may change depending on the compiler version and unsafe code must not
+    /// The return value may change from `Some` to `None` and vice versa depending on the compiler
+    /// version and unsafe code must not
     /// rely on the result of this function for soundness. It is suggested to only use this function
-    /// for performance optimizations where spurious `false` return values by this function do not
+    /// for performance optimizations where spurious `None` return values by this function do not
     /// affect the outcome, but just the performance.
     /// The consequences of using this method to make runtime and compile-time code behave
     /// differently have not been explored. This method should not be used to introduce such
@@ -823,11 +821,14 @@ pub const fn guaranteed_eq(self, other: *const T) -> bool
     #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[inline]
-    pub const fn guaranteed_ne(self, other: *const T) -> bool
+    pub const fn guaranteed_ne(self, other: *const T) -> Option<bool>
     where
         T: Sized,
     {
-        intrinsics::ptr_guaranteed_ne(self, other)
+        match self.guaranteed_eq(other) {
+            None => None,
+            Some(eq) => Some(!eq),
+        }
     }
 
     /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
index 3e4c3ae07567565da53e13364d3ed28a88890fa5..460f3df5feeabed4151b054c5c87369e94718950 100644 (file)
@@ -35,7 +35,10 @@ impl<T: ?Sized> *mut T {
     pub const fn is_null(self) -> bool {
         // Compare via a cast to a thin pointer, so fat pointers are only
         // considering their "data" part for null-ness.
-        (self as *mut u8).guaranteed_eq(null_mut())
+        match (self as *mut u8).guaranteed_eq(null_mut()) {
+            None => false,
+            Some(res) => res,
+        }
     }
 
     /// Casts to a pointer of another type.
@@ -697,20 +700,16 @@ pub fn mask(self, mask: usize) -> *mut T {
 
     /// Returns whether two pointers are guaranteed to be equal.
     ///
-    /// At runtime this function behaves like `self == other`.
+    /// At runtime this function behaves like `Some(self == other)`.
     /// However, in some contexts (e.g., compile-time evaluation),
     /// it is not always possible to determine equality of two pointers, so this function may
-    /// spuriously return `false` for pointers that later actually turn out to be equal.
-    /// But when it returns `true`, the pointers are guaranteed to be equal.
-    ///
-    /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
-    /// comparisons for which both functions return `false`.
-    ///
-    /// [`guaranteed_ne`]: #method.guaranteed_ne
+    /// spuriously return `None` for pointers that later actually turn out to have its equality known.
+    /// But when it returns `Some`, the pointers' equality is guaranteed to be known.
     ///
-    /// The return value may change depending on the compiler version and unsafe code might not
+    /// The return value may change from `Some` to `None` and vice versa depending on the compiler
+    /// version and unsafe code must not
     /// rely on the result of this function for soundness. It is suggested to only use this function
-    /// for performance optimizations where spurious `false` return values by this function do not
+    /// for performance optimizations where spurious `None` return values by this function do not
     /// affect the outcome, but just the performance.
     /// The consequences of using this method to make runtime and compile-time code behave
     /// differently have not been explored. This method should not be used to introduce such
@@ -719,29 +718,25 @@ pub fn mask(self, mask: usize) -> *mut T {
     #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[inline]
-    pub const fn guaranteed_eq(self, other: *mut T) -> bool
+    pub const fn guaranteed_eq(self, other: *mut T) -> Option<bool>
     where
         T: Sized,
     {
-        intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
+        (self as *const T).guaranteed_eq(other as _)
     }
 
-    /// Returns whether two pointers are guaranteed to be unequal.
+    /// Returns whether two pointers are guaranteed to be inequal.
     ///
-    /// At runtime this function behaves like `self != other`.
+    /// At runtime this function behaves like `Some(self == other)`.
     /// However, in some contexts (e.g., compile-time evaluation),
-    /// it is not always possible to determine the inequality of two pointers, so this function may
-    /// spuriously return `false` for pointers that later actually turn out to be unequal.
-    /// But when it returns `true`, the pointers are guaranteed to be unequal.
-    ///
-    /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
-    /// comparisons for which both functions return `false`.
-    ///
-    /// [`guaranteed_eq`]: #method.guaranteed_eq
+    /// it is not always possible to determine inequality of two pointers, so this function may
+    /// spuriously return `None` for pointers that later actually turn out to have its inequality known.
+    /// But when it returns `Some`, the pointers' inequality is guaranteed to be known.
     ///
-    /// The return value may change depending on the compiler version and unsafe code might not
+    /// The return value may change from `Some` to `None` and vice versa depending on the compiler
+    /// version and unsafe code must not
     /// rely on the result of this function for soundness. It is suggested to only use this function
-    /// for performance optimizations where spurious `false` return values by this function do not
+    /// for performance optimizations where spurious `None` return values by this function do not
     /// affect the outcome, but just the performance.
     /// The consequences of using this method to make runtime and compile-time code behave
     /// differently have not been explored. This method should not be used to introduce such
@@ -750,11 +745,11 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[inline]
-    pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool
+    pub const fn guaranteed_ne(self, other: *mut T) -> Option<bool>
     where
         T: Sized,
     {
-        intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _)
+        (self as *const T).guaranteed_ne(other as _)
     }
 
     /// Calculates the distance between two pointers. The returned value is in
index c315f3a7975129399459a37c48f8fcc63a1c15c7..4a0e162bc4a50b7c2584cbba730c68297caa0483 100644 (file)
@@ -3,6 +3,7 @@
 #![feature(array_methods)]
 #![feature(array_windows)]
 #![feature(bench_black_box)]
+#![feature(bigint_helper_methods)]
 #![feature(cell_update)]
 #![feature(const_assume)]
 #![feature(const_black_box)]
index 8b84a78e6be08823a33a1abb9ad07f7724778d73..18c55e43aac81958d897a9e85141f7483eb24387 100644 (file)
@@ -338,6 +338,32 @@ fn test_checked_next_multiple_of() {
                 assert_eq!(MIN.checked_next_multiple_of(-3), None);
                 assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN));
             }
+
+            #[test]
+            fn test_carrying_add() {
+                assert_eq!($T::MAX.carrying_add(1, false), ($T::MIN, true));
+                assert_eq!($T::MAX.carrying_add(0, true), ($T::MIN, true));
+                assert_eq!($T::MAX.carrying_add(1, true), ($T::MIN + 1, true));
+                assert_eq!($T::MAX.carrying_add(-1, false), ($T::MAX - 1, false));
+                assert_eq!($T::MAX.carrying_add(-1, true), ($T::MAX, false)); // no intermediate overflow
+                assert_eq!($T::MIN.carrying_add(-1, false), ($T::MAX, true));
+                assert_eq!($T::MIN.carrying_add(-1, true), ($T::MIN, false)); // no intermediate overflow
+                assert_eq!((0 as $T).carrying_add($T::MAX, true), ($T::MIN, true));
+                assert_eq!((0 as $T).carrying_add($T::MIN, true), ($T::MIN + 1, false));
+            }
+
+            #[test]
+            fn test_borrowing_sub() {
+                assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true));
+                assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true));
+                assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true));
+                assert_eq!($T::MIN.borrowing_sub(-1, false), ($T::MIN + 1, false));
+                assert_eq!($T::MIN.borrowing_sub(-1, true), ($T::MIN, false)); // no intermediate overflow
+                assert_eq!($T::MAX.borrowing_sub(-1, false), ($T::MIN, true));
+                assert_eq!($T::MAX.borrowing_sub(-1, true), ($T::MAX, false)); // no intermediate overflow
+                assert_eq!((0 as $T).borrowing_sub($T::MIN, false), ($T::MIN, true));
+                assert_eq!((0 as $T).borrowing_sub($T::MIN, true), ($T::MAX, false));
+            }
         }
     };
 }
index 93ae620c23302413da250988dd8b0592d8c19d8a..15ae9f2324f6c8a29605576e793f9609571f42ab 100644 (file)
@@ -230,6 +230,28 @@ fn test_checked_next_multiple_of() {
                 assert_eq!((1 as $T).checked_next_multiple_of(0), None);
                 assert_eq!(MAX.checked_next_multiple_of(2), None);
             }
+
+            #[test]
+            fn test_carrying_add() {
+                assert_eq!($T::MAX.carrying_add(1, false), (0, true));
+                assert_eq!($T::MAX.carrying_add(0, true), (0, true));
+                assert_eq!($T::MAX.carrying_add(1, true), (1, true));
+
+                assert_eq!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false));
+                assert_eq!($T::MIN.carrying_add(0, true), (1, false));
+                assert_eq!($T::MIN.carrying_add($T::MAX, true), (0, true));
+            }
+
+            #[test]
+            fn test_borrowing_sub() {
+                assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true));
+                assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true));
+                assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true));
+
+                assert_eq!($T::MAX.borrowing_sub($T::MAX, false), (0, false));
+                assert_eq!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false));
+                assert_eq!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true));
+            }
         }
     };
 }
index 3da9565a86d78588282ca040d7a5e4a676f0b1a2..324ecc8047730df5ed4407ba2f5488a726c850c5 100644 (file)
@@ -42,7 +42,7 @@ dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
 fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'] }
 
 [target.'cfg(target_os = "hermit")'.dependencies]
-hermit-abi = { version = "0.2.0", features = ['rustc-dep-of-std'] }
+hermit-abi = { version = "0.2.6", features = ['rustc-dep-of-std'] }
 
 [target.wasm32-wasi.dependencies]
 wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
index 91cff3217d21bce19ad24ebdd7632d66729a91e5..2dc12a18a8a66f029d657cfcb54af6185288a5c6 100644 (file)
@@ -992,6 +992,9 @@ pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> {
 /// the global stream.
 ///
 /// However, if the actual I/O causes an error, this function does panic.
+///
+/// Writing to non-blocking stdout/stderr can cause an error, which will lead
+/// this function to panic.
 fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
 where
     T: Write,
index a5003c66fcad72224b5ebc007c60d95c0ff0ba5e..6e4ba1404e55172333fe7897b6f78e62e07c4486 100644 (file)
@@ -49,6 +49,9 @@ macro_rules! panic {
 ///
 /// Panics if writing to `io::stdout()` fails.
 ///
+/// Writing to non-blocking stdout can cause an error, which will lead
+/// this macro to panic.
+///
 /// # Examples
 ///
 /// ```
@@ -107,6 +110,9 @@ macro_rules! print {
 ///
 /// Panics if writing to [`io::stdout`] fails.
 ///
+/// Writing to non-blocking stdout can cause an error, which will lead
+/// this macro to panic.
+///
 /// [`io::stdout`]: crate::io::stdout
 ///
 /// # Examples
@@ -147,6 +153,9 @@ macro_rules! println {
 ///
 /// Panics if writing to `io::stderr` fails.
 ///
+/// Writing to non-blocking stdout can cause an error, which will lead
+/// this macro to panic.
+///
 /// # Examples
 ///
 /// ```
@@ -179,6 +188,9 @@ macro_rules! eprint {
 ///
 /// Panics if writing to `io::stderr` fails.
 ///
+/// Writing to non-blocking stdout can cause an error, which will lead
+/// this macro to panic.
+///
 /// # Examples
 ///
 /// ```
diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs
deleted file mode 100644 (file)
index 22059ca..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-use crate::ffi::c_void;
-use crate::ptr;
-use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-use crate::sys::hermit::abi;
-use crate::sys::locks::Mutex;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-use crate::time::Duration;
-
-// The implementation is inspired by Andrew D. Birrell's paper
-// "Implementing Condition Variables with Semaphores"
-
-pub struct Condvar {
-    counter: AtomicUsize,
-    sem1: *const c_void,
-    sem2: *const c_void,
-}
-
-pub(crate) type MovableCondvar = LazyBox<Condvar>;
-
-impl LazyInit for Condvar {
-    fn init() -> Box<Self> {
-        Box::new(Self::new())
-    }
-}
-
-unsafe impl Send for Condvar {}
-unsafe impl Sync for Condvar {}
-
-impl Condvar {
-    pub fn new() -> Self {
-        let mut condvar =
-            Self { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() };
-        unsafe {
-            let _ = abi::sem_init(&mut condvar.sem1, 0);
-            let _ = abi::sem_init(&mut condvar.sem2, 0);
-        }
-        condvar
-    }
-
-    pub unsafe fn notify_one(&self) {
-        if self.counter.load(SeqCst) > 0 {
-            self.counter.fetch_sub(1, SeqCst);
-            abi::sem_post(self.sem1);
-            abi::sem_timedwait(self.sem2, 0);
-        }
-    }
-
-    pub unsafe fn notify_all(&self) {
-        let counter = self.counter.swap(0, SeqCst);
-        for _ in 0..counter {
-            abi::sem_post(self.sem1);
-        }
-        for _ in 0..counter {
-            abi::sem_timedwait(self.sem2, 0);
-        }
-    }
-
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        self.counter.fetch_add(1, SeqCst);
-        mutex.unlock();
-        abi::sem_timedwait(self.sem1, 0);
-        abi::sem_post(self.sem2);
-        mutex.lock();
-    }
-
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        self.counter.fetch_add(1, SeqCst);
-        mutex.unlock();
-        let millis = dur.as_millis().min(u32::MAX as u128) as u32;
-
-        let res = if millis > 0 {
-            abi::sem_timedwait(self.sem1, millis)
-        } else {
-            abi::sem_trywait(self.sem1)
-        };
-
-        abi::sem_post(self.sem2);
-        mutex.lock();
-        res == 0
-    }
-}
-
-impl Drop for Condvar {
-    fn drop(&mut self) {
-        unsafe {
-            let _ = abi::sem_destroy(self.sem1);
-            let _ = abi::sem_destroy(self.sem2);
-        }
-    }
-}
index 1c5efa94bd36ac50fed582ff2fee5da2a7cd23c0..f921839cf529f17cd59ca951b67bbe4d99460c61 100644 (file)
@@ -41,6 +41,9 @@ pub struct OpenOptions {
     mode: i32,
 }
 
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {}
+
 pub struct FilePermissions(!);
 
 pub struct FileType(!);
@@ -110,6 +113,11 @@ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+impl FileTimes {
+    pub fn set_accessed(&mut self, _t: SystemTime) {}
+    pub fn set_modified(&mut self, _t: SystemTime) {}
+}
+
 impl FileType {
     pub fn is_dir(&self) -> bool {
         self.0
@@ -344,6 +352,10 @@ pub fn duplicate(&self) -> io::Result<File> {
     pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
         Err(Error::from_raw_os_error(22))
     }
+
+    pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
+        Err(Error::from_raw_os_error(22))
+    }
 }
 
 impl DirBuilder {
diff --git a/library/std/src/sys/hermit/futex.rs b/library/std/src/sys/hermit/futex.rs
new file mode 100644 (file)
index 0000000..b64c174
--- /dev/null
@@ -0,0 +1,39 @@
+use super::abi;
+use crate::ptr::null;
+use crate::sync::atomic::AtomicU32;
+use crate::time::Duration;
+
+pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+    // Calculate the timeout as a relative timespec.
+    //
+    // Overflows are rounded up to an infinite timeout (None).
+    let timespec = timeout.and_then(|dur| {
+        Some(abi::timespec {
+            tv_sec: dur.as_secs().try_into().ok()?,
+            tv_nsec: dur.subsec_nanos().into(),
+        })
+    });
+
+    let r = unsafe {
+        abi::futex_wait(
+            futex.as_mut_ptr(),
+            expected,
+            timespec.as_ref().map_or(null(), |t| t as *const abi::timespec),
+            abi::FUTEX_RELATIVE_TIMEOUT,
+        )
+    };
+
+    r != -abi::errno::ETIMEDOUT
+}
+
+#[inline]
+pub fn futex_wake(futex: &AtomicU32) -> bool {
+    unsafe { abi::futex_wake(futex.as_mut_ptr(), 1) > 0 }
+}
+
+#[inline]
+pub fn futex_wake_all(futex: &AtomicU32) {
+    unsafe {
+        abi::futex_wake(futex.as_mut_ptr(), i32::MAX);
+    }
+}
index 61da096ae163883f73370305916aea26aa48d8b5..827d82900eae41d0b2f4972fd4727a2da30237a8 100644 (file)
@@ -25,6 +25,7 @@
 pub mod env;
 pub mod fd;
 pub mod fs;
+pub mod futex;
 #[path = "../unsupported/io.rs"]
 pub mod io;
 pub mod memchr;
 pub mod thread_local_key;
 pub mod time;
 
-mod condvar;
-mod mutex;
-mod rwlock;
-
+#[path = "../unix/locks"]
 pub mod locks {
-    pub use super::condvar::*;
-    pub use super::mutex::*;
-    pub use super::rwlock::*;
+    mod futex_condvar;
+    mod futex_mutex;
+    mod futex_rwlock;
+    pub(crate) use futex_condvar::MovableCondvar;
+    pub(crate) use futex_mutex::{MovableMutex, Mutex};
+    pub(crate) use futex_rwlock::{MovableRwLock, RwLock};
 }
 
 use crate::io::ErrorKind;
diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs
deleted file mode 100644 (file)
index e0184eb..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::collections::VecDeque;
-use crate::hint;
-use crate::ops::{Deref, DerefMut, Drop};
-use crate::ptr;
-use crate::sync::atomic::{AtomicUsize, Ordering};
-use crate::sys::hermit::abi;
-
-/// This type provides a lock based on busy waiting to realize mutual exclusion
-///
-/// # Description
-///
-/// This structure behaves a lot like a common mutex. There are some differences:
-///
-/// - By using busy waiting, it can be used outside the runtime.
-/// - It is a so called ticket lock and is completely fair.
-#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
-#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
-struct Spinlock<T: ?Sized> {
-    queue: AtomicUsize,
-    dequeue: AtomicUsize,
-    data: UnsafeCell<T>,
-}
-
-unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
-unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}
-
-/// A guard to which the protected data can be accessed
-///
-/// When the guard falls out of scope it will release the lock.
-struct SpinlockGuard<'a, T: ?Sized + 'a> {
-    dequeue: &'a AtomicUsize,
-    data: &'a mut T,
-}
-
-impl<T> Spinlock<T> {
-    pub const fn new(user_data: T) -> Spinlock<T> {
-        Spinlock {
-            queue: AtomicUsize::new(0),
-            dequeue: AtomicUsize::new(1),
-            data: UnsafeCell::new(user_data),
-        }
-    }
-
-    #[inline]
-    fn obtain_lock(&self) {
-        let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
-        let mut counter: u16 = 0;
-        while self.dequeue.load(Ordering::SeqCst) != ticket {
-            counter += 1;
-            if counter < 100 {
-                hint::spin_loop();
-            } else {
-                counter = 0;
-                unsafe {
-                    abi::yield_now();
-                }
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
-        self.obtain_lock();
-        SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
-    }
-}
-
-impl<T: ?Sized + Default> Default for Spinlock<T> {
-    fn default() -> Spinlock<T> {
-        Spinlock::new(Default::default())
-    }
-}
-
-impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
-    type Target = T;
-    fn deref(&self) -> &T {
-        &*self.data
-    }
-}
-
-impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
-    fn deref_mut(&mut self) -> &mut T {
-        &mut *self.data
-    }
-}
-
-impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
-    /// The dropping of the SpinlockGuard will release the lock it was created from.
-    fn drop(&mut self) {
-        self.dequeue.fetch_add(1, Ordering::SeqCst);
-    }
-}
-
-/// Realize a priority queue for tasks
-struct PriorityQueue {
-    queues: [Option<VecDeque<abi::Tid>>; abi::NO_PRIORITIES],
-    prio_bitmap: u64,
-}
-
-impl PriorityQueue {
-    pub const fn new() -> PriorityQueue {
-        PriorityQueue {
-            queues: [
-                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
-                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
-                None, None, None,
-            ],
-            prio_bitmap: 0,
-        }
-    }
-
-    /// Add a task id by its priority to the queue
-    pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
-        let i: usize = prio.into().into();
-        self.prio_bitmap |= (1 << i) as u64;
-        if let Some(queue) = &mut self.queues[i] {
-            queue.push_back(id);
-        } else {
-            let mut queue = VecDeque::new();
-            queue.push_back(id);
-            self.queues[i] = Some(queue);
-        }
-    }
-
-    fn pop_from_queue(&mut self, queue_index: usize) -> Option<abi::Tid> {
-        if let Some(queue) = &mut self.queues[queue_index] {
-            let id = queue.pop_front();
-
-            if queue.is_empty() {
-                self.prio_bitmap &= !(1 << queue_index as u64);
-            }
-
-            id
-        } else {
-            None
-        }
-    }
-
-    /// Pop the task handle with the highest priority from the queue
-    pub fn pop(&mut self) -> Option<abi::Tid> {
-        for i in 0..abi::NO_PRIORITIES {
-            if self.prio_bitmap & (1 << i) != 0 {
-                return self.pop_from_queue(i);
-            }
-        }
-
-        None
-    }
-}
-
-struct MutexInner {
-    locked: bool,
-    blocked_task: PriorityQueue,
-}
-
-impl MutexInner {
-    pub const fn new() -> MutexInner {
-        MutexInner { locked: false, blocked_task: PriorityQueue::new() }
-    }
-}
-
-pub struct Mutex {
-    inner: Spinlock<MutexInner>,
-}
-
-pub type MovableMutex = Mutex;
-
-unsafe impl Send for Mutex {}
-unsafe impl Sync for Mutex {}
-
-impl Mutex {
-    pub const fn new() -> Mutex {
-        Mutex { inner: Spinlock::new(MutexInner::new()) }
-    }
-
-    #[inline]
-    pub unsafe fn lock(&self) {
-        loop {
-            let mut guard = self.inner.lock();
-            if guard.locked == false {
-                guard.locked = true;
-                return;
-            } else {
-                let prio = abi::get_priority();
-                let id = abi::getpid();
-
-                guard.blocked_task.push(prio, id);
-                abi::block_current_task();
-                drop(guard);
-                abi::yield_now();
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn unlock(&self) {
-        let mut guard = self.inner.lock();
-        guard.locked = false;
-        if let Some(tid) = guard.blocked_task.pop() {
-            abi::wakeup_task(tid);
-        }
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        let mut guard = self.inner.lock();
-        if guard.locked == false {
-            guard.locked = true;
-        }
-        guard.locked
-    }
-}
index 74547617150b0b48bd22294456d8fbe43766072e..8a13879d8cc837ebc76fc35213c28819a944b853 100644 (file)
@@ -487,6 +487,4 @@ pub struct sockaddr_in6 {
 
     #[derive(Copy, Clone)]
     pub struct sockaddr {}
-
-    pub type socklen_t = usize;
 }
diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs
deleted file mode 100644 (file)
index 9701bab..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::sys::locks::{MovableCondvar, Mutex};
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-
-pub struct RwLock {
-    lock: Mutex,
-    cond: MovableCondvar,
-    state: UnsafeCell<State>,
-}
-
-pub type MovableRwLock = RwLock;
-
-enum State {
-    Unlocked,
-    Reading(usize),
-    Writing,
-}
-
-unsafe impl Send for RwLock {}
-unsafe impl Sync for RwLock {}
-
-// This rwlock implementation is a relatively simple implementation which has a
-// condition variable for readers/writers as well as a mutex protecting the
-// internal state of the lock. A current downside of the implementation is that
-// unlocking the lock will notify *all* waiters rather than just readers or just
-// writers. This can cause lots of "thundering stampede" problems. While
-// hopefully correct this implementation is very likely to want to be changed in
-// the future.
-
-impl RwLock {
-    pub const fn new() -> RwLock {
-        RwLock {
-            lock: Mutex::new(),
-            cond: MovableCondvar::new(),
-            state: UnsafeCell::new(State::Unlocked),
-        }
-    }
-
-    #[inline]
-    pub unsafe fn read(&self) {
-        self.lock.lock();
-        while !(*self.state.get()).inc_readers() {
-            self.cond.wait(&self.lock);
-        }
-        self.lock.unlock();
-    }
-
-    #[inline]
-    pub unsafe fn try_read(&self) -> bool {
-        self.lock.lock();
-        let ok = (*self.state.get()).inc_readers();
-        self.lock.unlock();
-        return ok;
-    }
-
-    #[inline]
-    pub unsafe fn write(&self) {
-        self.lock.lock();
-        while !(*self.state.get()).inc_writers() {
-            self.cond.wait(&self.lock);
-        }
-        self.lock.unlock();
-    }
-
-    #[inline]
-    pub unsafe fn try_write(&self) -> bool {
-        self.lock.lock();
-        let ok = (*self.state.get()).inc_writers();
-        self.lock.unlock();
-        return ok;
-    }
-
-    #[inline]
-    pub unsafe fn read_unlock(&self) {
-        self.lock.lock();
-        let notify = (*self.state.get()).dec_readers();
-        self.lock.unlock();
-        if notify {
-            // FIXME: should only wake up one of these some of the time
-            self.cond.notify_all();
-        }
-    }
-
-    #[inline]
-    pub unsafe fn write_unlock(&self) {
-        self.lock.lock();
-        (*self.state.get()).dec_writers();
-        self.lock.unlock();
-        // FIXME: should only wake up one of these some of the time
-        self.cond.notify_all();
-    }
-}
-
-impl State {
-    fn inc_readers(&mut self) -> bool {
-        match *self {
-            State::Unlocked => {
-                *self = State::Reading(1);
-                true
-            }
-            State::Reading(ref mut cnt) => {
-                *cnt += 1;
-                true
-            }
-            State::Writing => false,
-        }
-    }
-
-    fn inc_writers(&mut self) -> bool {
-        match *self {
-            State::Unlocked => {
-                *self = State::Writing;
-                true
-            }
-            State::Reading(_) | State::Writing => false,
-        }
-    }
-
-    fn dec_readers(&mut self) -> bool {
-        let zero = match *self {
-            State::Reading(ref mut cnt) => {
-                *cnt -= 1;
-                *cnt == 0
-            }
-            State::Unlocked | State::Writing => invalid(),
-        };
-        if zero {
-            *self = State::Unlocked;
-        }
-        zero
-    }
-
-    fn dec_writers(&mut self) {
-        match *self {
-            State::Writing => {}
-            State::Unlocked | State::Reading(_) => invalid(),
-        }
-        *self = State::Unlocked;
-    }
-}
-
-fn invalid() -> ! {
-    panic!("inconsistent rwlock");
-}
index 78d6ce3eff493452f934fcec8c23b4d8065bc9d1..89d0ab59be89f3edcc15eba93163fd3a1485bcc4 100644 (file)
@@ -66,6 +66,7 @@
 pub type LPWSABUF = *mut WSABUF;
 pub type LPWSAOVERLAPPED = *mut c_void;
 pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void;
+pub type BCRYPT_ALG_HANDLE = LPVOID;
 
 pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE;
 pub type PLARGE_INTEGER = *mut c_longlong;
@@ -278,6 +279,7 @@ pub struct ipv6_mreq {
 pub const STATUS_PENDING: NTSTATUS = 0x103 as _;
 pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _;
 pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _;
+pub const STATUS_NOT_SUPPORTED: NTSTATUS = 0xC00000BB_u32 as _;
 
 // Equivalent to the `NT_SUCCESS` C preprocessor macro.
 // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
@@ -285,7 +287,8 @@ pub fn nt_success(status: NTSTATUS) -> bool {
     status >= 0
 }
 
-pub const BCRYPT_RNG_ALG_HANDLE: usize = 0x81;
+// "RNG\0"
+pub const BCRYPT_RNG_ALGORITHM: &[u16] = &[b'R' as u16, b'N' as u16, b'G' as u16, 0];
 
 #[repr(C)]
 pub struct UNICODE_STRING {
@@ -1229,11 +1232,18 @@ pub fn select(
     // >= Vista / Server 2008
     // https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
     pub fn BCryptGenRandom(
-        hAlgorithm: LPVOID,
+        hAlgorithm: BCRYPT_ALG_HANDLE,
         pBuffer: *mut u8,
         cbBuffer: ULONG,
         dwFlags: ULONG,
     ) -> NTSTATUS;
+    pub fn BCryptOpenAlgorithmProvider(
+        phalgorithm: *mut BCRYPT_ALG_HANDLE,
+        pszAlgId: LPCWSTR,
+        pszimplementation: LPCWSTR,
+        dwflags: ULONG,
+    ) -> NTSTATUS;
+    pub fn BCryptCloseAlgorithmProvider(hAlgorithm: BCRYPT_ALG_HANDLE, dwFlags: ULONG) -> NTSTATUS;
 }
 
 // Functions that aren't available on every version of Windows that we support,
index c2ad592dfea73379ca8a433aab2179307a7f2ab0..155d0297e49acfdfd8881c948645acbbdcd4f9e9 100644 (file)
@@ -403,7 +403,7 @@ pub fn file_attr(&self) -> io::Result<FileAttr> {
                     mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
                 ))?;
                 if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
-                    reparse_tag = attr_tag.ReparseTag;
+                    attr.reparse_tag = attr_tag.ReparseTag;
                 }
             }
             Ok(attr)
index a0f822070992f5032e6f54a5c16b77d19c0eaa85..beeca1917a9af74e40516748a93c8aa26594c5ca 100644 (file)
@@ -198,14 +198,7 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
 
     match path.bytes().iter().position(|&x| separator(x)) {
         Some(separator_start) => {
-            let mut separator_end = separator_start + 1;
-
-            // a series of multiple separator characters is treated as a single separator,
-            // except in verbatim paths
-            while !verbatim && separator_end < path.len() && separator(path.bytes()[separator_end])
-            {
-                separator_end += 1;
-            }
+            let separator_end = separator_start + 1;
 
             let component = &path.bytes()[..separator_start];
 
index a71175069052f0539c8af1b850fc9ad48eee3d7d..623c6236166da6e3ce7a6768fb66e157553dab24 100644 (file)
@@ -31,16 +31,6 @@ fn test_parse_next_component() {
         parse_next_component(OsStr::new(r"servershare"), false),
         (OsStr::new(r"servershare"), OsStr::new(""))
     );
-
-    assert_eq!(
-        parse_next_component(OsStr::new(r"server/\//\/\\\\/////\/share"), false),
-        (OsStr::new(r"server"), OsStr::new(r"share"))
-    );
-
-    assert_eq!(
-        parse_next_component(OsStr::new(r"server\\\\\\\\\\\\\\share"), true),
-        (OsStr::new(r"server"), OsStr::new(r"\\\\\\\\\\\\\share"))
-    );
 }
 
 #[test]
@@ -126,3 +116,22 @@ fn test_windows_prefix_components() {
     assert_eq!(drive.as_os_str(), OsStr::new("C:"));
     assert_eq!(components.as_path(), Path::new(""));
 }
+
+/// See #101358.
+///
+/// Note that the exact behaviour here may change in the future.
+/// In which case this test will need to adjusted.
+#[test]
+fn broken_unc_path() {
+    use crate::path::Component;
+
+    let mut components = Path::new(r"\\foo\\bar\\").components();
+    assert_eq!(components.next(), Some(Component::RootDir));
+    assert_eq!(components.next(), Some(Component::Normal("foo".as_ref())));
+    assert_eq!(components.next(), Some(Component::Normal("bar".as_ref())));
+
+    let mut components = Path::new("//foo//bar//").components();
+    assert_eq!(components.next(), Some(Component::RootDir));
+    assert_eq!(components.next(), Some(Component::Normal("foo".as_ref())));
+    assert_eq!(components.next(), Some(Component::Normal("bar".as_ref())));
+}
index 8b9697884364c837ac44f8308d184ee7ab0eb78d..d6cd8f80271620c1d619193d90a1bdfe4e75b097 100644 (file)
@@ -22,7 +22,6 @@
 //! [`RtlGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
 //! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
 //! [Pseudo-handle]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-pseudo-handles
-use crate::io;
 use crate::mem;
 use crate::ptr;
 use crate::sys::c;
 /// [`HashMap`]: crate::collections::HashMap
 /// [`RandomState`]: crate::collections::hash_map::RandomState
 pub fn hashmap_random_keys() -> (u64, u64) {
-    let mut v = (0, 0);
-    let ret = unsafe {
-        let size = mem::size_of_val(&v).try_into().unwrap();
-        c::BCryptGenRandom(
-            // BCRYPT_RNG_ALG_HANDLE is only supported in Windows 10+.
-            // So for Windows 8.1 and Windows 7 we'll need a fallback when this fails.
-            ptr::invalid_mut(c::BCRYPT_RNG_ALG_HANDLE),
-            ptr::addr_of_mut!(v).cast(),
-            size,
-            0,
-        )
-    };
-    if ret != 0 { fallback_rng() } else { v }
+    Rng::open().and_then(|rng| rng.gen_random_keys()).unwrap_or_else(fallback_rng)
+}
+
+struct Rng(c::BCRYPT_ALG_HANDLE);
+impl Rng {
+    #[cfg(miri)]
+    fn open() -> Result<Self, c::NTSTATUS> {
+        const BCRYPT_RNG_ALG_HANDLE: c::BCRYPT_ALG_HANDLE = ptr::invalid_mut(0x81);
+        let _ = (
+            c::BCryptOpenAlgorithmProvider,
+            c::BCryptCloseAlgorithmProvider,
+            c::BCRYPT_RNG_ALGORITHM,
+            c::STATUS_NOT_SUPPORTED,
+        );
+        Ok(Self(BCRYPT_RNG_ALG_HANDLE))
+    }
+    #[cfg(not(miri))]
+    // Open a handle to the RNG algorithm.
+    fn open() -> Result<Self, c::NTSTATUS> {
+        use crate::sync::atomic::AtomicPtr;
+        use crate::sync::atomic::Ordering::{Acquire, Release};
+        const ERROR_VALUE: c::LPVOID = ptr::invalid_mut(usize::MAX);
+
+        // An atomic is used so we don't need to reopen the handle every time.
+        static HANDLE: AtomicPtr<crate::ffi::c_void> = AtomicPtr::new(ptr::null_mut());
+
+        let mut handle = HANDLE.load(Acquire);
+        // We use a sentinel value to designate an error occurred last time.
+        if handle == ERROR_VALUE {
+            Err(c::STATUS_NOT_SUPPORTED)
+        } else if handle.is_null() {
+            let status = unsafe {
+                c::BCryptOpenAlgorithmProvider(
+                    &mut handle,
+                    c::BCRYPT_RNG_ALGORITHM.as_ptr(),
+                    ptr::null(),
+                    0,
+                )
+            };
+            if c::nt_success(status) {
+                // If another thread opens a handle first then use that handle instead.
+                let result = HANDLE.compare_exchange(ptr::null_mut(), handle, Release, Acquire);
+                if let Err(previous_handle) = result {
+                    // Close our handle and return the previous one.
+                    unsafe { c::BCryptCloseAlgorithmProvider(handle, 0) };
+                    handle = previous_handle;
+                }
+                Ok(Self(handle))
+            } else {
+                HANDLE.store(ERROR_VALUE, Release);
+                Err(status)
+            }
+        } else {
+            Ok(Self(handle))
+        }
+    }
+
+    fn gen_random_keys(self) -> Result<(u64, u64), c::NTSTATUS> {
+        let mut v = (0, 0);
+        let status = unsafe {
+            let size = mem::size_of_val(&v).try_into().unwrap();
+            c::BCryptGenRandom(self.0, ptr::addr_of_mut!(v).cast(), size, 0)
+        };
+        if c::nt_success(status) { Ok(v) } else { Err(status) }
+    }
 }
 
 /// Generate random numbers using the fallback RNG function (RtlGenRandom)
 #[cfg(not(target_vendor = "uwp"))]
 #[inline(never)]
-fn fallback_rng() -> (u64, u64) {
+fn fallback_rng(rng_status: c::NTSTATUS) -> (u64, u64) {
     let mut v = (0, 0);
     let ret =
         unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) };
 
-    if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) }
+    if ret != 0 {
+        v
+    } else {
+        panic!(
+            "RNG broken: {rng_status:#x}, fallback RNG broken: {}",
+            crate::io::Error::last_os_error()
+        )
+    }
 }
 
 /// We can't use RtlGenRandom with UWP, so there is no fallback
 #[cfg(target_vendor = "uwp")]
 #[inline(never)]
-fn fallback_rng() -> (u64, u64) {
-    panic!("fallback RNG broken: RtlGenRandom() not supported on UWP");
+fn fallback_rng(rng_status: c::NTSTATUS) -> (u64, u64) {
+    panic!("RNG broken: {rng_status:#x} fallback RNG broken: RtlGenRandom() not supported on UWP");
 }
index cbd7832eb7a4c8e0a1cc932a3463d6c6d1249da1..f86a9a555d322e02c08c885aadcd4af194795921 100644 (file)
@@ -7,6 +7,7 @@
         target_os = "openbsd",
         target_os = "dragonfly",
         target_os = "fuchsia",
+        target_os = "hermit",
     ))] {
         mod futex;
         pub use futex::Parker;
index a17185b6f707545551578758fc1216ca5f5be016..ceea6986e3335afdd67f4e3989a80185dbc514f3 100644 (file)
 //! Threads are able to have associated names for identification purposes. By default, spawned
 //! threads are unnamed. To specify a name for a thread, build the thread with [`Builder`] and pass
 //! the desired thread name to [`Builder::name`]. To retrieve the thread name from within the
-//! thread, use [`Thread::name`]. A couple examples of where the name of a thread gets used:
+//! thread, use [`Thread::name`]. A couple of examples where the name of a thread gets used:
 //!
 //! * If a panic occurs in a named thread, the thread name will be printed in the panic message.
 //! * The thread name is provided to the OS where applicable (e.g., `pthread_setname_np` in
index 2dad41bb18fceb48cc5a73848615dba9b14ae7bc..95e711737738a4e661fe1f86c0b7edfb09e3241c 100644 (file)
@@ -67,6 +67,7 @@ features = [
     "psapi",
     "impl-default",
     "timezoneapi",
+    "winbase",
 ]
 
 [dev-dependencies]
index 3a00e258e00e5b142ac82b3e73ad6f21c7e7ce61..0ebabbd5ca5c04599f065a52f7654a93e6232fcc 100644 (file)
@@ -197,9 +197,11 @@ fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
                 ptr::null_mut(),
             );
 
-            let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize];
-            let db = data.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
-            let buf = &mut (*db).ReparseTarget as *mut u16;
+            #[repr(C, align(8))]
+            struct Align8<T>(T);
+            let mut data = Align8([0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]);
+            let db = data.0.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
+            let buf = core::ptr::addr_of_mut!((*db).ReparseTarget) as *mut u16;
             let mut i = 0;
             // FIXME: this conversion is very hacky
             let v = br"\??\";
@@ -219,7 +221,7 @@ fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
             let res = DeviceIoControl(
                 h as *mut _,
                 FSCTL_SET_REPARSE_POINT,
-                data.as_ptr() as *mut _,
+                db.cast(),
                 (*db).ReparseDataLength + 8,
                 ptr::null_mut(),
                 0,
index 1025f5bce802cd5bd815696fbc9594522c741a61..fa780e1e45ea6df07991992ca1cc912693f1c3be 100755 (executable)
@@ -4,7 +4,7 @@ set -ex
 
 source shared.sh
 
-LLVM=llvmorg-14.0.5
+LLVM=llvmorg-15.0.0
 
 mkdir llvm-project
 cd llvm-project
index 742fbe11d9c6fbab4ae13be216ad7a35e65643c8..fe090a73327ce2f538bbbafb29ddb1b138f2b9ff 100644 (file)
@@ -213,7 +213,7 @@ target | std | host | notes
 [`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ |
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 `aarch64-unknown-hermit` | ✓ |  | ARM64 HermitCore
-`aarch64-unknown-uefi` | * |  | ARM64 UEFI
+[`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | * |  | ARM64 UEFI
 `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI)
 `aarch64-unknown-netbsd` | ✓ | ✓ |
 [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD
@@ -250,7 +250,7 @@ target | std | host | notes
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
 `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2
 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD
-`i686-unknown-uefi` | * |  | 32-bit UEFI
+[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | * |  | 32-bit UEFI
 `i686-uwp-windows-gnu` | ? |  |
 `i686-uwp-windows-msvc` | ? |  |
 `i686-wrs-vxworks` | ? |  |
@@ -307,7 +307,7 @@ target | std | host | notes
 `x86_64-unknown-l4re-uclibc` | ? |  |
 `x86_64-unknown-none-linuxkernel` | * |  | Linux kernel modules
 [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
-`x86_64-unknown-uefi` | * |  | 64-bit UEFI
+[`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | * |  | 64-bit UEFI
 `x86_64-uwp-windows-gnu` | ✓ |  |
 `x86_64-uwp-windows-msvc` | ✓ |  |
 `x86_64-wrs-vxworks` | ? |  |
index 3c9eecbe128d6ca9b04272b1e1bbe6b454e4466c..1d5ad3cce1840bd44930b80f62e83642b88d84b1 100644 (file)
@@ -422,6 +422,7 @@ Next, we'll build a package manifest as defined by our manifest:
 
 ```sh
 ${SDK_PATH}/tools/${ARCH}/pm \
+    -api-level $(${SDK_PATH}/tools/${ARCH}/ffx version -v | grep "api-level" | head -1 |  awk -F ' ' '{print $2}') \
     -o pkg/hello_fuchsia_manifest \
     -m pkg/hello_fuchsia.manifest \
     build \
index 23fc5b3052d8da9899736362841269a1e12b9ef5..5fd208ae7571c979d61c7b3342d13bff6da7c832 100644 (file)
@@ -26,9 +26,9 @@ fn main() {
 
 ## Limitations
 
-Currently, this feature is only supported on `-windows-msvc` targets.  Non-Windows platforms don't have import
-libraries, and an incompatibility between LLVM and the BFD linker means that it is not currently supported on
-`-windows-gnu` targets.
+This feature is unstable for the `x86` architecture, and stable for all other architectures.
 
-On the `i686-pc-windows-msvc` target, this feature supports only the `cdecl`, `stdcall`, `system`, and `fastcall`
-calling conventions.
+This feature is only supported on Windows.
+
+On the `x86` architecture, this feature supports only the `cdecl`, `stdcall`, `system`, `fastcall`, and
+`vectorcall` calling conventions.
index 27fb018aecaddfa399f274705308c93ba181caf5..991c881bae10d8b707b2e1c3cd43ba4725fb7076 100644 (file)
@@ -132,9 +132,11 @@ while work_list:
         work_list |= set(item["inner"]["items"]) - visited
     elif item["kind"] == "struct":
         check_generics(item["inner"]["generics"])
-        work_list |= (
-            set(item["inner"]["fields"]) | set(item["inner"]["impls"])
-        ) - visited
+        work_list |= set(item["inner"]["impls"]) - visited
+        if "tuple" in item["inner"]["kind"]:
+            work_list |= set(filter(None, item["inner"]["kind"]["tuple"])) - visited
+        elif "plain" in item["inner"]["kind"]:
+            work_list |= set(item["inner"]["kind"]["plain"]["fields"]) - visited
     elif item["kind"] == "struct_field":
         check_type(item["inner"])
     elif item["kind"] == "enum":
index be2227f47af613c50797412a1f30d55160049c30..bca3f4db4a85460c0f686fa3baf3b7f24726365d 100644 (file)
@@ -50,14 +50,23 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
     let mut inserted = FxHashSet::default();
     items.extend(doc.foreigns.iter().map(|(item, renamed)| {
         let item = clean_maybe_renamed_foreign_item(cx, item, *renamed);
-        if let Some(name) = item.name {
+        if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) {
             inserted.insert((item.type_(), name));
         }
         item
     }));
-    items.extend(doc.mods.iter().map(|x| {
-        inserted.insert((ItemType::Module, x.name));
-        clean_doc_module(x, cx)
+    items.extend(doc.mods.iter().filter_map(|x| {
+        if !inserted.insert((ItemType::Module, x.name)) {
+            return None;
+        }
+        let item = clean_doc_module(x, cx);
+        if item.attrs.lists(sym::doc).has_word(sym::hidden) {
+            // Hidden modules are stripped at a later stage.
+            // If a hidden module has the same name as a visible one, we want
+            // to keep both of them around.
+            inserted.remove(&(ItemType::Module, x.name));
+        }
+        Some(item)
     }));
 
     // Split up imports from all other items.
@@ -72,7 +81,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
         }
         let v = clean_maybe_renamed_item(cx, item, *renamed);
         for item in &v {
-            if let Some(name) = item.name {
+            if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) {
                 inserted.insert((item.type_(), name));
             }
         }
@@ -190,7 +199,7 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
     )
 }
 
-fn clean_lifetime<'tcx>(lifetime: hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
+fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
     let def = cx.tcx.named_region(lifetime.hir_id);
     if let Some(
         rl::Region::EarlyBound(node_id)
@@ -370,9 +379,9 @@ fn clean_type_outlives_predicate<'tcx>(
 }
 
 fn clean_middle_term<'tcx>(term: ty::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term {
-    match term {
-        ty::Term::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)),
-        ty::Term::Const(c) => Term::Constant(clean_middle_const(c, cx)),
+    match term.unpack() {
+        ty::TermKind::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)),
+        ty::TermKind::Const(c) => Term::Constant(clean_middle_const(c, cx)),
     }
 }
 
@@ -495,7 +504,7 @@ fn clean_generic_param<'tcx>(
                     .filter(|bp| !bp.in_where_clause)
                     .flat_map(|bp| bp.bounds)
                     .map(|bound| match bound {
-                        hir::GenericBound::Outlives(lt) => clean_lifetime(*lt, cx),
+                        hir::GenericBound::Outlives(lt) => clean_lifetime(lt, cx),
                         _ => panic!(),
                     })
                     .collect()
@@ -1392,7 +1401,7 @@ fn maybe_expand_private_type_alias<'tcx>(
                     }
                     _ => None,
                 });
-                if let Some(lt) = lifetime.cloned() {
+                if let Some(lt) = lifetime {
                     let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
                     let cleaned =
                         if !lt.is_elided() { clean_lifetime(lt, cx) } else { Lifetime::elided() };
@@ -1492,7 +1501,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             Array(Box::new(clean_ty(ty, cx)), length)
         }
         TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
-        TyKind::OpaqueDef(item_id, _) => {
+        TyKind::OpaqueDef(item_id, _, _) => {
             let item = cx.tcx.hir().item(item_id);
             if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
                 ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
@@ -1777,7 +1786,7 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     }
 }
 
-pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility {
+pub(crate) fn clean_visibility(vis: ty::Visibility<DefId>) -> Visibility {
     match vis {
         ty::Visibility::Public => Visibility::Public,
         ty::Visibility::Restricted(module) => Visibility::Restricted(module),
@@ -2111,8 +2120,8 @@ fn clean_use_statement<'tcx>(
     // `pub(super)` or higher. If the current module is the top level
     // module, there isn't really a parent module, which makes the results
     // meaningless. In this case, we make sure the answer is `false`.
-    let is_visible_from_parent_mod = visibility.is_accessible_from(parent_mod.to_def_id(), cx.tcx)
-        && !current_mod.is_top_level_module();
+    let is_visible_from_parent_mod =
+        visibility.is_accessible_from(parent_mod, cx.tcx) && !current_mod.is_top_level_module();
 
     if pub_underscore {
         if let Some(ref inline) = inline_attr {
index d6bb7c6c4fc89055e6540f6a19db0209aaebfbb1..f973fd0889ebc364b2bd1cd8d213527d6674baf4 100644 (file)
@@ -510,7 +510,7 @@ pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
             .get(&self.item_id)
             .map_or(&[][..], |v| v.as_slice())
             .iter()
-            .filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
+            .filter_map(|ItemLink { link: s, link_text, page_id: did, ref fragment }| {
                 debug!(?did);
                 if let Ok((mut href, ..)) = href(*did, cx) {
                     debug!(?href);
@@ -1134,7 +1134,10 @@ pub(crate) struct ItemLink {
     /// This may not be the same as `link` if there was a disambiguator
     /// in an intra-doc link (e.g. \[`fn@f`\])
     pub(crate) link_text: String,
-    pub(crate) did: DefId,
+    /// The `DefId` of the Item whose **HTML Page** contains the item being
+    /// linked to. This will be different to `item_id` on item's that don't
+    /// have their own page, such as struct fields and enum variants.
+    pub(crate) page_id: DefId,
     /// The url fragment to append to the link
     pub(crate) fragment: Option<UrlFragment>,
 }
@@ -2532,7 +2535,8 @@ mod size_asserts {
     // These are in alphabetical order, which is easy to maintain.
     static_assert_size!(Crate, 72); // frequently moved by-value
     static_assert_size!(DocFragment, 32);
-    static_assert_size!(GenericArg, 64);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(GenericArg, 56);
     static_assert_size!(GenericArgs, 32);
     static_assert_size!(GenericParamDef, 56);
     static_assert_size!(Item, 56);
index a9d511ae11e8b92db472859e788db67d7b317d99..395f213ca87c353836a89a36537f84b36dcd99ca 100644 (file)
@@ -511,8 +511,8 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
         | Res::Err => return res.def_id(),
         Res::Def(
             TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst
-            | InlineConst | OpaqueTy | Field | LifetimeParam | GlobalAsm | Impl | Closure
-            | Generator,
+            | InlineConst | OpaqueTy | ImplTraitPlaceholder | Field | LifetimeParam | GlobalAsm
+            | Impl | Closure | Generator,
             id,
         ) => return id,
     };
index 0a7ee2005915baa6cbb977aefd12b44361962fdf..f21e60a64e0055f87060c44de8b5b492866deb66 100644 (file)
@@ -135,6 +135,7 @@ fn from(other: DefKind) -> Self {
             | DefKind::AnonConst
             | DefKind::InlineConst
             | DefKind::OpaqueTy
+            | DefKind::ImplTraitPlaceholder
             | DefKind::Field
             | DefKind::LifetimeParam
             | DefKind::GlobalAsm
index bb8e46af76286d9b74a22e54e868eb464094ed41..84781d898385921d1da249da9eb39eae1177a4fa 100644 (file)
@@ -52,35 +52,14 @@ pub(crate) fn render_example_with_highlighting(
     tooltip: Tooltip,
     playground_button: Option<&str>,
 ) {
-    let class = match tooltip {
-        Tooltip::Ignore => " ignore",
-        Tooltip::CompileFail => " compile_fail",
-        Tooltip::ShouldPanic => " should_panic",
-        Tooltip::Edition(_) => " edition",
-        Tooltip::None => "",
-    };
-
-    if tooltip != Tooltip::None {
-        write!(
-            out,
-            "<div class='information'><div class='tooltip{}'{}>ⓘ</div></div>",
-            class,
-            if let Tooltip::Edition(edition_info) = tooltip {
-                format!(" data-edition=\"{}\"", edition_info)
-            } else {
-                String::new()
-            },
-        );
-    }
-
-    write_header(out, &format!("rust-example-rendered{}", class), None);
+    write_header(out, "rust-example-rendered", None, tooltip);
     write_code(out, src, None, None);
     write_footer(out, playground_button);
 }
 
 /// Highlights `src` as a macro, returning the HTML output.
 pub(crate) fn render_macro_with_highlighting(src: &str, out: &mut Buffer) {
-    write_header(out, "macro", None);
+    write_header(out, "macro", None, Tooltip::None);
     write_code(out, src, None, None);
     write_footer(out, None);
 }
@@ -93,20 +72,42 @@ pub(crate) fn render_source_with_highlighting(
     href_context: HrefContext<'_, '_, '_>,
     decoration_info: DecorationInfo,
 ) {
-    write_header(out, "", Some(line_numbers));
+    write_header(out, "", Some(line_numbers), Tooltip::None);
     write_code(out, src, Some(href_context), Some(decoration_info));
     write_footer(out, None);
 }
 
-fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>) {
+fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, tooltip: Tooltip) {
     write!(out, "<div class=\"example-wrap\">");
+
+    let tooltip_class = match tooltip {
+        Tooltip::Ignore => " ignore",
+        Tooltip::CompileFail => " compile_fail",
+        Tooltip::ShouldPanic => " should_panic",
+        Tooltip::Edition(_) => " edition",
+        Tooltip::None => "",
+    };
+
+    if tooltip != Tooltip::None {
+        write!(
+            out,
+            "<div class='information'><div class='tooltip{}'{}>ⓘ</div></div>",
+            tooltip_class,
+            if let Tooltip::Edition(edition_info) = tooltip {
+                format!(" data-edition=\"{}\"", edition_info)
+            } else {
+                String::new()
+            },
+        );
+    }
+
     if let Some(extra) = extra_content {
         out.push_buffer(extra);
     }
-    if class.is_empty() {
+    if class.is_empty() && tooltip_class.is_empty() {
         write!(out, "<pre class=\"rust\">");
     } else {
-        write!(out, "<pre class=\"rust {}\">", class);
+        write!(out, "<pre class=\"rust {class}{tooltip_class}\">");
     }
     write!(out, "<code>");
 }
index 3502d97d470fecb56c39d3012db24cfb62ea1bb2..dae2ff4e226370646d391d90ad0de9dee72ec4ed 100644 (file)
@@ -197,10 +197,6 @@ h4.code-header {
        position: relative;
 }
 
-div.impl-items > div {
-       padding-left: 0;
-}
-
 h1, h2, h3, h4, h5, h6,
 .sidebar,
 .mobile-topbar,
@@ -212,7 +208,6 @@ a.source,
 span.since,
 #source-sidebar, #sidebar-toggle,
 details.rustdoc-toggle > summary::before,
-div.impl-items > div:not(.docblock):not(.item-info),
 .content ul.crate a.crate,
 a.srclink,
 #help-button > button,
@@ -352,10 +347,6 @@ img {
        max-width: 100%;
 }
 
-li {
-       position: relative;
-}
-
 .source .content {
        max-width: none;
        overflow: visible;
@@ -601,19 +592,10 @@ h2.location a {
        margin: 0;
 }
 
-#search {
-       position: relative;
-}
-
 .search-loading {
        text-align: center;
 }
 
-#results > table {
-       width: 100%;
-       table-layout: fixed;
-}
-
 .content > .example-wrap pre.line-numbers {
        position: relative;
        -webkit-user-select: none;
@@ -662,7 +644,7 @@ h2.location a {
        position: relative;
 }
 
-.docblock > :not(.information):not(.more-examples-toggle) {
+.docblock > :not(.more-examples-toggle):not(.example-wrap) {
        max-width: 100%;
        overflow-x: auto;
 }
@@ -704,9 +686,6 @@ pre, .rustdoc.source .example-wrap {
 #main-content {
        position: relative;
 }
-#main-content > .since {
-       top: inherit;
-}
 
 .content table {
        border-spacing: 0 5px;
@@ -752,11 +731,6 @@ pre, .rustdoc.source .example-wrap {
        font-size: 0.875rem;
 }
 
-.content .methods > div:not(.notable-traits):not(.method) {
-       margin-left: 40px;
-       margin-bottom: 15px;
-}
-
 .item-info {
        display: block;
 }
@@ -770,10 +744,6 @@ pre, .rustdoc.source .example-wrap {
        margin-left: 24px;
 }
 
-.sub-variant > div > .item-info {
-       margin-top: initial;
-}
-
 .content .impl-items .docblock, .content .impl-items .item-info {
        margin-bottom: .6em;
 }
@@ -999,7 +969,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
 
 .search-results > a {
        display: block;
-       width: 100%;
        /* A little margin ensures the browser's outlining of focused links has room to display. */
        margin-left: 2px;
        margin-right: 2px;
@@ -1182,6 +1151,42 @@ pre.rust .question-mark {
        font-weight: bold;
 }
 
+pre.compile_fail,
+pre.should_panic {
+       border-left: 2px solid var(--codeblock-error-color);
+}
+
+pre.ignore {
+       border-left: 2px solid var(--codeblock-ignore-color);
+}
+
+.example-wrap:hover pre.compile_fail,
+.example-wrap:hover pre.should_panic {
+       border-left: 2px solid var(--codeblock-error-hover-color);
+}
+
+.example-wrap:hover pre.ignore {
+       border-left: 2px solid var(--codeblock-ignore-hover-color);
+}
+
+.tooltip.compile_fail,
+.tooltip.should_panic {
+       color: var(--codeblock-error-color);
+}
+
+.tooltip.ignore {
+       color:  var(--codeblock-ignore-color);
+}
+
+.example-wrap:hover .tooltip.compile_fail,
+.example-wrap:hover .tooltip.should_panic {
+       color: var(--codeblock-error-hover-color);
+}
+
+.example-wrap:hover .tooltip.ignore {
+       color: var(--codeblock-ignore-hover-color);
+}
+
 a.test-arrow {
        display: inline-block;
        visibility: hidden;
@@ -1466,9 +1471,7 @@ pre.rust {
        border-radius: 2px;
        cursor: pointer;
 }
-#settings-menu {
-       padding: 0;
-}
+
 #settings-menu > a, #help-button > button {
        padding: 5px;
        height: 100%;
@@ -1545,10 +1548,6 @@ kbd {
        cursor: default;
 }
 
-#implementations-list > h3 > span.in-band {
-       width: 100%;
-}
-
 #main-content > ul {
        padding-left: 10px;
 }
@@ -1719,7 +1718,7 @@ in storage.js plus the media query with (max-width: 700px)
        to prevent an overlay between the "collapse toggle" and the information tooltip.
        However, it's not needed with smaller screen width because the doc/code block is always put
        "one line" below. */
-       .docblock > .information:first-child > .tooltip {
+       .docblock > .example-wrap:first-child > .information > .tooltip {
                margin-top: 16px;
        }
 
@@ -1760,7 +1759,6 @@ in storage.js plus the media query with (min-width: 701px)
                padding-top: 0px;
        }
 
-       .rustdoc,
        .main-heading {
                flex-direction: column;
        }
@@ -2047,11 +2045,6 @@ in storage.js plus the media query with (min-width: 701px)
                height: 73px;
        }
 
-       #main-content > table td {
-               word-break: break-word;
-               width: 50%;
-       }
-
        #crate-search {
                border-radius: 4px;
        }
index be359a8e72d25d250631a2f651dfb343454b9f04..74de113495c2ed017d218d5b64dea56e499463b2 100644 (file)
@@ -23,6 +23,10 @@ Original by Dempfi (https://github.com/dempfi/ayu)
        --copy-path-button-color: #fff;
        --copy-path-img-filter: invert(70%);
        --copy-path-img-hover-filter: invert(100%);
+       --codeblock-error-hover-color: rgb(255, 0, 0);
+       --codeblock-error-color: rgba(255, 0, 0, .5);
+       --codeblock-ignore-hover-color: rgb(255, 142, 0);
+       --codeblock-ignore-color: rgba(255, 142, 0, .6);
 }
 
 .slider {
@@ -244,54 +248,6 @@ a.test-arrow:hover {
        border-right: 3px solid rgba(255, 180, 76, 0.85);
 }
 
-pre.compile_fail {
-       border-left: 2px solid rgba(255,0,0,.4);
-}
-
-pre.compile_fail:hover, .information:hover + pre.compile_fail {
-       border-left: 2px solid #f00;
-}
-
-pre.should_panic {
-       border-left: 2px solid rgba(255,0,0,.4);
-}
-
-pre.should_panic:hover, .information:hover + pre.should_panic {
-       border-left: 2px solid #f00;
-}
-
-pre.ignore {
-       border-left: 2px solid rgba(255,142,0,.6);
-}
-
-pre.ignore:hover, .information:hover + pre.ignore {
-       border-left: 2px solid #ff9200;
-}
-
-.tooltip.compile_fail {
-       color: rgba(255,0,0,.5);
-}
-
-.information > .compile_fail:hover {
-       color: #f00;
-}
-
-.tooltip.should_panic {
-       color: rgba(255,0,0,.5);
-}
-
-.information > .should_panic:hover {
-       color: #f00;
-}
-
-.tooltip.ignore {
-       color: rgba(255,142,0,.6);
-}
-
-.information > .ignore:hover {
-       color: #ff9200;
-}
-
 .search-failed a {
        color: #39AFD7;
 }
index f633abe94e5af075b6b14973faadc2b88ab71623..153b40f05d8de108e28fdea657dc686e4a7c01bb 100644 (file)
        --copy-path-button-color: #999;
        --copy-path-img-filter: invert(50%);
        --copy-path-img-hover-filter: invert(65%);
+       --codeblock-error-hover-color: rgb(255, 0, 0);
+       --codeblock-error-color: rgba(255, 0, 0, .5);
+       --codeblock-ignore-hover-color: rgb(255, 142, 0);
+       --codeblock-ignore-color: rgba(255, 142, 0, .6);
 }
 
 .slider {
@@ -194,54 +198,6 @@ a.test-arrow:hover{
        border-right: 3px solid #bb7410;
 }
 
-pre.compile_fail {
-       border-left: 2px solid rgba(255,0,0,.8);
-}
-
-pre.compile_fail:hover, .information:hover + pre.compile_fail {
-       border-left: 2px solid #f00;
-}
-
-pre.should_panic {
-       border-left: 2px solid rgba(255,0,0,.8);
-}
-
-pre.should_panic:hover, .information:hover + pre.should_panic {
-       border-left: 2px solid #f00;
-}
-
-pre.ignore {
-       border-left: 2px solid rgba(255,142,0,.6);
-}
-
-pre.ignore:hover, .information:hover + pre.ignore {
-       border-left: 2px solid #ff9200;
-}
-
-.tooltip.compile_fail {
-       color: rgba(255,0,0,.8);
-}
-
-.information > .compile_fail:hover {
-       color: #f00;
-}
-
-.tooltip.should_panic {
-       color: rgba(255,0,0,.8);
-}
-
-.information > .should_panic:hover {
-       color: #f00;
-}
-
-.tooltip.ignore {
-       color: rgba(255,142,0,.6);
-}
-
-.information > .ignore:hover {
-       color: #ff9200;
-}
-
 .search-failed a {
        color: #0089ff;
 }
index 875bb79302560f4b1754ab6a5c78470123abf6cb..9ced9e7b5ce32ea8e4754e7fd71dba5a78a7e424 100644 (file)
        --copy-path-button-color: #999;
        --copy-path-img-filter: invert(50%);
        --copy-path-img-hover-filter: invert(35%);
+       --codeblock-error-hover-color: rgb(255, 0, 0);
+       --codeblock-error-color: rgba(255, 0, 0, .5);
+       --codeblock-ignore-hover-color: rgb(255, 142, 0);
+       --codeblock-ignore-color: rgba(255, 142, 0, .6);
 }
 
 .slider {
@@ -180,54 +184,6 @@ a.test-arrow:hover{
        border-right: 3px solid #AD7C37;
 }
 
-pre.compile_fail {
-       border-left: 2px solid rgba(255,0,0,.5);
-}
-
-pre.compile_fail:hover, .information:hover + pre.compile_fail {
-       border-left: 2px solid #f00;
-}
-
-pre.should_panic {
-       border-left: 2px solid rgba(255,0,0,.5);
-}
-
-pre.should_panic:hover, .information:hover + pre.should_panic {
-       border-left: 2px solid #f00;
-}
-
-pre.ignore {
-       border-left: 2px solid rgba(255,142,0,.6);
-}
-
-pre.ignore:hover, .information:hover + pre.ignore {
-       border-left: 2px solid #ff9200;
-}
-
-.tooltip.compile_fail {
-       color: rgba(255,0,0,.5);
-}
-
-.information > .compile_fail:hover {
-       color: #f00;
-}
-
-.tooltip.should_panic {
-       color: rgba(255,0,0,.5);
-}
-
-.information > .should_panic:hover {
-       color: #f00;
-}
-
-.tooltip.ignore {
-       color: rgba(255,142,0,.6);
-}
-
-.information > .ignore:hover {
-       color: #ff9200;
-}
-
 .search-failed a {
        color: #3873AD;
 }
index 7f61c95e794b0696fde560ee74a6d42dd8a3ac95..6e9660ddcc96a651f24ac02c5aa9197503c523b9 100644 (file)
@@ -699,9 +699,8 @@ function loadCss(cssFileName) {
 
     (function() {
         // To avoid checking on "rustdoc-line-numbers" value on every loop...
-        let lineNumbersFunc = () => {};
         if (getSettingValue("line-numbers") === "true") {
-            lineNumbersFunc = x => {
+            onEachLazy(document.getElementsByClassName("rust-example-rendered"), x => {
                 const count = x.textContent.split("\n").length;
                 const elems = [];
                 for (let i = 0; i < count; ++i) {
@@ -711,26 +710,8 @@ function loadCss(cssFileName) {
                 addClass(node, "line-number");
                 node.innerHTML = elems.join("\n");
                 x.parentNode.insertBefore(node, x);
-            };
+            });
         }
-        onEachLazy(document.getElementsByClassName("rust-example-rendered"), e => {
-            if (hasClass(e, "compile_fail")) {
-                e.addEventListener("mouseover", function() {
-                    this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
-                });
-                e.addEventListener("mouseout", function() {
-                    this.parentElement.previousElementSibling.childNodes[0].style.color = "";
-                });
-            } else if (hasClass(e, "ignore")) {
-                e.addEventListener("mouseover", function() {
-                    this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
-                });
-                e.addEventListener("mouseout", function() {
-                    this.parentElement.previousElementSibling.childNodes[0].style.color = "";
-                });
-            }
-            lineNumbersFunc(e);
-        });
     }());
 
     let oldSidebarScrollPosition = null;
index c2d3543942db16b02b94080f558271bb6ab2ceb0..49a31f5f1da1f8494b9065deab6b3cf76821901c 100644 (file)
@@ -19,6 +19,7 @@
 use crate::clean::{self, ItemId};
 use crate::formats::item_type::ItemType;
 use crate::json::JsonRenderer;
+use crate::passes::collect_intra_doc_links::UrlFragment;
 
 impl JsonRenderer<'_> {
     pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
@@ -29,8 +30,14 @@ pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
             .get(&item.item_id)
             .into_iter()
             .flatten()
-            .map(|clean::ItemLink { link, did, .. }| {
-                (link.clone(), from_item_id((*did).into(), self.tcx))
+            .map(|clean::ItemLink { link, page_id, fragment, .. }| {
+                let id = match fragment {
+                    Some(UrlFragment::Item(frag_id)) => *frag_id,
+                    // FIXME: Pass the `UserWritten` segment to JSON consumer.
+                    Some(UrlFragment::UserWritten(_)) | None => *page_id,
+                };
+
+                (link.clone(), from_item_id(id.into(), self.tcx))
             })
             .collect();
         let docs = item.attrs.collapsed_doc_value();
@@ -304,11 +311,19 @@ impl FromWithTcx<clean::Struct> for Struct {
     fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self {
         let fields_stripped = struct_.has_stripped_entries();
         let clean::Struct { struct_type, generics, fields } = struct_;
+
+        let kind = match struct_type {
+            CtorKind::Fn => StructKind::Tuple(ids_keeping_stripped(fields, tcx)),
+            CtorKind::Const => {
+                assert!(fields.is_empty());
+                StructKind::Unit
+            }
+            CtorKind::Fictive => StructKind::Plain { fields: ids(fields, tcx), fields_stripped },
+        };
+
         Struct {
-            struct_type: from_ctor_kind(struct_type),
+            kind,
             generics: generics.into_tcx(tcx),
-            fields_stripped,
-            fields: ids(fields, tcx),
             impls: Vec::new(), // Added in JsonRenderer::item
         }
     }
@@ -327,14 +342,6 @@ fn from_tcx(union_: clean::Union, tcx: TyCtxt<'_>) -> Self {
     }
 }
 
-pub(crate) fn from_ctor_kind(struct_type: CtorKind) -> StructType {
-    match struct_type {
-        CtorKind::Fictive => StructType::Plain,
-        CtorKind::Fn => StructType::Tuple,
-        CtorKind::Const => StructType::Unit,
-    }
-}
-
 pub(crate) fn from_fn_header(header: &rustc_hir::FnHeader) -> Header {
     Header {
         async_: header.is_async(),
@@ -644,20 +651,6 @@ fn from_tcx(enum_: clean::Enum, tcx: TyCtxt<'_>) -> Self {
     }
 }
 
-impl FromWithTcx<clean::VariantStruct> for Struct {
-    fn from_tcx(struct_: clean::VariantStruct, tcx: TyCtxt<'_>) -> Self {
-        let fields_stripped = struct_.has_stripped_entries();
-        let clean::VariantStruct { struct_type, fields } = struct_;
-        Struct {
-            struct_type: from_ctor_kind(struct_type),
-            generics: Generics { params: vec![], where_predicates: vec![] },
-            fields_stripped,
-            fields: ids(fields, tcx),
-            impls: Vec::new(),
-        }
-    }
-}
-
 impl FromWithTcx<clean::Variant> for Variant {
     fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
         use clean::Variant::*;
index c27f0ce18c1414d027453b4e8d2799105c980cfa..677c980f63cc4a5a795eaa0b6d4662c164fd1eb1 100644 (file)
@@ -223,6 +223,9 @@ enum MalformedGenerics {
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 pub(crate) enum UrlFragment {
     Item(DefId),
+    /// A part of a page that isn't a rust item.
+    ///
+    /// Eg: `[Vector Examples](std::vec::Vec#examples)`
     UserWritten(String),
 }
 
@@ -1127,7 +1130,7 @@ fn resolve_link(
                 Some(ItemLink {
                     link: ori_link.link.clone(),
                     link_text: link_text.clone(),
-                    did: res.def_id(self.cx.tcx),
+                    page_id: res.def_id(self.cx.tcx),
                     fragment,
                 })
             }
@@ -1146,11 +1149,12 @@ fn resolve_link(
                     item,
                     &diag_info,
                 )?;
-                let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
+
+                let page_id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
                 Some(ItemLink {
                     link: ori_link.link.clone(),
                     link_text: link_text.clone(),
-                    did: id,
+                    page_id,
                     fragment,
                 })
             }
@@ -1805,8 +1809,8 @@ fn split(path: &str) -> Option<(&str, &str)> {
                                 }
                                 return;
                             }
-                            Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam
-                            | Static(_) => "associated item",
+                            Trait | TyAlias | ForeignTy | OpaqueTy | ImplTraitPlaceholder
+                            | TraitAlias | TyParam | Static(_) => "associated item",
                             Impl | GlobalAsm => unreachable!("not a path"),
                         }
                     } else {
index ca7a20bf3688a934fd2a36a937c253e8f40f0b5f..c27ac0ac40e1dbe200e196510df111b12522da1e 100644 (file)
@@ -164,8 +164,20 @@ fn visit_mod_contents(
         self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public();
         for &i in m.item_ids {
             let item = self.cx.tcx.hir().item(i);
+            if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
+                continue;
+            }
             self.visit_item(item, None, &mut om);
         }
+        for &i in m.item_ids {
+            let item = self.cx.tcx.hir().item(i);
+            // To match the way import precedence works, visit glob imports last.
+            // Later passes in rustdoc will de-duplicate by name and kind, so if glob-
+            // imported items appear last, then they'll be the ones that get discarded.
+            if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
+                self.visit_item(item, None, &mut om);
+            }
+        }
         self.inside_public_path = orig_inside_public_path;
         om
     }
index eea62f3af5ab4de437119a3b9b98df9f4a978f91..13bafa506e4a6c6753d3435ce976e12ed96388c9 100644 (file)
@@ -9,7 +9,7 @@
 use serde::{Deserialize, Serialize};
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 20;
+pub const FORMAT_VERSION: u32 = 21;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -289,13 +289,39 @@ pub struct Union {
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Struct {
-    pub struct_type: StructType,
+    pub kind: StructKind,
     pub generics: Generics,
-    pub fields_stripped: bool,
-    pub fields: Vec<Id>,
     pub impls: Vec<Id>,
 }
 
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+pub enum StructKind {
+    /// A struct with no fields and no parentheses.
+    ///
+    /// ```rust
+    /// pub struct Unit;
+    /// ```
+    Unit,
+    /// A struct with unnamed fields.
+    ///
+    /// ```rust
+    /// pub struct TupleStruct(i32);
+    /// pub struct EmptyTupleStruct();
+    /// ```
+    ///
+    /// All [`Id`]'s will point to [`ItemEnum::StructField`]. Private and
+    /// `#[doc(hidden)]` fields will be given as `None`
+    Tuple(Vec<Option<Id>>),
+    /// A struct with nammed fields.
+    ///
+    /// ```rust
+    /// pub struct PlainStruct { x: i32 }
+    /// pub struct EmptyPlainStruct {}
+    /// ```
+    Plain { fields: Vec<Id>, fields_stripped: bool },
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Enum {
     pub generics: Generics,
@@ -357,14 +383,6 @@ pub struct Discriminant {
     pub value: String,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
-#[serde(rename_all = "snake_case")]
-pub enum StructType {
-    Plain,
-    Tuple,
-    Unit,
-}
-
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Header {
     #[serde(rename = "const")]
index e7f6447ed87531dc944188e5a3fdf24ba90023ca..399ff54b294977a12b3613805c6f6743c6f19108 100644 (file)
@@ -3,10 +3,8 @@
 #[test]
 fn test_struct_info_roundtrip() {
     let s = ItemEnum::Struct(Struct {
-        struct_type: StructType::Plain,
         generics: Generics { params: vec![], where_predicates: vec![] },
-        fields_stripped: false,
-        fields: vec![],
+        kind: StructKind::Plain { fields: vec![], fields_stripped: false },
         impls: vec![],
     });
 
index 4dc9d183b0b20d2d1515e1a092057a411eee80f1..b4fda5f8c8428d0c879382dbf0a6e616af8315f6 100644 (file)
@@ -24,7 +24,7 @@ trait Freeze { }
 #[lang="copy"]
 trait Copy { }
 
-//x86_64: define dso_local win64cc void @has_efiapi
+//x86_64: define win64cc void @has_efiapi
 //i686: define void @has_efiapi
 //aarch64: define dso_local void @has_efiapi
 //arm: define dso_local void @has_efiapi
diff --git a/src/test/codegen/issue-98294-get-mut-copy-from-slice-opt.rs b/src/test/codegen/issue-98294-get-mut-copy-from-slice-opt.rs
new file mode 100644 (file)
index 0000000..7da29cd
--- /dev/null
@@ -0,0 +1,19 @@
+// min-llvm-version: 15.0.0
+// ignore-debug: The debug assertions get in the way
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// There should be no calls to panic / len_mismatch_fail.
+
+#[no_mangle]
+pub fn test(a: &mut [u8], offset: usize, bytes: &[u8]) {
+    // CHECK-LABEL: @test(
+    // CHECK-NOT: call
+    // CHECK: call void @llvm.memcpy
+    // CHECK-NOT: call
+    // CHECK: }
+    if let Some(dst) = a.get_mut(offset..offset + bytes.len()) {
+        dst.copy_from_slice(bytes);
+    }
+}
index 45d5ddf5c0ebc8644832c112986c09bf5840418a..7f1be6f27847c0d7f9632984f56dc384b9792852 100644 (file)
@@ -53,8 +53,8 @@
 // cdb-command: dx niche128_none
 // cdb-check: niche128_none    : None [Type: enum2$<core::option::Option<core::num::nonzero::NonZeroI128> >]
 
-// cdb-command: dx wrapping_niche128_dataful
-// cdb-check: wrapping_niche128_dataful : X [Type: enum2$<msvc_pretty_enums::Wrapping128Niche>]
+// cdb-command: dx wrapping_niche128_untagged
+// cdb-check: wrapping_niche128_untagged : X [Type: enum2$<msvc_pretty_enums::Wrapping128Niche>]
 // cdb-check:    [+0x[...]] __0              [Type: msvc_pretty_enums::Wrapping128]
 
 // cdb-command: dx wrapping_niche128_none1
@@ -213,7 +213,7 @@ fn main() {
     let niche128_some = Some(NonZeroI128::new(123456).unwrap());
     let niche128_none: Option<NonZeroI128> = None;
 
-    let wrapping_niche128_dataful =
+    let wrapping_niche128_untagged =
         unsafe { Wrapping128Niche::X(Wrapping128(340282366920938463463374607431768211454)) };
     let wrapping_niche128_none1 = Wrapping128Niche::Y;
     let wrapping_niche128_none2 = Wrapping128Niche::Z;
diff --git a/src/test/incremental/issue-100521-change-struct-name-assocty.rs b/src/test/incremental/issue-100521-change-struct-name-assocty.rs
new file mode 100644 (file)
index 0000000..7f8d1e6
--- /dev/null
@@ -0,0 +1,65 @@
+// revisions: rpass1 rpass2
+
+pub fn foo() {
+    bar();
+    baz::<()>();
+}
+
+fn bar()
+where
+    <() as Table>::AllColumns:,
+{
+}
+
+fn baz<W>()
+where
+    W: AsQuery,
+    <W as AsQuery>::Query:,
+{
+}
+
+trait AsQuery {
+    type Query;
+}
+
+trait UnimplementedTrait {}
+
+impl<T> AsQuery for T
+where
+    T: UnimplementedTrait,
+{
+    type Query = ();
+}
+
+struct Wrapper<Expr>(Expr);
+
+impl<Ret> AsQuery for Wrapper<Ret> {
+    type Query = ();
+}
+
+impl AsQuery for ()
+where
+    Wrapper<<() as Table>::AllColumns>: AsQuery,
+{
+    type Query = ();
+}
+
+trait Table {
+    type AllColumns;
+}
+
+#[cfg(rpass1)]
+impl Table for () {
+    type AllColumns = Checksum1;
+}
+#[cfg(rpass1)]
+struct Checksum1;
+
+#[cfg(rpass2)]
+impl Table for () {
+    type AllColumns = Checksum2;
+}
+#[cfg(rpass2)]
+struct Checksum2;
+
+fn main() {}
index 0e4c486e4640f03eb070d338c3a5103866087044..e7bde81d4ca36204fe9642958546f34714226aa2 100644 (file)
@@ -7,7 +7,7 @@ unsafe fn foo(z: *mut usize) -> u32 {
     99
 }
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir
 fn main() {
     let mut x = [42, 43, 44];
diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir
deleted file mode 100644 (file)
index 27f883e..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-// MIR for `main` after SimplifyCfg-elaborate-drops
-
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +0:11
-    let mut _1: [u32; 3];                // in scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
-    let mut _4: &mut usize;              // in scope 0 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
-    let mut _5: u32;                     // in scope 0 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
-    let mut _6: *mut usize;              // in scope 0 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
-    let _7: usize;                       // in scope 0 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
-    let mut _8: usize;                   // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-    let mut _9: bool;                    // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-    scope 1 {
-        debug x => _1;                   // in scope 1 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
-        let mut _2: usize;               // in scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
-        scope 2 {
-            debug y => _2;               // in scope 2 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
-            let _3: *mut usize;          // in scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
-            scope 3 {
-                debug z => _3;           // in scope 3 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
-                scope 4 {
-                }
-            }
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
-        _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:+1:17: +1:29
-        StorageLive(_2);                 // scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
-        _2 = const 1_usize;              // scope 1 at $DIR/array-index-is-temporary.rs:+2:17: +2:18
-        StorageLive(_3);                 // scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
-        StorageLive(_4);                 // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
-        _4 = &mut _2;                    // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
-        _3 = &raw mut (*_4);             // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
-        StorageDead(_4);                 // scope 2 at $DIR/array-index-is-temporary.rs:+3:31: +3:32
-        StorageLive(_5);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
-        StorageLive(_6);                 // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
-        _6 = _3;                         // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
-        _5 = foo(move _6) -> bb1;        // scope 4 at $DIR/array-index-is-temporary.rs:+4:21: +4:27
-                                         // mir::Constant
-                                         // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24
-                                         // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) }
-    }
-
-    bb1: {
-        StorageDead(_6);                 // scope 4 at $DIR/array-index-is-temporary.rs:+4:26: +4:27
-        StorageLive(_7);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
-        _7 = _2;                         // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
-        _8 = Len(_1);                    // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-        _9 = Lt(_7, _8);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-        assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-    }
-
-    bb2: {
-        _1[_7] = move _5;                // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:29
-        StorageDead(_5);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:28: +4:29
-        StorageDead(_7);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:29: +4:30
-        _0 = const ();                   // scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +5:2
-        StorageDead(_3);                 // scope 2 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
-        StorageDead(_2);                 // scope 1 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
-        StorageDead(_1);                 // scope 0 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
-        return;                          // scope 0 at $DIR/array-index-is-temporary.rs:+5:2: +5:2
-    }
-}
diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir
deleted file mode 100644 (file)
index 27f883e..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-// MIR for `main` after SimplifyCfg-elaborate-drops
-
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +0:11
-    let mut _1: [u32; 3];                // in scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
-    let mut _4: &mut usize;              // in scope 0 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
-    let mut _5: u32;                     // in scope 0 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
-    let mut _6: *mut usize;              // in scope 0 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
-    let _7: usize;                       // in scope 0 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
-    let mut _8: usize;                   // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-    let mut _9: bool;                    // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-    scope 1 {
-        debug x => _1;                   // in scope 1 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
-        let mut _2: usize;               // in scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
-        scope 2 {
-            debug y => _2;               // in scope 2 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
-            let _3: *mut usize;          // in scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
-            scope 3 {
-                debug z => _3;           // in scope 3 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
-                scope 4 {
-                }
-            }
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
-        _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:+1:17: +1:29
-        StorageLive(_2);                 // scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
-        _2 = const 1_usize;              // scope 1 at $DIR/array-index-is-temporary.rs:+2:17: +2:18
-        StorageLive(_3);                 // scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
-        StorageLive(_4);                 // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
-        _4 = &mut _2;                    // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
-        _3 = &raw mut (*_4);             // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
-        StorageDead(_4);                 // scope 2 at $DIR/array-index-is-temporary.rs:+3:31: +3:32
-        StorageLive(_5);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
-        StorageLive(_6);                 // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
-        _6 = _3;                         // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
-        _5 = foo(move _6) -> bb1;        // scope 4 at $DIR/array-index-is-temporary.rs:+4:21: +4:27
-                                         // mir::Constant
-                                         // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24
-                                         // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) }
-    }
-
-    bb1: {
-        StorageDead(_6);                 // scope 4 at $DIR/array-index-is-temporary.rs:+4:26: +4:27
-        StorageLive(_7);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
-        _7 = _2;                         // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
-        _8 = Len(_1);                    // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-        _9 = Lt(_7, _8);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-        assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-    }
-
-    bb2: {
-        _1[_7] = move _5;                // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:29
-        StorageDead(_5);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:28: +4:29
-        StorageDead(_7);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:29: +4:30
-        _0 = const ();                   // scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +5:2
-        StorageDead(_3);                 // scope 2 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
-        StorageDead(_2);                 // scope 1 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
-        StorageDead(_1);                 // scope 0 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
-        return;                          // scope 0 at $DIR/array-index-is-temporary.rs:+5:2: +5:2
-    }
-}
diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir
new file mode 100644 (file)
index 0000000..27f883e
--- /dev/null
@@ -0,0 +1,64 @@
+// MIR for `main` after SimplifyCfg-elaborate-drops
+
+fn main() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +0:11
+    let mut _1: [u32; 3];                // in scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
+    let mut _4: &mut usize;              // in scope 0 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
+    let mut _5: u32;                     // in scope 0 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
+    let mut _6: *mut usize;              // in scope 0 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
+    let _7: usize;                       // in scope 0 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
+    let mut _8: usize;                   // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
+    let mut _9: bool;                    // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
+    scope 1 {
+        debug x => _1;                   // in scope 1 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
+        let mut _2: usize;               // in scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
+        scope 2 {
+            debug y => _2;               // in scope 2 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
+            let _3: *mut usize;          // in scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
+            scope 3 {
+                debug z => _3;           // in scope 3 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
+                scope 4 {
+                }
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
+        _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:+1:17: +1:29
+        StorageLive(_2);                 // scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
+        _2 = const 1_usize;              // scope 1 at $DIR/array-index-is-temporary.rs:+2:17: +2:18
+        StorageLive(_3);                 // scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
+        StorageLive(_4);                 // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
+        _4 = &mut _2;                    // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
+        _3 = &raw mut (*_4);             // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
+        StorageDead(_4);                 // scope 2 at $DIR/array-index-is-temporary.rs:+3:31: +3:32
+        StorageLive(_5);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
+        StorageLive(_6);                 // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
+        _6 = _3;                         // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
+        _5 = foo(move _6) -> bb1;        // scope 4 at $DIR/array-index-is-temporary.rs:+4:21: +4:27
+                                         // mir::Constant
+                                         // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24
+                                         // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        StorageDead(_6);                 // scope 4 at $DIR/array-index-is-temporary.rs:+4:26: +4:27
+        StorageLive(_7);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
+        _7 = _2;                         // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
+        _8 = Len(_1);                    // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
+        _9 = Lt(_7, _8);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
+        assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
+    }
+
+    bb2: {
+        _1[_7] = move _5;                // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:29
+        StorageDead(_5);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:28: +4:29
+        StorageDead(_7);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:29: +4:30
+        _0 = const ();                   // scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +5:2
+        StorageDead(_3);                 // scope 2 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
+        StorageDead(_2);                 // scope 1 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
+        StorageDead(_1);                 // scope 0 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
+        return;                          // scope 0 at $DIR/array-index-is-temporary.rs:+5:2: +5:2
+    }
+}
index d39145973624fb3dd51963f85626b18dab7a55f7..96716a39a2bfdbbe57532361f0e2f5984b72c870 100644 (file)
@@ -8,13 +8,13 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
     let mut _4: bool;                    // in scope 0 at $DIR/exponential-or.rs:+2:70: +2:77
     let mut _5: bool;                    // in scope 0 at $DIR/exponential-or.rs:+2:62: +2:67
     let mut _6: bool;                    // in scope 0 at $DIR/exponential-or.rs:+2:62: +2:67
-    let _7: u32;                         // in scope 0 at $DIR/exponential-or.rs:+2:10: +2:21
-    let _8: u32;                         // in scope 0 at $DIR/exponential-or.rs:+2:57: +2:78
+    let _7: u32;                         // in scope 0 at $DIR/exponential-or.rs:+2:10: +2:11
+    let _8: u32;                         // in scope 0 at $DIR/exponential-or.rs:+2:57: +2:58
     let mut _9: u32;                     // in scope 0 at $DIR/exponential-or.rs:+2:83: +2:84
     let mut _10: u32;                    // in scope 0 at $DIR/exponential-or.rs:+2:87: +2:88
     scope 1 {
-        debug y => _7;                   // in scope 1 at $DIR/exponential-or.rs:+2:10: +2:21
-        debug z => _8;                   // in scope 1 at $DIR/exponential-or.rs:+2:57: +2:78
+        debug y => _7;                   // in scope 1 at $DIR/exponential-or.rs:+2:10: +2:11
+        debug z => _8;                   // in scope 1 at $DIR/exponential-or.rs:+2:57: +2:58
     }
 
     bb0: {
@@ -61,10 +61,10 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
     }
 
     bb9: {
-        StorageLive(_7);                 // scope 0 at $DIR/exponential-or.rs:+2:10: +2:21
-        _7 = (_1.0: u32);                // scope 0 at $DIR/exponential-or.rs:+2:10: +2:21
-        StorageLive(_8);                 // scope 0 at $DIR/exponential-or.rs:+2:57: +2:78
-        _8 = (_1.3: u32);                // scope 0 at $DIR/exponential-or.rs:+2:57: +2:78
+        StorageLive(_7);                 // scope 0 at $DIR/exponential-or.rs:+2:10: +2:11
+        _7 = (_1.0: u32);                // scope 0 at $DIR/exponential-or.rs:+2:10: +2:11
+        StorageLive(_8);                 // scope 0 at $DIR/exponential-or.rs:+2:57: +2:58
+        _8 = (_1.3: u32);                // scope 0 at $DIR/exponential-or.rs:+2:57: +2:58
         StorageLive(_9);                 // scope 1 at $DIR/exponential-or.rs:+2:83: +2:84
         _9 = _7;                         // scope 1 at $DIR/exponential-or.rs:+2:83: +2:84
         StorageLive(_10);                // scope 1 at $DIR/exponential-or.rs:+2:87: +2:88
index 049a97816f68bed68afe9b216a3d1309dc9f9047..232bcc7b27d465dc327ed666410f825ecd34ada2 100644 (file)
@@ -1,7 +1,7 @@
 // ignore-endian-big
 // ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: -Z mir-opt-level=4
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 #![feature(box_syntax)]
 // EMIT_MIR inline_into_box_place.main.Inline.diff
 fn main() {
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
deleted file mode 100644 (file)
index 7017413..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-- // MIR for `main` before Inline
-+ // MIR for `main` after Inline
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/inline-into-box-place.rs:+0:11: +0:11
-      let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
-      let mut _2: usize;                   // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _3: usize;                   // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _4: *mut u8;                 // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _6: ();                      // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
-      let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-+     let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-      scope 1 {
-          debug _x => _1;                  // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
-      }
-      scope 2 {
-      }
-+     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+     }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
-          _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-                                           // mir::Constant
-                                           // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
-                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
-      }
-  
-      bb1: {
-          StorageLive(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
--         (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         _8 = &mut (*_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-                                           // mir::Constant
--                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
--                                          // + user_ty: UserType(1)
--                                          // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) }
--     }
-- 
--     bb2: {
-+                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+                                          // + user_ty: UserType(0)
-+                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+         Deinit((*_8));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-          _1 = move _5;                    // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          StorageDead(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
-          _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:+0:11: +2:2
--         drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
-+         drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
-      }
-  
--     bb3: {
-+     bb2: {
-          StorageDead(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/inline-into-box-place.rs:+2:2: +2:2
-      }
-  
--     bb4 (cleanup): {
-+     bb3 (cleanup): {
-          resume;                          // scope 0 at $DIR/inline-into-box-place.rs:+0:1: +2:2
--     }
-- 
--     bb5 (cleanup): {
--         _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
--                                          // mir::Constant
--                                          // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
--                                          // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(<ZST>) }
-      }
-  }
-  
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
deleted file mode 100644 (file)
index 7017413..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-- // MIR for `main` before Inline
-+ // MIR for `main` after Inline
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/inline-into-box-place.rs:+0:11: +0:11
-      let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
-      let mut _2: usize;                   // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _3: usize;                   // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _4: *mut u8;                 // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _6: ();                      // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
-      let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-+     let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-      scope 1 {
-          debug _x => _1;                  // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
-      }
-      scope 2 {
-      }
-+     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+     }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
-          _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-                                           // mir::Constant
-                                           // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
-                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
-      }
-  
-      bb1: {
-          StorageLive(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
--         (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         _8 = &mut (*_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-                                           // mir::Constant
--                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
--                                          // + user_ty: UserType(1)
--                                          // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) }
--     }
-- 
--     bb2: {
-+                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+                                          // + user_ty: UserType(0)
-+                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+         Deinit((*_8));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-          _1 = move _5;                    // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          StorageDead(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
-          _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:+0:11: +2:2
--         drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
-+         drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
-      }
-  
--     bb3: {
-+     bb2: {
-          StorageDead(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/inline-into-box-place.rs:+2:2: +2:2
-      }
-  
--     bb4 (cleanup): {
-+     bb3 (cleanup): {
-          resume;                          // scope 0 at $DIR/inline-into-box-place.rs:+0:1: +2:2
--     }
-- 
--     bb5 (cleanup): {
--         _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
--                                          // mir::Constant
--                                          // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
--                                          // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(<ZST>) }
-      }
-  }
-  
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff
new file mode 100644 (file)
index 0000000..7017413
--- /dev/null
@@ -0,0 +1,82 @@
+- // MIR for `main` before Inline
++ // MIR for `main` after Inline
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/inline-into-box-place.rs:+0:11: +0:11
+      let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
+      let mut _2: usize;                   // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+      let mut _3: usize;                   // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+      let mut _4: *mut u8;                 // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+      let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+      let mut _6: ();                      // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
+      let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
++     let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
+      scope 1 {
+          debug _x => _1;                  // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
+      }
+      scope 2 {
+      }
++     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
++         let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++     }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
+          _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+          _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+          _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+                                           // mir::Constant
+                                           // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
+                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageLive(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+          _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+          _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
+-         (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         StorageLive(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         _8 = &mut (*_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         StorageLive(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+                                           // mir::Constant
+-                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
+-                                          // + user_ty: UserType(1)
+-                                          // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) }
+-     }
+- 
+-     bb2: {
++                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++                                          // + user_ty: UserType(0)
++                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
++         Deinit((*_8));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
+          _1 = move _5;                    // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+          StorageDead(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
+          _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:+0:11: +2:2
+-         drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
++         drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
+      }
+  
+-     bb3: {
++     bb2: {
+          StorageDead(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
+          return;                          // scope 0 at $DIR/inline-into-box-place.rs:+2:2: +2:2
+      }
+  
+-     bb4 (cleanup): {
++     bb3 (cleanup): {
+          resume;                          // scope 0 at $DIR/inline-into-box-place.rs:+0:1: +2:2
+-     }
+- 
+-     bb5 (cleanup): {
+-         _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
+-                                          // mir::Constant
+-                                          // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
+-                                          // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(<ZST>) }
+      }
+  }
+  
index 5c34d8e68d0c054710bd6b75320f00a428ec157d..cbd8633a345c7fdf16fa3bf449272ccf545db7ee 100644 (file)
@@ -13,7 +13,7 @@ trait Foo {
     fn get(&self) -> [u8; 2];
 }
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir
 impl Foo for [u8; 1+1] {
     fn get(&self) -> [u8; 2] {
index 844d53a4b2bcebab09c302847c8e31dd68a68057..ebb5f5042fccb7084b85226017187e67d603f417 100644 (file)
@@ -11,14 +11,14 @@ union Foo {
     b: Never
 }
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR issue_72181.foo.mir_map.0.mir
 fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 }
 
 // EMIT_MIR issue_72181.bar.mir_map.0.mir
 fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { x }
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR issue_72181.main.mir_map.0.mir
 fn main() {
     let _ = mem::size_of::<Foo>();
index 9e731c40908790c8a9c30440333ca8bc7c8bbca9..be114cab719c0c77fb5abdb715f464b549126fdc 100644 (file)
@@ -8,5 +8,5 @@ fn main() {
     assert_eq!(split, 1);
 }
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR issue_73223.main.SimplifyArmIdentity.diff
diff --git a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir
deleted file mode 100644 (file)
index 047b24d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// MIR for `<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}` after SimplifyCfg-promote-consts
-
-<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}: usize = {
-    let mut _0: usize;                   // return place in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-    let mut _1: (usize, bool);           // in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-
-    bb0: {
-        _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-        assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-    }
-
-    bb1: {
-        _0 = move (_1.0: usize);         // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-        return;                          // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-    }
-}
diff --git a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir
deleted file mode 100644 (file)
index 047b24d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// MIR for `<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}` after SimplifyCfg-promote-consts
-
-<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}: usize = {
-    let mut _0: usize;                   // return place in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-    let mut _1: (usize, bool);           // in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-
-    bb0: {
-        _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-        assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-    }
-
-    bb1: {
-        _0 = move (_1.0: usize);         // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-        return;                          // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-    }
-}
diff --git a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir
new file mode 100644 (file)
index 0000000..047b24d
--- /dev/null
@@ -0,0 +1,20 @@
+// MIR for `<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}` after SimplifyCfg-promote-consts
+
+<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}: usize = {
+    let mut _0: usize;                   // return place in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+    let mut _1: (usize, bool);           // in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+
+    bb0: {
+        _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+        assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+    }
+
+    bb1: {
+        _0 = move (_1.0: usize);         // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+        return;                          // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+    }
+
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+    }
+}
diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir
deleted file mode 100644 (file)
index 972ce1d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// MIR for `bar` 0 mir_map
-
-fn bar(_1: [(Never, u32); 1]) -> u32 {
-    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:+0:40: +0:43
-    let _2: u32;                         // in scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
-    scope 1 {
-        debug x => _2;                   // in scope 1 at $DIR/issue-72181.rs:+0:13: +0:14
-    }
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
-        _2 = (_1[0 of 1].1: u32);        // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
-        _0 = _2;                         // scope 1 at $DIR/issue-72181.rs:+0:46: +0:47
-        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
-        return;                          // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
-    }
-}
diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir
deleted file mode 100644 (file)
index 972ce1d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// MIR for `bar` 0 mir_map
-
-fn bar(_1: [(Never, u32); 1]) -> u32 {
-    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:+0:40: +0:43
-    let _2: u32;                         // in scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
-    scope 1 {
-        debug x => _2;                   // in scope 1 at $DIR/issue-72181.rs:+0:13: +0:14
-    }
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
-        _2 = (_1[0 of 1].1: u32);        // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
-        _0 = _2;                         // scope 1 at $DIR/issue-72181.rs:+0:46: +0:47
-        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
-        return;                          // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
-    }
-}
diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.mir b/src/test/mir-opt/issue_72181.bar.mir_map.0.mir
new file mode 100644 (file)
index 0000000..972ce1d
--- /dev/null
@@ -0,0 +1,17 @@
+// MIR for `bar` 0 mir_map
+
+fn bar(_1: [(Never, u32); 1]) -> u32 {
+    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:+0:40: +0:43
+    let _2: u32;                         // in scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
+    scope 1 {
+        debug x => _2;                   // in scope 1 at $DIR/issue-72181.rs:+0:13: +0:14
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
+        _2 = (_1[0 of 1].1: u32);        // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
+        _0 = _2;                         // scope 1 at $DIR/issue-72181.rs:+0:46: +0:47
+        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
+        return;                          // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
+    }
+}
diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir
deleted file mode 100644 (file)
index 534f131..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// MIR for `foo` 0 mir_map
-
-fn foo(_1: [(Never, u32); 1]) -> u32 {
-    debug xs => _1;                      // in scope 0 at $DIR/issue-72181.rs:+0:8: +0:10
-    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:+0:34: +0:37
-    let _2: usize;                       // in scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
-    let mut _3: usize;                   // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-    let mut _4: bool;                    // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
-        _2 = const 0_usize;              // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
-        _3 = Len(_1);                    // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-        _4 = Lt(_2, _3);                 // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-        assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-    }
-
-    bb1: {
-        _0 = (_1[_2].1: u32);            // scope 0 at $DIR/issue-72181.rs:+0:40: +0:47
-        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
-        return;                          // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181.rs:+0:1: +0:49
-    }
-}
diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir
deleted file mode 100644 (file)
index 534f131..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// MIR for `foo` 0 mir_map
-
-fn foo(_1: [(Never, u32); 1]) -> u32 {
-    debug xs => _1;                      // in scope 0 at $DIR/issue-72181.rs:+0:8: +0:10
-    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:+0:34: +0:37
-    let _2: usize;                       // in scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
-    let mut _3: usize;                   // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-    let mut _4: bool;                    // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
-        _2 = const 0_usize;              // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
-        _3 = Len(_1);                    // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-        _4 = Lt(_2, _3);                 // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-        assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-    }
-
-    bb1: {
-        _0 = (_1[_2].1: u32);            // scope 0 at $DIR/issue-72181.rs:+0:40: +0:47
-        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
-        return;                          // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181.rs:+0:1: +0:49
-    }
-}
diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.mir b/src/test/mir-opt/issue_72181.foo.mir_map.0.mir
new file mode 100644 (file)
index 0000000..534f131
--- /dev/null
@@ -0,0 +1,27 @@
+// MIR for `foo` 0 mir_map
+
+fn foo(_1: [(Never, u32); 1]) -> u32 {
+    debug xs => _1;                      // in scope 0 at $DIR/issue-72181.rs:+0:8: +0:10
+    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:+0:34: +0:37
+    let _2: usize;                       // in scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
+    let mut _3: usize;                   // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
+    let mut _4: bool;                    // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
+        _2 = const 0_usize;              // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
+        _3 = Len(_1);                    // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
+        _4 = Lt(_2, _3);                 // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
+        assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
+    }
+
+    bb1: {
+        _0 = (_1[_2].1: u32);            // scope 0 at $DIR/issue-72181.rs:+0:40: +0:47
+        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
+        return;                          // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
+    }
+
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:+0:1: +0:49
+    }
+}
diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir
deleted file mode 100644 (file)
index 425906f..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-// MIR for `main` 0 mir_map
-
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/issue-72181.rs:+0:11: +0:11
-    let mut _1: usize;                   // in scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
-    let mut _3: Foo;                     // in scope 0 at $DIR/issue-72181.rs:+3:14: +3:27
-    let mut _4: Foo;                     // in scope 0 at $DIR/issue-72181.rs:+3:29: +3:42
-    let mut _5: u64;                     // in scope 0 at $DIR/issue-72181.rs:+4:13: +4:30
-    let _6: usize;                       // in scope 0 at $DIR/issue-72181.rs:+4:24: +4:25
-    let mut _7: usize;                   // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
-    let mut _8: bool;                    // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
-    scope 1 {
-        let _2: [Foo; 2];                // in scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
-        scope 2 {
-            debug f => _2;               // in scope 2 at $DIR/issue-72181.rs:+3:9: +3:10
-            scope 3 {
-            }
-            scope 4 {
-            }
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
-        _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
-                                         // mir::Constant
-                                         // + span: $DIR/issue-72181.rs:24:13: 24:32
-                                         // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) }
-    }
-
-    bb1: {
-        StorageDead(_1);                 // scope 0 at $DIR/issue-72181.rs:+1:34: +1:35
-        StorageLive(_2);                 // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
-        StorageLive(_3);                 // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
-        _3 = Foo { a: const 42_u64 };    // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
-        StorageLive(_4);                 // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
-        _4 = Foo { a: const 10_u64 };    // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
-        _2 = [move _3, move _4];         // scope 1 at $DIR/issue-72181.rs:+3:13: +3:43
-        StorageDead(_4);                 // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
-        StorageDead(_3);                 // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
-        FakeRead(ForLet(None), _2);      // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
-        StorageLive(_5);                 // scope 2 at $DIR/issue-72181.rs:+4:13: +4:30
-        StorageLive(_6);                 // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
-        _6 = const 0_usize;              // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
-        _7 = Len(_2);                    // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
-        _8 = Lt(_6, _7);                 // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
-        assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
-    }
-
-    bb2: {
-        _5 = (_2[_6].0: u64);            // scope 4 at $DIR/issue-72181.rs:+4:22: +4:28
-        StorageDead(_6);                 // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
-        StorageDead(_5);                 // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
-        _0 = const ();                   // scope 0 at $DIR/issue-72181.rs:+0:11: +5:2
-        StorageDead(_2);                 // scope 1 at $DIR/issue-72181.rs:+5:1: +5:2
-        return;                          // scope 0 at $DIR/issue-72181.rs:+5:2: +5:2
-    }
-
-    bb3 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181.rs:+0:1: +5:2
-    }
-}
diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir
deleted file mode 100644 (file)
index 425906f..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-// MIR for `main` 0 mir_map
-
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/issue-72181.rs:+0:11: +0:11
-    let mut _1: usize;                   // in scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
-    let mut _3: Foo;                     // in scope 0 at $DIR/issue-72181.rs:+3:14: +3:27
-    let mut _4: Foo;                     // in scope 0 at $DIR/issue-72181.rs:+3:29: +3:42
-    let mut _5: u64;                     // in scope 0 at $DIR/issue-72181.rs:+4:13: +4:30
-    let _6: usize;                       // in scope 0 at $DIR/issue-72181.rs:+4:24: +4:25
-    let mut _7: usize;                   // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
-    let mut _8: bool;                    // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
-    scope 1 {
-        let _2: [Foo; 2];                // in scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
-        scope 2 {
-            debug f => _2;               // in scope 2 at $DIR/issue-72181.rs:+3:9: +3:10
-            scope 3 {
-            }
-            scope 4 {
-            }
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
-        _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
-                                         // mir::Constant
-                                         // + span: $DIR/issue-72181.rs:24:13: 24:32
-                                         // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) }
-    }
-
-    bb1: {
-        StorageDead(_1);                 // scope 0 at $DIR/issue-72181.rs:+1:34: +1:35
-        StorageLive(_2);                 // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
-        StorageLive(_3);                 // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
-        _3 = Foo { a: const 42_u64 };    // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
-        StorageLive(_4);                 // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
-        _4 = Foo { a: const 10_u64 };    // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
-        _2 = [move _3, move _4];         // scope 1 at $DIR/issue-72181.rs:+3:13: +3:43
-        StorageDead(_4);                 // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
-        StorageDead(_3);                 // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
-        FakeRead(ForLet(None), _2);      // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
-        StorageLive(_5);                 // scope 2 at $DIR/issue-72181.rs:+4:13: +4:30
-        StorageLive(_6);                 // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
-        _6 = const 0_usize;              // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
-        _7 = Len(_2);                    // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
-        _8 = Lt(_6, _7);                 // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
-        assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
-    }
-
-    bb2: {
-        _5 = (_2[_6].0: u64);            // scope 4 at $DIR/issue-72181.rs:+4:22: +4:28
-        StorageDead(_6);                 // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
-        StorageDead(_5);                 // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
-        _0 = const ();                   // scope 0 at $DIR/issue-72181.rs:+0:11: +5:2
-        StorageDead(_2);                 // scope 1 at $DIR/issue-72181.rs:+5:1: +5:2
-        return;                          // scope 0 at $DIR/issue-72181.rs:+5:2: +5:2
-    }
-
-    bb3 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181.rs:+0:1: +5:2
-    }
-}
diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.mir
new file mode 100644 (file)
index 0000000..425906f
--- /dev/null
@@ -0,0 +1,62 @@
+// MIR for `main` 0 mir_map
+
+fn main() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/issue-72181.rs:+0:11: +0:11
+    let mut _1: usize;                   // in scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
+    let mut _3: Foo;                     // in scope 0 at $DIR/issue-72181.rs:+3:14: +3:27
+    let mut _4: Foo;                     // in scope 0 at $DIR/issue-72181.rs:+3:29: +3:42
+    let mut _5: u64;                     // in scope 0 at $DIR/issue-72181.rs:+4:13: +4:30
+    let _6: usize;                       // in scope 0 at $DIR/issue-72181.rs:+4:24: +4:25
+    let mut _7: usize;                   // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
+    let mut _8: bool;                    // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
+    scope 1 {
+        let _2: [Foo; 2];                // in scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
+        scope 2 {
+            debug f => _2;               // in scope 2 at $DIR/issue-72181.rs:+3:9: +3:10
+            scope 3 {
+            }
+            scope 4 {
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
+        _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:24:13: 24:32
+                                         // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        StorageDead(_1);                 // scope 0 at $DIR/issue-72181.rs:+1:34: +1:35
+        StorageLive(_2);                 // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
+        StorageLive(_3);                 // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
+        _3 = Foo { a: const 42_u64 };    // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
+        StorageLive(_4);                 // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
+        _4 = Foo { a: const 10_u64 };    // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
+        _2 = [move _3, move _4];         // scope 1 at $DIR/issue-72181.rs:+3:13: +3:43
+        StorageDead(_4);                 // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
+        StorageDead(_3);                 // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
+        FakeRead(ForLet(None), _2);      // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
+        StorageLive(_5);                 // scope 2 at $DIR/issue-72181.rs:+4:13: +4:30
+        StorageLive(_6);                 // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
+        _6 = const 0_usize;              // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
+        _7 = Len(_2);                    // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
+        _8 = Lt(_6, _7);                 // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
+        assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
+    }
+
+    bb2: {
+        _5 = (_2[_6].0: u64);            // scope 4 at $DIR/issue-72181.rs:+4:22: +4:28
+        StorageDead(_6);                 // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
+        StorageDead(_5);                 // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
+        _0 = const ();                   // scope 0 at $DIR/issue-72181.rs:+0:11: +5:2
+        StorageDead(_2);                 // scope 1 at $DIR/issue-72181.rs:+5:1: +5:2
+        return;                          // scope 0 at $DIR/issue-72181.rs:+5:2: +5:2
+    }
+
+    bb3 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:+0:1: +5:2
+    }
+}
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
deleted file mode 100644 (file)
index ac7fe31..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-- // MIR for `main` before SimplifyArmIdentity
-+ // MIR for `main` after SimplifyArmIdentity
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11
-      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
-      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-      let mut _3: isize;                   // in scope 0 at $DIR/issue-73223.rs:+2:9: +2:16
-      let _4: i32;                         // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-      let mut _5: !;                       // in scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
-      let mut _7: i32;                     // in scope 0 at $DIR/issue-73223.rs:+6:22: +6:27
-      let _8: ();                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _9: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _10: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _11: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _12: i32;                        // in scope 0 at $DIR/issue-73223.rs:+7:23: +7:24
-      let mut _15: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _16: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _17: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _18: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _19: !;                      // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _21: !;                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _22: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _23: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _24: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _25: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _26: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _27: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      scope 1 {
-          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14
-          let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
-          scope 3 {
-              debug _prev => _6;           // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14
-              let _13: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let _14: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let mut _28: &i32;           // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              scope 4 {
-                  debug left_val => _13;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  debug right_val => _14;  // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  let _20: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  scope 5 {
-                      debug kind => _20;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  }
-              }
-          }
-      }
-      scope 2 {
-          debug v => _4;                   // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
-          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          Deinit(_2);                      // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          _3 = const 1_isize;              // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          goto -> bb3;                     // scope 0 at $DIR/issue-73223.rs:+1:17: +1:30
-      }
-  
-      bb1: {
-          nop;                             // scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
-          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
-          return;                          // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-      }
-  
-      bb3: {
-          StorageLive(_4);                 // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-          _4 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-          _1 = _4;                         // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21
-          StorageDead(_4);                 // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21
-          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
-          StorageLive(_6);                 // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
-          StorageLive(_7);                 // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
-          _7 = _1;                         // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
-          Deinit(_6);                      // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
-          ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
-          discriminant(_6) = 1;            // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
-          StorageDead(_7);                 // scope 1 at $DIR/issue-73223.rs:+6:27: +6:28
-          StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _10 = &_1;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_11);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _28 = const main::promoted[0];   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
-          _11 = _28;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_9);                      // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_9.0: &i32) = move _10;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_9.1: &i32) = move _11;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_11);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_13);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _13 = (_9.0: &i32);              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_14);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _14 = (_9.1: &i32);              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _17 = (*_13);                    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _18 = const 1_i32;               // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _16 = Eq(move _17, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _15 = Not(move _16);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          switchInt(move _15) -> [false: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb4: {
-          StorageLive(_20);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_20);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          discriminant(_20) = 0;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_21);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_22);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _22 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
-          StorageLive(_23);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_24);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _24 = _13;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _23 = _24;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_25);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_26);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _26 = _14;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _25 = _26;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_27);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_27);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          discriminant(_27) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
-      }
-  
-      bb5: {
-          nop;                             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_14);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_13);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          nop;                             // scope 0 at $DIR/issue-73223.rs:+0:11: +8:2
-          StorageDead(_6);                 // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
-          return;                          // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
deleted file mode 100644 (file)
index ac7fe31..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-- // MIR for `main` before SimplifyArmIdentity
-+ // MIR for `main` after SimplifyArmIdentity
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11
-      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
-      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-      let mut _3: isize;                   // in scope 0 at $DIR/issue-73223.rs:+2:9: +2:16
-      let _4: i32;                         // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-      let mut _5: !;                       // in scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
-      let mut _7: i32;                     // in scope 0 at $DIR/issue-73223.rs:+6:22: +6:27
-      let _8: ();                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _9: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _10: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _11: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _12: i32;                        // in scope 0 at $DIR/issue-73223.rs:+7:23: +7:24
-      let mut _15: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _16: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _17: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _18: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _19: !;                      // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _21: !;                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _22: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _23: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _24: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _25: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _26: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _27: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      scope 1 {
-          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14
-          let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
-          scope 3 {
-              debug _prev => _6;           // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14
-              let _13: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let _14: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let mut _28: &i32;           // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              scope 4 {
-                  debug left_val => _13;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  debug right_val => _14;  // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  let _20: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  scope 5 {
-                      debug kind => _20;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  }
-              }
-          }
-      }
-      scope 2 {
-          debug v => _4;                   // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
-          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          Deinit(_2);                      // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          _3 = const 1_isize;              // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          goto -> bb3;                     // scope 0 at $DIR/issue-73223.rs:+1:17: +1:30
-      }
-  
-      bb1: {
-          nop;                             // scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
-          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
-          return;                          // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-      }
-  
-      bb3: {
-          StorageLive(_4);                 // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-          _4 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-          _1 = _4;                         // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21
-          StorageDead(_4);                 // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21
-          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
-          StorageLive(_6);                 // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
-          StorageLive(_7);                 // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
-          _7 = _1;                         // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
-          Deinit(_6);                      // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
-          ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
-          discriminant(_6) = 1;            // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
-          StorageDead(_7);                 // scope 1 at $DIR/issue-73223.rs:+6:27: +6:28
-          StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _10 = &_1;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_11);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _28 = const main::promoted[0];   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
-          _11 = _28;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_9);                      // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_9.0: &i32) = move _10;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_9.1: &i32) = move _11;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_11);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_13);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _13 = (_9.0: &i32);              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_14);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _14 = (_9.1: &i32);              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _17 = (*_13);                    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _18 = const 1_i32;               // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _16 = Eq(move _17, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _15 = Not(move _16);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          switchInt(move _15) -> [false: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb4: {
-          StorageLive(_20);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_20);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          discriminant(_20) = 0;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_21);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_22);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _22 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
-          StorageLive(_23);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_24);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _24 = _13;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _23 = _24;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_25);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_26);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _26 = _14;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _25 = _26;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_27);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_27);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          discriminant(_27) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
-      }
-  
-      bb5: {
-          nop;                             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_14);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_13);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          nop;                             // scope 0 at $DIR/issue-73223.rs:+0:11: +8:2
-          StorageDead(_6);                 // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
-          return;                          // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff
new file mode 100644 (file)
index 0000000..ac7fe31
--- /dev/null
@@ -0,0 +1,161 @@
+- // MIR for `main` before SimplifyArmIdentity
++ // MIR for `main` after SimplifyArmIdentity
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11
+      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
+      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+      let mut _3: isize;                   // in scope 0 at $DIR/issue-73223.rs:+2:9: +2:16
+      let _4: i32;                         // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
+      let mut _5: !;                       // in scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
+      let mut _7: i32;                     // in scope 0 at $DIR/issue-73223.rs:+6:22: +6:27
+      let _8: ();                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _9: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _10: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _11: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _12: i32;                        // in scope 0 at $DIR/issue-73223.rs:+7:23: +7:24
+      let mut _15: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _16: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _17: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _18: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _19: !;                      // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _21: !;                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _22: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _23: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _24: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _25: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _26: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _27: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      scope 1 {
+          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14
+          let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
+          scope 3 {
+              debug _prev => _6;           // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14
+              let _13: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+              let _14: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+              let mut _28: &i32;           // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+              scope 4 {
+                  debug left_val => _13;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  debug right_val => _14;  // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  let _20: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  scope 5 {
+                      debug kind => _20;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  }
+              }
+          }
+      }
+      scope 2 {
+          debug v => _4;                   // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
+          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+          Deinit(_2);                      // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+          ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+          discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+          _3 = const 1_isize;              // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+          goto -> bb3;                     // scope 0 at $DIR/issue-73223.rs:+1:17: +1:30
+      }
+  
+      bb1: {
+          nop;                             // scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
+          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
+          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
+          return;                          // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+      }
+  
+      bb3: {
+          StorageLive(_4);                 // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
+          _4 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
+          _1 = _4;                         // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21
+          StorageDead(_4);                 // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21
+          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
+          StorageLive(_6);                 // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
+          StorageLive(_7);                 // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
+          _7 = _1;                         // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
+          Deinit(_6);                      // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
+          ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
+          discriminant(_6) = 1;            // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
+          StorageDead(_7);                 // scope 1 at $DIR/issue-73223.rs:+6:27: +6:28
+          StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _10 = &_1;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_11);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _28 = const main::promoted[0];   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
+          _11 = _28;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_9);                      // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_9.0: &i32) = move _10;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_9.1: &i32) = move _11;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_11);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_13);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _13 = (_9.0: &i32);              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_14);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _14 = (_9.1: &i32);              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _17 = (*_13);                    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _18 = const 1_i32;               // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _16 = Eq(move _17, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _15 = Not(move _16);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          switchInt(move _15) -> [false: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      }
+  
+      bb4: {
+          StorageLive(_20);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_20);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          discriminant(_20) = 0;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_21);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_22);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _22 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
+          StorageLive(_23);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_24);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _24 = _13;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _23 = _24;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_25);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_26);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _26 = _14;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _25 = _26;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_27);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_27);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          discriminant(_27) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
+      }
+  
+      bb5: {
+          nop;                             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_14);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_13);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          nop;                             // scope 0 at $DIR/issue-73223.rs:+0:11: +8:2
+          StorageDead(_6);                 // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2
+          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
+          return;                          // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff
new file mode 100644 (file)
index 0000000..d9898d8
--- /dev/null
@@ -0,0 +1,26 @@
+- // MIR for `assume` before LowerIntrinsics
++ // MIR for `assume` after LowerIntrinsics
+  
+  fn assume() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:17: +0:17
+      let _1: ();                          // in scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+-         _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:72:9: 72:32
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) }
++         assume(const true);              // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
++         goto -> bb1;                     // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+      }
+  
+      bb1: {
+          StorageDead(_1);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:38: +2:39
+          _0 = const ();                   // scope 1 at $DIR/lower_intrinsics.rs:+1:5: +3:6
+          return;                          // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
new file mode 100644 (file)
index 0000000..4fb6752
--- /dev/null
@@ -0,0 +1,72 @@
+- // MIR for `f_copy_nonoverlapping` before LowerIntrinsics
++ // MIR for `f_copy_nonoverlapping` after LowerIntrinsics
+  
+  fn f_copy_nonoverlapping() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:32: +0:32
+      let _1: ();                          // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:12
+      let _3: ();                          // in scope 0 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+      let mut _4: *const i32;              // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:59
+      let mut _5: *const ();               // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+      let mut _6: *const ();               // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+      let _7: &();                         // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+      let mut _8: *mut i32;                // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:91
+      let mut _9: *mut ();                 // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+      let mut _10: *mut ();                // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+      let mut _11: &mut ();                // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+      scope 1 {
+          debug src => _1;                 // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:12
+          let mut _2: ();                  // in scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:16
+          scope 2 {
+              debug dst => _2;             // in scope 2 at $DIR/lower_intrinsics.rs:+2:9: +2:16
+              scope 3 {
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:12
+          Deinit(_1);                      // scope 0 at $DIR/lower_intrinsics.rs:+1:15: +1:17
+          StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:16
+          Deinit(_2);                      // scope 1 at $DIR/lower_intrinsics.rs:+2:19: +2:21
+          StorageLive(_3);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+          StorageLive(_4);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:59
+          StorageLive(_5);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+          StorageLive(_6);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+          StorageLive(_7);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+          _7 = &_1;                        // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+          _6 = &raw const (*_7);           // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+          _5 = _6;                         // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+          _4 = move _5 as *const i32 (Misc); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:59
+          StorageDead(_5);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:58: +4:59
+          StorageLive(_8);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:91
+          StorageLive(_9);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+          StorageLive(_10);                // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+          StorageLive(_11);                // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+          _11 = &mut _2;                   // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+          _10 = &raw mut (*_11);           // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+          _9 = _10;                        // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+          _8 = move _9 as *mut i32 (Misc); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:91
+          StorageDead(_9);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91
+-         _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:65:9: 65:28
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::<i32>}, val: Value(<ZST>) }
++         copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
++         goto -> bb1;                     // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+      }
+  
+      bb1: {
+          StorageDead(_8);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:94: +4:95
+          StorageDead(_4);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:94: +4:95
+          StorageDead(_11);                // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          StorageDead(_10);                // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          StorageDead(_7);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          StorageDead(_6);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          StorageDead(_3);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          _0 = const ();                   // scope 3 at $DIR/lower_intrinsics.rs:+3:5: +5:6
+          StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+6:1: +6:2
+          StorageDead(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+6:1: +6:2
+          return;                          // scope 0 at $DIR/lower_intrinsics.rs:+6:2: +6:2
+      }
+  }
+  
index 195543d42bb5ba157b8a46c5d2b5fed5c1a96a13..66dae0e46b9d7a15912ad5d6c02394dd58f4fee9 100644 (file)
@@ -1,7 +1,7 @@
 // unit-test: LowerIntrinsics
 // ignore-wasm32 compiled with panic=abort by default
 
-#![feature(core_intrinsics)]
+#![feature(core_intrinsics, intrinsics)]
 #![crate_type = "lib"]
 
 // EMIT_MIR lower_intrinsics.wrapping.LowerIntrinsics.diff
@@ -51,3 +51,24 @@ pub fn discriminant<T>(t: T) {
     core::intrinsics::discriminant_value(&());
     core::intrinsics::discriminant_value(&E::B);
 }
+
+extern "rust-intrinsic" {
+    // Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function
+    fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+}
+
+// EMIT_MIR lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
+pub fn f_copy_nonoverlapping() {
+    let src = ();
+    let mut dst = ();
+    unsafe {
+        copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
+    }
+}
+
+// EMIT_MIR lower_intrinsics.assume.LowerIntrinsics.diff
+pub fn assume() {
+    unsafe {
+        std::intrinsics::assume(true);
+    }
+}
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
deleted file mode 100644 (file)
index f9eeb1e..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-- // MIR for `bar` before MatchBranchSimplification
-+ // MIR for `bar` after MatchBranchSimplification
-  
-  fn bar(_1: i32) -> (bool, bool, bool, bool) {
-      debug i => _1;                       // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:9
-      let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:19: +0:43
-      let _2: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
-      let _6: ();                          // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
-      let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
-      let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
-      let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
-      let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
-+     let mut _11: i32;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-      scope 1 {
-          debug a => _2;                   // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
-          let _3: bool;                    // in scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
-          scope 2 {
-              debug b => _3;               // in scope 2 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
-              let _4: bool;                // in scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
-              scope 3 {
-                  debug c => _4;           // in scope 3 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
-                  let _5: bool;            // in scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
-                  scope 4 {
-                      debug d => _5;       // in scope 4 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
-                  }
-              }
-          }
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
-          StorageLive(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
-          StorageLive(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
-          StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
-          StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
--         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
--     }
-- 
--     bb1: {
--         _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+15:13: +15:21
--         _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22
--         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22
--         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21
--         Deinit(_6);                      // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
--         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
--     }
-- 
--     bb2: {
--         _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
--         _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
-+         StorageLive(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-+         _11 = _1;                        // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-+         _2 = Ne(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
-+         _3 = Eq(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
-          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22
-          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21
-          Deinit(_6);                      // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
--         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
--     }
-- 
--     bb3: {
-+         StorageDead(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-          StorageDead(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:+21:6: +21:7
-          StorageLive(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
-          _7 = _2;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
-          StorageLive(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
-          _8 = _3;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
-          StorageLive(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
-          _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
-          StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
-          _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
-          Deinit(_0);                      // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.3: bool) = move _10;         // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          StorageDead(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
-          StorageDead(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
-          StorageDead(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
-          StorageDead(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
-          StorageDead(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
-          StorageDead(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
-          StorageDead(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+24:2: +24:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
deleted file mode 100644 (file)
index f9eeb1e..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-- // MIR for `bar` before MatchBranchSimplification
-+ // MIR for `bar` after MatchBranchSimplification
-  
-  fn bar(_1: i32) -> (bool, bool, bool, bool) {
-      debug i => _1;                       // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:9
-      let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:19: +0:43
-      let _2: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
-      let _6: ();                          // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
-      let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
-      let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
-      let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
-      let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
-+     let mut _11: i32;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-      scope 1 {
-          debug a => _2;                   // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
-          let _3: bool;                    // in scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
-          scope 2 {
-              debug b => _3;               // in scope 2 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
-              let _4: bool;                // in scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
-              scope 3 {
-                  debug c => _4;           // in scope 3 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
-                  let _5: bool;            // in scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
-                  scope 4 {
-                      debug d => _5;       // in scope 4 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
-                  }
-              }
-          }
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
-          StorageLive(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
-          StorageLive(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
-          StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
-          StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
--         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
--     }
-- 
--     bb1: {
--         _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+15:13: +15:21
--         _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22
--         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22
--         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21
--         Deinit(_6);                      // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
--         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
--     }
-- 
--     bb2: {
--         _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
--         _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
-+         StorageLive(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-+         _11 = _1;                        // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-+         _2 = Ne(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
-+         _3 = Eq(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
-          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22
-          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21
-          Deinit(_6);                      // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
--         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
--     }
-- 
--     bb3: {
-+         StorageDead(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-          StorageDead(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:+21:6: +21:7
-          StorageLive(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
-          _7 = _2;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
-          StorageLive(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
-          _8 = _3;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
-          StorageLive(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
-          _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
-          StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
-          _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
-          Deinit(_0);                      // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.3: bool) = move _10;         // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          StorageDead(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
-          StorageDead(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
-          StorageDead(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
-          StorageDead(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
-          StorageDead(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
-          StorageDead(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
-          StorageDead(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+24:2: +24:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff
new file mode 100644 (file)
index 0000000..f9eeb1e
--- /dev/null
@@ -0,0 +1,88 @@
+- // MIR for `bar` before MatchBranchSimplification
++ // MIR for `bar` after MatchBranchSimplification
+  
+  fn bar(_1: i32) -> (bool, bool, bool, bool) {
+      debug i => _1;                       // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:9
+      let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:19: +0:43
+      let _2: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
+      let _6: ();                          // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
+      let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
+      let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
+      let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
+      let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
++     let mut _11: i32;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
+      scope 1 {
+          debug a => _2;                   // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
+          let _3: bool;                    // in scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
+          scope 2 {
+              debug b => _3;               // in scope 2 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
+              let _4: bool;                // in scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
+              scope 3 {
+                  debug c => _4;           // in scope 3 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
+                  let _5: bool;            // in scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
+                  scope 4 {
+                      debug d => _5;       // in scope 4 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
+          StorageLive(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
+          StorageLive(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
+          StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
+          StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
+-         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
+-     }
+- 
+-     bb1: {
+-         _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+15:13: +15:21
+-         _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22
+-         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22
+-         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21
+-         Deinit(_6);                      // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
+-         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
+-     }
+- 
+-     bb2: {
+-         _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
+-         _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
++         StorageLive(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
++         _11 = _1;                        // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
++         _2 = Ne(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
++         _3 = Eq(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
+          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22
+          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21
+          Deinit(_6);                      // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
+-         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
+-     }
+- 
+-     bb3: {
++         StorageDead(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
+          StorageDead(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:+21:6: +21:7
+          StorageLive(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
+          _7 = _2;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
+          StorageLive(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
+          _8 = _3;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
+          StorageLive(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
+          _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
+          StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
+          _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
+          Deinit(_0);                      // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
+          (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
+          (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
+          (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
+          (_0.3: bool) = move _10;         // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
+          StorageDead(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
+          StorageDead(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
+          StorageDead(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
+          StorageDead(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
+          StorageDead(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
+          StorageDead(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
+          StorageDead(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+24:2: +24:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff
deleted file mode 100644 (file)
index 0b40b3b..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-- // MIR for `foo` before MatchBranchSimplification
-+ // MIR for `foo` after MatchBranchSimplification
-  
-  fn foo(_1: Option<()>) -> () {
-      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11
-      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25
-      let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
-+     let mut _4: isize;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
--         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         StorageLive(_4);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         _4 = move _3;                    // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         _2 = Eq(_4, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         StorageDead(_4);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb1: {
--         _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--         goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--     }
-- 
--     bb2: {
--         _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--         goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--     }
-- 
--     bb3: {
--         switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--     }
-- 
--     bb4: {
-          Deinit(_0);                      // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11
--         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-      }
-  
--     bb5: {
-+     bb2: {
-          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:+3:6: +3:6
--         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-      }
-  
--     bb6: {
-+     bb3: {
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+3:5: +3:6
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
deleted file mode 100644 (file)
index 0b40b3b..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-- // MIR for `foo` before MatchBranchSimplification
-+ // MIR for `foo` after MatchBranchSimplification
-  
-  fn foo(_1: Option<()>) -> () {
-      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11
-      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25
-      let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
-+     let mut _4: isize;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
--         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         StorageLive(_4);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         _4 = move _3;                    // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         _2 = Eq(_4, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         StorageDead(_4);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb1: {
--         _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--         goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--     }
-- 
--     bb2: {
--         _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--         goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--     }
-- 
--     bb3: {
--         switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--     }
-- 
--     bb4: {
-          Deinit(_0);                      // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11
--         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-      }
-  
--     bb5: {
-+     bb2: {
-          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:+3:6: +3:6
--         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-      }
-  
--     bb6: {
-+     bb3: {
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+3:5: +3:6
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff
new file mode 100644 (file)
index 0000000..0b40b3b
--- /dev/null
@@ -0,0 +1,55 @@
+- // MIR for `foo` before MatchBranchSimplification
++ // MIR for `foo` after MatchBranchSimplification
+  
+  fn foo(_1: Option<()>) -> () {
+      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11
+      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25
+      let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
++     let mut _4: isize;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
+-         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++         StorageLive(_4);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++         _4 = move _3;                    // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++         _2 = Eq(_4, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++         StorageDead(_4);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      }
+  
+      bb1: {
+-         _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-         goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-     }
+- 
+-     bb2: {
+-         _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-         goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-     }
+- 
+-     bb3: {
+-         switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-     }
+- 
+-     bb4: {
+          Deinit(_0);                      // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11
+-         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
++         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
+      }
+  
+-     bb5: {
++     bb2: {
+          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:+3:6: +3:6
+-         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
++         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
+      }
+  
+-     bb6: {
++     bb3: {
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+3:5: +3:6
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff
deleted file mode 100644 (file)
index b8c7722..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-- // MIR for `match_nested_if` before MatchBranchSimplification
-+ // MIR for `match_nested_if` after MatchBranchSimplification
-  
-  fn match_nested_if() -> bool {
-      let mut _0: bool;                    // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29
-      let _1: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
-      let mut _2: ();                      // in scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
-      let mut _3: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-      let mut _4: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-      let mut _5: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-      let mut _6: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+     let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+     let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+     let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+     let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-      scope 1 {
-          debug val => _1;                 // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
-          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
-          Deinit(_2);                      // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
-          StorageLive(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-          StorageLive(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-          StorageLive(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-          StorageLive(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-          _6 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
--         switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
--     }
-- 
--     bb1: {
--         _5 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:31: +2:35
--         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
--     }
-- 
--     bb2: {
--         _5 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
--         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
--     }
-- 
--     bb3: {
-+         StorageLive(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+         _7 = move _6;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+         _5 = Ne(_7, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
-+         StorageDead(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-          StorageDead(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
--         switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
--     }
-- 
--     bb4: {
--         _4 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:55: +2:59
--         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
--     }
-- 
--     bb5: {
--         _4 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
--         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
--     }
-- 
--     bb6: {
-+         StorageLive(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+         _8 = move _5;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+         _4 = Ne(_8, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
-+         StorageDead(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-          StorageDead(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:75: +2:76
--         switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
--     }
-- 
--     bb7: {
--         _3 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+3:13: +3:17
--         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
--     }
-- 
--     bb8: {
--         _3 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
--         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
--     }
-- 
--     bb9: {
--         switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
--     }
-- 
--     bb10: {
-+         StorageLive(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+         _9 = move _4;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+         _3 = Ne(_9, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
-+         StorageDead(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+         StorageLive(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-+         _10 = move _3;                   // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-          StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
-          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
--         _1 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
--         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
--     }
-- 
--     bb11: {
--         StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
--         StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
--         _1 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
--         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
--     }
-- 
--     bb12: {
-+         _1 = Ne(_10, const false);       // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-+         StorageDead(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+11:6: +11:7
-          _0 = _1;                         // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8
-          StorageDead(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff
deleted file mode 100644 (file)
index b8c7722..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-- // MIR for `match_nested_if` before MatchBranchSimplification
-+ // MIR for `match_nested_if` after MatchBranchSimplification
-  
-  fn match_nested_if() -> bool {
-      let mut _0: bool;                    // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29
-      let _1: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
-      let mut _2: ();                      // in scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
-      let mut _3: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-      let mut _4: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-      let mut _5: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-      let mut _6: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+     let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+     let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+     let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+     let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-      scope 1 {
-          debug val => _1;                 // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
-          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
-          Deinit(_2);                      // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
-          StorageLive(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-          StorageLive(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-          StorageLive(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-          StorageLive(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-          _6 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
--         switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
--     }
-- 
--     bb1: {
--         _5 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:31: +2:35
--         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
--     }
-- 
--     bb2: {
--         _5 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
--         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
--     }
-- 
--     bb3: {
-+         StorageLive(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+         _7 = move _6;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+         _5 = Ne(_7, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
-+         StorageDead(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-          StorageDead(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
--         switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
--     }
-- 
--     bb4: {
--         _4 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:55: +2:59
--         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
--     }
-- 
--     bb5: {
--         _4 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
--         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
--     }
-- 
--     bb6: {
-+         StorageLive(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+         _8 = move _5;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+         _4 = Ne(_8, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
-+         StorageDead(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-          StorageDead(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:75: +2:76
--         switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
--     }
-- 
--     bb7: {
--         _3 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+3:13: +3:17
--         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
--     }
-- 
--     bb8: {
--         _3 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
--         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
--     }
-- 
--     bb9: {
--         switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
--     }
-- 
--     bb10: {
-+         StorageLive(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+         _9 = move _4;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+         _3 = Ne(_9, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
-+         StorageDead(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+         StorageLive(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-+         _10 = move _3;                   // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-          StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
-          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
--         _1 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
--         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
--     }
-- 
--     bb11: {
--         StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
--         StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
--         _1 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
--         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
--     }
-- 
--     bb12: {
-+         _1 = Ne(_10, const false);       // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-+         StorageDead(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+11:6: +11:7
-          _0 = _1;                         // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8
-          StorageDead(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
new file mode 100644 (file)
index 0000000..b8c7722
--- /dev/null
@@ -0,0 +1,113 @@
+- // MIR for `match_nested_if` before MatchBranchSimplification
++ // MIR for `match_nested_if` after MatchBranchSimplification
+  
+  fn match_nested_if() -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29
+      let _1: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
+      let mut _2: ();                      // in scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+      let mut _3: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+      let mut _4: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+      let mut _5: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+      let mut _6: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++     let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++     let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
++     let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++     let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+      scope 1 {
+          debug val => _1;                 // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
+          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+          Deinit(_2);                      // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
+          StorageLive(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+          StorageLive(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+          StorageLive(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+          StorageLive(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+          _6 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+-         switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+-     }
+- 
+-     bb1: {
+-         _5 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:31: +2:35
+-         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+-     }
+- 
+-     bb2: {
+-         _5 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
+-         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+-     }
+- 
+-     bb3: {
++         StorageLive(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++         _7 = move _6;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++         _5 = Ne(_7, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
++         StorageDead(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+          StorageDead(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
+-         switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+-     }
+- 
+-     bb4: {
+-         _4 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:55: +2:59
+-         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+-     }
+- 
+-     bb5: {
+-         _4 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
+-         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+-     }
+- 
+-     bb6: {
++         StorageLive(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
++         _8 = move _5;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
++         _4 = Ne(_8, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
++         StorageDead(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
+          StorageDead(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:75: +2:76
+-         switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
+-     }
+- 
+-     bb7: {
+-         _3 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+3:13: +3:17
+-         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+-     }
+- 
+-     bb8: {
+-         _3 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
+-         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+-     }
+- 
+-     bb9: {
+-         switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+-     }
+- 
+-     bb10: {
++         StorageLive(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++         _9 = move _4;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++         _3 = Ne(_9, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
++         StorageDead(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
++         StorageLive(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
++         _10 = move _3;                   // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+          StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+-         _1 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
+-         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
+-     }
+- 
+-     bb11: {
+-         StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+-         StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
+-         _1 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
+-         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
+-     }
+- 
+-     bb12: {
++         _1 = Ne(_10, const false);       // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
++         StorageDead(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+11:6: +11:7
+          _0 = _1;                         // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8
+          StorageDead(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2
+      }
+  }
+  
index c122b4c69d15a1a8f17411371eec649a526e8e05..a81d5f7b4e8bc7a529a69fb680b449b7f7fe67fa 100644 (file)
@@ -1,6 +1,6 @@
 // unit-test: MatchBranchSimplification
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
 // EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
 // EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff
deleted file mode 100644 (file)
index 1b4dddc..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-- // MIR for `exhaustive_match` before MatchBranchSimplification
-+ // MIR for `exhaustive_match` after MatchBranchSimplification
-  
-  fn exhaustive_match(_1: E) -> u8 {
-      debug e => _1;                       // in scope 0 at $DIR/matches_u8.rs:+0:25: +0:26
-      let mut _0: u8;                      // return place in scope 0 at $DIR/matches_u8.rs:+0:34: +0:36
-      let mut _2: isize;                   // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
-  
-      bb0: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          _0 = const 1_u8;                 // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
-          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          _0 = const 0_u8;                 // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
-          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
-      }
-  
-      bb4: {
-          return;                          // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff
deleted file mode 100644 (file)
index 1b4dddc..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-- // MIR for `exhaustive_match` before MatchBranchSimplification
-+ // MIR for `exhaustive_match` after MatchBranchSimplification
-  
-  fn exhaustive_match(_1: E) -> u8 {
-      debug e => _1;                       // in scope 0 at $DIR/matches_u8.rs:+0:25: +0:26
-      let mut _0: u8;                      // return place in scope 0 at $DIR/matches_u8.rs:+0:34: +0:36
-      let mut _2: isize;                   // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
-  
-      bb0: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          _0 = const 1_u8;                 // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
-          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          _0 = const 0_u8;                 // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
-          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
-      }
-  
-      bb4: {
-          return;                          // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff
new file mode 100644 (file)
index 0000000..1b4dddc
--- /dev/null
@@ -0,0 +1,32 @@
+- // MIR for `exhaustive_match` before MatchBranchSimplification
++ // MIR for `exhaustive_match` after MatchBranchSimplification
+  
+  fn exhaustive_match(_1: E) -> u8 {
+      debug e => _1;                       // in scope 0 at $DIR/matches_u8.rs:+0:25: +0:26
+      let mut _0: u8;                      // return place in scope 0 at $DIR/matches_u8.rs:+0:34: +0:36
+      let mut _2: isize;                   // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
+          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
+      }
+  
+      bb1: {
+          _0 = const 1_u8;                 // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
+          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
+      }
+  
+      bb3: {
+          _0 = const 0_u8;                 // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
+          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
+      }
+  
+      bb4: {
+          return;                          // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff
deleted file mode 100644 (file)
index 6e73485..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-- // MIR for `exhaustive_match_i8` before MatchBranchSimplification
-+ // MIR for `exhaustive_match_i8` after MatchBranchSimplification
-  
-  fn exhaustive_match_i8(_1: E) -> i8 {
-      debug e => _1;                       // in scope 0 at $DIR/matches_u8.rs:+0:28: +0:29
-      let mut _0: i8;                      // return place in scope 0 at $DIR/matches_u8.rs:+0:37: +0:39
-      let mut _2: isize;                   // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
-  
-      bb0: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          _0 = const 1_i8;                 // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
-          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          _0 = const 0_i8;                 // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
-          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
-      }
-  
-      bb4: {
-          return;                          // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff
deleted file mode 100644 (file)
index 6e73485..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-- // MIR for `exhaustive_match_i8` before MatchBranchSimplification
-+ // MIR for `exhaustive_match_i8` after MatchBranchSimplification
-  
-  fn exhaustive_match_i8(_1: E) -> i8 {
-      debug e => _1;                       // in scope 0 at $DIR/matches_u8.rs:+0:28: +0:29
-      let mut _0: i8;                      // return place in scope 0 at $DIR/matches_u8.rs:+0:37: +0:39
-      let mut _2: isize;                   // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
-  
-      bb0: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          _0 = const 1_i8;                 // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
-          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          _0 = const 0_i8;                 // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
-          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
-      }
-  
-      bb4: {
-          return;                          // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
new file mode 100644 (file)
index 0000000..6e73485
--- /dev/null
@@ -0,0 +1,32 @@
+- // MIR for `exhaustive_match_i8` before MatchBranchSimplification
++ // MIR for `exhaustive_match_i8` after MatchBranchSimplification
+  
+  fn exhaustive_match_i8(_1: E) -> i8 {
+      debug e => _1;                       // in scope 0 at $DIR/matches_u8.rs:+0:28: +0:29
+      let mut _0: i8;                      // return place in scope 0 at $DIR/matches_u8.rs:+0:37: +0:39
+      let mut _2: isize;                   // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
+          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
+      }
+  
+      bb1: {
+          _0 = const 1_i8;                 // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
+          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
+      }
+  
+      bb3: {
+          _0 = const 0_i8;                 // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
+          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
+      }
+  
+      bb4: {
+          return;                          // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
+      }
+  }
+  
index 2c748b02a8b76711fc937d7447016410a440644d..422c3a95e8efa3cd894bb7a2dbc1e5036d806ce5 100644 (file)
@@ -1,6 +1,6 @@
 // unit-test: MatchBranchSimplification
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR matches_u8.exhaustive_match.MatchBranchSimplification.diff
 // EMIT_MIR matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
 
index 6c2e265d5146920aff554c383da16631591ac1e7..cb65242609086e0ef04ca11b20eb2b74e0fd7e35 100644 (file)
@@ -1,6 +1,6 @@
 // ignore-wasm32-bare compiled with panic=abort by default
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
 fn main() {
     let mut x = Packed(Aligned(Droppy(0)));
diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir
deleted file mode 100644 (file)
index f9ed103..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-// MIR for `main` after SimplifyCfg-elaborate-drops
-
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +0:11
-    let mut _1: Packed;                  // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
-    let mut _2: Aligned;                 // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
-    let mut _3: Droppy;                  // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-    let mut _4: Aligned;                 // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
-    let mut _5: Droppy;                  // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-    let mut _6: Aligned;                 // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-    scope 1 {
-        debug x => _1;                   // in scope 1 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
-        StorageLive(_2);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
-        StorageLive(_3);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-        Deinit(_3);                      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-        (_3.0: usize) = const 0_usize;   // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-        Deinit(_2);                      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
-        (_2.0: Droppy) = move _3;        // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
-        StorageDead(_3);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42
-        Deinit(_1);                      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
-        (_1.0: Aligned) = move _2;       // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
-        StorageDead(_2);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43
-        StorageLive(_4);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
-        StorageLive(_5);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-        Deinit(_5);                      // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-        (_5.0: usize) = const 0_usize;   // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-        Deinit(_4);                      // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
-        (_4.0: Droppy) = move _5;        // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
-        StorageDead(_5);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
-        StorageLive(_6);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        _6 = move (_1.0: Aligned);       // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-    }
-
-    bb1: {
-        StorageDead(_1);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
-        return;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:2: +3:2
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:1: +3:2
-    }
-
-    bb3 (cleanup): {
-        (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        drop(_1) -> bb2;                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
-    }
-
-    bb4: {
-        StorageDead(_6);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        StorageDead(_4);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
-        _0 = const ();                   // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +3:2
-        drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
-    }
-}
diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir
deleted file mode 100644 (file)
index f9ed103..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-// MIR for `main` after SimplifyCfg-elaborate-drops
-
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +0:11
-    let mut _1: Packed;                  // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
-    let mut _2: Aligned;                 // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
-    let mut _3: Droppy;                  // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-    let mut _4: Aligned;                 // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
-    let mut _5: Droppy;                  // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-    let mut _6: Aligned;                 // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-    scope 1 {
-        debug x => _1;                   // in scope 1 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
-        StorageLive(_2);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
-        StorageLive(_3);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-        Deinit(_3);                      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-        (_3.0: usize) = const 0_usize;   // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-        Deinit(_2);                      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
-        (_2.0: Droppy) = move _3;        // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
-        StorageDead(_3);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42
-        Deinit(_1);                      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
-        (_1.0: Aligned) = move _2;       // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
-        StorageDead(_2);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43
-        StorageLive(_4);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
-        StorageLive(_5);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-        Deinit(_5);                      // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-        (_5.0: usize) = const 0_usize;   // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-        Deinit(_4);                      // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
-        (_4.0: Droppy) = move _5;        // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
-        StorageDead(_5);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
-        StorageLive(_6);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        _6 = move (_1.0: Aligned);       // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-    }
-
-    bb1: {
-        StorageDead(_1);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
-        return;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:2: +3:2
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:1: +3:2
-    }
-
-    bb3 (cleanup): {
-        (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        drop(_1) -> bb2;                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
-    }
-
-    bb4: {
-        StorageDead(_6);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        StorageDead(_4);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
-        _0 = const ();                   // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +3:2
-        drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
-    }
-}
diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
new file mode 100644 (file)
index 0000000..f9ed103
--- /dev/null
@@ -0,0 +1,60 @@
+// MIR for `main` after SimplifyCfg-elaborate-drops
+
+fn main() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +0:11
+    let mut _1: Packed;                  // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
+    let mut _2: Aligned;                 // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
+    let mut _3: Droppy;                  // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
+    let mut _4: Aligned;                 // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
+    let mut _5: Droppy;                  // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
+    let mut _6: Aligned;                 // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+    scope 1 {
+        debug x => _1;                   // in scope 1 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
+        StorageLive(_2);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
+        StorageLive(_3);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
+        Deinit(_3);                      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
+        (_3.0: usize) = const 0_usize;   // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
+        Deinit(_2);                      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
+        (_2.0: Droppy) = move _3;        // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
+        StorageDead(_3);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42
+        Deinit(_1);                      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
+        (_1.0: Aligned) = move _2;       // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
+        StorageDead(_2);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43
+        StorageLive(_4);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
+        StorageLive(_5);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
+        Deinit(_5);                      // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
+        (_5.0: usize) = const 0_usize;   // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
+        Deinit(_4);                      // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
+        (_4.0: Droppy) = move _5;        // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
+        StorageDead(_5);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
+        StorageLive(_6);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+        _6 = move (_1.0: Aligned);       // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+        drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+    }
+
+    bb1: {
+        StorageDead(_1);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
+        return;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:2: +3:2
+    }
+
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:1: +3:2
+    }
+
+    bb3 (cleanup): {
+        (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+        drop(_1) -> bb2;                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
+    }
+
+    bb4: {
+        StorageDead(_6);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+        (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+        StorageDead(_4);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
+        _0 = const ();                   // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +3:2
+        drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
+    }
+}
diff --git a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff b/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
deleted file mode 100644 (file)
index 28536dc..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-- // MIR for `identity` before ConstProp
-+ // MIR for `identity` after ConstProp
-  
-  fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
-      debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14
-      let mut _0: std::result::Result<i32, i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53
-      let mut _2: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, i32>, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      let mut _4: std::result::Result<i32, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-      let mut _5: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-      let _6: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-      let mut _7: !;                       // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-      let mut _8: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-      let _9: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      scope 1 {
-          debug residual => _6;            // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          scope 2 {
-              scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
-                  debug residual => _8;    // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let _16: i32;            // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let mut _17: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let mut _18: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  scope 9 {
-                      debug e => _16;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-                      scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
-                          debug t => _18;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-                      }
-                  }
-              }
-          }
-      }
-      scope 3 {
-          debug val => _9;                 // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          scope 4 {
-          }
-      }
-      scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
-          debug self => _4;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let mut _10: isize;              // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let _11: i32;                    // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let mut _12: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let _13: i32;                    // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let mut _14: std::result::Result<std::convert::Infallible, i32>; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let mut _15: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          scope 6 {
-              debug v => _11;              // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          }
-          scope 7 {
-              debug e => _13;              // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          }
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          StorageLive(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-          _4 = _1;                         // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-          _10 = discriminant(_4);          // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-      }
-  
-      bb1: {
-          StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          _9 = ((_3 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          _2 = _9;                         // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          Deinit(_0);                      // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-          ((_0 as Ok).0: i32) = move _2;   // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-          discriminant(_0) = 0;            // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      }
-  
-      bb3: {
-          StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          _6 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageLive(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          _8 = _6;                         // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageLive(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          _16 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          _18 = move _16;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          _17 = move _18;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-          StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-      }
-  
-      bb4: {
-          StorageLive(_13);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          _13 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          _15 = move _13;                  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_14);                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_14 as Err).0: i32) = move _15; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_14) = 1;           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_3);                      // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _14; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_3) = 1;            // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_13);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
--         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
--         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         _5 = const 1_isize;              // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         switchInt(const 1_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      }
-  
-      bb5: {
-          unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-      }
-  
-      bb6: {
-          StorageLive(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          _11 = move ((_4 as Ok).0: i32);  // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          _12 = move _11;                  // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_3);                      // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_3 as Continue).0: i32) = move _12; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_3) = 0;            // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
--         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
--         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         _5 = const 0_isize;              // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         switchInt(const 0_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      }
-  }
-  
diff --git a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
deleted file mode 100644 (file)
index df20f0e..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-// MIR for `identity` after PreCodegen
-
-fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
-    debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14
-    let mut _0: std::result::Result<i32, i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53
-    let mut _2: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-    let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, i32>, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-    let mut _4: std::result::Result<i32, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-    let _5: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-    let mut _6: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-    let _7: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-    scope 1 {
-        debug residual => _5;            // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        scope 2 {
-            scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
-                debug residual => _6;    // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                let _14: i32;            // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                let mut _15: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                let mut _16: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                scope 9 {
-                    debug e => _14;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-                    scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
-                        debug t => _16;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-                    }
-                }
-            }
-        }
-    }
-    scope 3 {
-        debug val => _7;                 // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        scope 4 {
-        }
-    }
-    scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
-        debug self => _4;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let mut _8: isize;               // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let _9: i32;                     // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let mut _10: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let _11: i32;                    // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let mut _12: std::result::Result<std::convert::Infallible, i32>; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let mut _13: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        scope 6 {
-            debug v => _9;               // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        }
-        scope 7 {
-            debug e => _11;              // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        }
-    }
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        StorageLive(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-        _4 = _1;                         // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-        _8 = discriminant(_4);           // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        switchInt(move _8) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-    }
-
-    bb1: {
-        StorageLive(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        _11 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_12);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_13);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        _13 = move _11;                  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        Deinit(_12);                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        ((_12 as Err).0: i32) = move _13; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        discriminant(_12) = 1;           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_13);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        Deinit(_3);                      // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _12; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        discriminant(_3) = 1;            // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_12);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageLive(_5);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        _5 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageLive(_6);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        _6 = _5;                         // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageLive(_14);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-        _14 = move ((_6 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_15);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_16);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        _16 = move _14;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        _15 = move _16;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-        StorageDead(_16);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        ((_0 as Err).0: i32) = move _15; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_15);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_14);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_6);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageDead(_5);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-        StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-        return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-    }
-
-    bb2: {
-        unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-    }
-
-    bb3: {
-        StorageLive(_9);                 // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        _9 = move ((_4 as Ok).0: i32);   // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_10);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        _10 = move _9;                   // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        Deinit(_3);                      // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        ((_3 as Continue).0: i32) = move _10; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        discriminant(_3) = 0;            // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_10);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_9);                 // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageLive(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        _7 = ((_3 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        _2 = _7;                         // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        StorageDead(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        Deinit(_0);                      // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-        ((_0 as Ok).0: i32) = move _2;   // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-        discriminant(_0) = 0;            // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-        StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-        StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-        return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-    }
-}
diff --git a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff b/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff
deleted file mode 100644 (file)
index 2826916..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-- // MIR for `too_complex` before ConstProp
-+ // MIR for `too_complex` after ConstProp
-  
-  fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
-      debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17
-      let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53
-      let mut _2: std::ops::ControlFlow<usize, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-      let mut _3: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18
-      let _4: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-      let mut _5: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45
-      let _6: usize;                       // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-      let mut _7: usize;                   // in scope 0 at $DIR/separate_const_switch.rs:+8:42: +8:43
-      let mut _8: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+11:9: +11:33
-      let _9: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-      let mut _10: i32;                    // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43
-      let _11: usize;                      // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-      scope 1 {
-          debug v => _4;                   // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17
-      }
-      scope 2 {
-          debug r => _6;                   // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18
-      }
-      scope 3 {
-          debug v => _9;                   // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32
-      }
-      scope 4 {
-          debug r => _11;                  // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-          _3 = discriminant(_1);           // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-          switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16
-      }
-  
-      bb1: {
-          StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-          _6 = ((_1 as Err).0: usize);     // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-          StorageLive(_7);                 // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43
-          _7 = _6;                         // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43
-          Deinit(_2);                      // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
-          ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
-          discriminant(_2) = 1;            // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
-          StorageDead(_7);                 // scope 2 at $DIR/separate_const_switch.rs:+8:43: +8:44
-          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
--         _8 = discriminant(_2);           // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
--         switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-+         _8 = const 1_isize;              // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-+         switchInt(const 1_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-      }
-  
-      bb3: {
-          StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-          _4 = ((_1 as Ok).0: i32);        // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-          StorageLive(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-          _5 = _4;                         // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-          Deinit(_2);                      // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-          ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-          discriminant(_2) = 0;            // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-          StorageDead(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46
-          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
--         _8 = discriminant(_2);           // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
--         switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-+         _8 = const 0_isize;              // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-+         switchInt(const 0_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-      }
-  
-      bb4: {
-          StorageLive(_11);                // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-          _11 = ((_2 as Break).0: usize);  // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-          Deinit(_0);                      // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-          discriminant(_0) = 0;            // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-          StorageDead(_11);                // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-          goto -> bb7;                     // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-      }
-  
-      bb5: {
-          unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-      }
-  
-      bb6: {
-          StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-          _9 = ((_2 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-          StorageLive(_10);                // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-          _10 = _9;                        // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-          Deinit(_0);                      // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-          ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-          discriminant(_0) = 1;            // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-          StorageDead(_10);                // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44
-          StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-          goto -> bb7;                     // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-      }
-  
-      bb7: {
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir
deleted file mode 100644 (file)
index 0ee0706..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-// MIR for `too_complex` after PreCodegen
-
-fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
-    debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17
-    let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53
-    let mut _2: std::ops::ControlFlow<usize, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-    let mut _3: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18
-    let _4: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-    let mut _5: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45
-    let _6: usize;                       // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-    let _7: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-    let mut _8: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43
-    let _9: usize;                       // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-    scope 1 {
-        debug v => _4;                   // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17
-    }
-    scope 2 {
-        debug r => _6;                   // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18
-    }
-    scope 3 {
-        debug v => _7;                   // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32
-    }
-    scope 4 {
-        debug r => _9;                   // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29
-    }
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-        _3 = discriminant(_1);           // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-        switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16
-    }
-
-    bb1: {
-        StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-        StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
-        StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-        Deinit(_0);                      // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-        discriminant(_0) = 0;            // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-        StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-        goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-    }
-
-    bb2: {
-        unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-    }
-
-    bb3: {
-        StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-        _4 = ((_1 as Ok).0: i32);        // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-        StorageLive(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-        _5 = _4;                         // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-        Deinit(_2);                      // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-        ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-        discriminant(_2) = 0;            // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-        StorageDead(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46
-        StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
-        StorageLive(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-        _7 = ((_2 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-        StorageLive(_8);                 // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-        _8 = _7;                         // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-        Deinit(_0);                      // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-        ((_0 as Some).0: i32) = move _8; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-        discriminant(_0) = 1;            // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-        StorageDead(_8);                 // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44
-        StorageDead(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-        goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-    }
-
-    bb4: {
-        StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2
-        return;                          // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2
-    }
-}
index 44adc55b6f7feadd5418f31ad8b676a3f26b69b8..103033c4e2b861072f03d35aed92333f8cdbb274 100644 (file)
@@ -1,6 +1,6 @@
 // Test that we don't generate unnecessarily large MIR for very simple matches
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR simple_match.match_bool.mir_map.0.mir
 fn match_bool(x: bool) -> usize {
     match x {
diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir
deleted file mode 100644 (file)
index 3bef6aa..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// MIR for `match_bool` 0 mir_map
-
-fn match_bool(_1: bool) -> usize {
-    debug x => _1;                       // in scope 0 at $DIR/simple-match.rs:+0:15: +0:16
-    let mut _0: usize;                   // return place in scope 0 at $DIR/simple-match.rs:+0:27: +0:32
-
-    bb0: {
-        FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:+1:11: +1:12
-        switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:+1:5: +1:12
-    }
-
-    bb1: {
-        falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:+2:9: +2:13
-    }
-
-    bb2: {
-        _0 = const 20_usize;             // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
-        goto -> bb4;                     // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
-    }
-
-    bb3: {
-        _0 = const 10_usize;             // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
-        goto -> bb4;                     // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
-    }
-
-    bb4: {
-        return;                          // scope 0 at $DIR/simple-match.rs:+5:2: +5:2
-    }
-}
diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir
deleted file mode 100644 (file)
index 3bef6aa..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// MIR for `match_bool` 0 mir_map
-
-fn match_bool(_1: bool) -> usize {
-    debug x => _1;                       // in scope 0 at $DIR/simple-match.rs:+0:15: +0:16
-    let mut _0: usize;                   // return place in scope 0 at $DIR/simple-match.rs:+0:27: +0:32
-
-    bb0: {
-        FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:+1:11: +1:12
-        switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:+1:5: +1:12
-    }
-
-    bb1: {
-        falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:+2:9: +2:13
-    }
-
-    bb2: {
-        _0 = const 20_usize;             // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
-        goto -> bb4;                     // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
-    }
-
-    bb3: {
-        _0 = const 10_usize;             // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
-        goto -> bb4;                     // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
-    }
-
-    bb4: {
-        return;                          // scope 0 at $DIR/simple-match.rs:+5:2: +5:2
-    }
-}
diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.mir
new file mode 100644 (file)
index 0000000..3bef6aa
--- /dev/null
@@ -0,0 +1,29 @@
+// MIR for `match_bool` 0 mir_map
+
+fn match_bool(_1: bool) -> usize {
+    debug x => _1;                       // in scope 0 at $DIR/simple-match.rs:+0:15: +0:16
+    let mut _0: usize;                   // return place in scope 0 at $DIR/simple-match.rs:+0:27: +0:32
+
+    bb0: {
+        FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:+1:11: +1:12
+        switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:+1:5: +1:12
+    }
+
+    bb1: {
+        falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:+2:9: +2:13
+    }
+
+    bb2: {
+        _0 = const 20_usize;             // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
+        goto -> bb4;                     // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
+    }
+
+    bb3: {
+        _0 = const 10_usize;             // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
+        goto -> bb4;                     // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
+    }
+
+    bb4: {
+        return;                          // scope 0 at $DIR/simple-match.rs:+5:2: +5:2
+    }
+}
index 62a15df04b14429940d05a89f1711268caa43dc2..d09bd92c4e81d176328a1159f1c23aadd8c1e723 100644 (file)
@@ -11,5 +11,4 @@ fn main() {
     map(None);
 }
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff
deleted file mode 100644 (file)
index 51d26b0..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-- // MIR for `map` before SimplifyLocals
-+ // MIR for `map` after SimplifyLocals
-  
-  fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
-      debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9
-      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46
-      let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13
-      let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-      let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
--     let mut _5: bool;                    // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
--     let mut _6: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
--     let mut _7: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
-      scope 1 {
-          debug x => _3;                   // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-      }
-  
-      bb0: {
--         _5 = const false;                // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
--         _5 = const true;                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
-          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          StorageLive(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-          _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-          StorageLive(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
-          _4 = move _3;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
-          Deinit(_0);                      // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
-          ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
-          discriminant(_0) = 1;            // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
-          StorageDead(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
-          StorageDead(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
-          goto -> bb4;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          Deinit(_0);                      // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
-          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
-          goto -> bb4;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
-      }
-  
-      bb4: {
--         _6 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
-          return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff
deleted file mode 100644 (file)
index 51d26b0..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-- // MIR for `map` before SimplifyLocals
-+ // MIR for `map` after SimplifyLocals
-  
-  fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
-      debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9
-      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46
-      let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13
-      let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-      let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
--     let mut _5: bool;                    // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
--     let mut _6: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
--     let mut _7: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
-      scope 1 {
-          debug x => _3;                   // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-      }
-  
-      bb0: {
--         _5 = const false;                // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
--         _5 = const true;                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
-          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          StorageLive(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-          _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-          StorageLive(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
-          _4 = move _3;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
-          Deinit(_0);                      // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
-          ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
-          discriminant(_0) = 1;            // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
-          StorageDead(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
-          StorageDead(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
-          goto -> bb4;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          Deinit(_0);                      // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
-          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
-          goto -> bb4;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
-      }
-  
-      bb4: {
--         _6 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
-          return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff
new file mode 100644 (file)
index 0000000..51d26b0
--- /dev/null
@@ -0,0 +1,52 @@
+- // MIR for `map` before SimplifyLocals
++ // MIR for `map` after SimplifyLocals
+  
+  fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
+      debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9
+      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13
+      let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+      let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
+-     let mut _5: bool;                    // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
+-     let mut _6: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
+-     let mut _7: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
+      scope 1 {
+          debug x => _3;                   // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+      }
+  
+      bb0: {
+-         _5 = const false;                // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
+-         _5 = const true;                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
+          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12
+      }
+  
+      bb1: {
+          StorageLive(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+          _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+          StorageLive(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
+          _4 = move _3;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
+          Deinit(_0);                      // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
+          ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
+          discriminant(_0) = 1;            // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
+          StorageDead(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
+          goto -> bb4;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
+      }
+  
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
+      }
+  
+      bb3: {
+          Deinit(_0);                      // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
+          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
+          goto -> bb4;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
+      }
+  
+      bb4: {
+-         _6 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
+          return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2
+      }
+  }
+  
index 0fd32906db6be56536e6d51e65bf26864e4daf1d..344c1af2c91347c661ace0a5476d8dd05e5dd894 100644 (file)
@@ -1,6 +1,6 @@
 // compile-flags: -Zmir-opt-level=0
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
 fn main() {
     let _fn = std::ptr::drop_in_place::<[String]> as unsafe fn(_);
diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir
deleted file mode 100644 (file)
index b4b317e..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
-
-fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
-    let mut _0: ();                      // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _2: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _3: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _4: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _6: bool;                    // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _8: bool;                    // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _12: bool;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _14: bool;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-
-    bb0: {
-        goto -> bb15;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb1: {
-        return;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb3 (cleanup): {
-        _5 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_5)) -> bb4;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb4 (cleanup): {
-        _6 = Eq(_4, _3);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb5: {
-        _7 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb6: {
-        _8 = Eq(_4, _3);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb7: {
-        _4 = const 0_usize;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        goto -> bb6;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb8: {
-        goto -> bb7;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb9 (cleanup): {
-        _11 = _9;                        // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_11)) -> bb10;            // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb10 (cleanup): {
-        _12 = Eq(_9, _10);               // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb11: {
-        _13 = _9;                        // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb12: {
-        _14 = Eq(_9, _10);               // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb13: {
-        _15 = &raw mut (*_1);            // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _9 = move _15 as *mut std::string::String (Misc); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _10 = Offset(_9, move _3);       // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        goto -> bb12;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb14: {
-        goto -> bb13;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb15: {
-        _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _3 = Len((*_1));                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-}
diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir
deleted file mode 100644 (file)
index b4b317e..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
-
-fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
-    let mut _0: ();                      // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _2: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _3: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _4: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _6: bool;                    // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _8: bool;                    // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _12: bool;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _14: bool;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-
-    bb0: {
-        goto -> bb15;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb1: {
-        return;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb3 (cleanup): {
-        _5 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_5)) -> bb4;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb4 (cleanup): {
-        _6 = Eq(_4, _3);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb5: {
-        _7 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb6: {
-        _8 = Eq(_4, _3);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb7: {
-        _4 = const 0_usize;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        goto -> bb6;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb8: {
-        goto -> bb7;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb9 (cleanup): {
-        _11 = _9;                        // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_11)) -> bb10;            // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb10 (cleanup): {
-        _12 = Eq(_9, _10);               // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb11: {
-        _13 = _9;                        // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb12: {
-        _14 = Eq(_9, _10);               // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb13: {
-        _15 = &raw mut (*_1);            // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _9 = move _15 as *mut std::string::String (Misc); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _10 = Offset(_9, move _3);       // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        goto -> bb12;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb14: {
-        goto -> bb13;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb15: {
-        _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _3 = Len((*_1));                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-}
diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
new file mode 100644 (file)
index 0000000..b4b317e
--- /dev/null
@@ -0,0 +1,101 @@
+// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
+
+fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
+    let mut _0: ();                      // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _2: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _3: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _4: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _6: bool;                    // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _8: bool;                    // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _12: bool;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _14: bool;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+
+    bb0: {
+        goto -> bb15;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb1: {
+        return;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb3 (cleanup): {
+        _5 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        drop((*_5)) -> bb4;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb4 (cleanup): {
+        _6 = Eq(_4, _3);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb5: {
+        _7 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb6: {
+        _8 = Eq(_4, _3);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb7: {
+        _4 = const 0_usize;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        goto -> bb6;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb8: {
+        goto -> bb7;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb9 (cleanup): {
+        _11 = _9;                        // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        drop((*_11)) -> bb10;            // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb10 (cleanup): {
+        _12 = Eq(_9, _10);               // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb11: {
+        _13 = _9;                        // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb12: {
+        _14 = Eq(_9, _10);               // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb13: {
+        _15 = &raw mut (*_1);            // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _9 = move _15 as *mut std::string::String (Misc); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _10 = Offset(_9, move _3);       // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        goto -> bb12;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb14: {
+        goto -> bb13;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb15: {
+        _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _3 = Len((*_1));                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+}
index 6e9a8b4d975fa7a34a4a8ae3d95f1b0b81fa890d..6a5021139cf611f52de7fdf7deae94a04ffb0a9a 100644 (file)
@@ -15,9 +15,9 @@ fn move_out_by_subslice() -> () {
     let mut _11: std::boxed::Box<i32>;   // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
     scope 1 {
         debug a => _1;                   // in scope 1 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
-        let _12: [std::boxed::Box<i32>; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17
+        let _12: [std::boxed::Box<i32>; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
         scope 4 {
-            debug _y => _12;             // in scope 4 at $DIR/uniform_array_move_out.rs:+2:10: +2:17
+            debug _y => _12;             // in scope 4 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
         }
     }
     scope 2 {
@@ -77,8 +77,8 @@ fn move_out_by_subslice() -> () {
     bb6: {
         StorageDead(_2);                 // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
         FakeRead(ForLet(None), _1);      // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
-        StorageLive(_12);                // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17
-        _12 = move _1[0..2];             // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17
+        StorageLive(_12);                // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
+        _12 = move _1[0..2];             // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
         _0 = const ();                   // scope 0 at $DIR/uniform_array_move_out.rs:+0:27: +3:2
         drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
     }
index 670f61cd5ce3aff53a6a51ef1364b1e06bb94509..9ef3d86472db2158c11d09934758ae4b107ab321 100644 (file)
@@ -1,7 +1,7 @@
 // Test that we don't ICE when trying to dump MIR for unusual item types and
 // that we don't create filenames containing `<` and `>`
 // compile-flags: -Zmir-opt-level=0
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 
 struct A;
 
diff --git a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir
deleted file mode 100644 (file)
index a72e00e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// MIR for `E::V::{constant#0}` 0 mir_map
-
-E::V::{constant#0}: isize = {
-    let mut _0: isize;                   // return place in scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
-
-    bb0: {
-        _0 = const 5_isize;              // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
-        return;                          // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
-    }
-}
diff --git a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir
deleted file mode 100644 (file)
index a72e00e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// MIR for `E::V::{constant#0}` 0 mir_map
-
-E::V::{constant#0}: isize = {
-    let mut _0: isize;                   // return place in scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
-
-    bb0: {
-        _0 = const 5_isize;              // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
-        return;                          // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
-    }
-}
diff --git a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.mir b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.mir
new file mode 100644 (file)
index 0000000..a72e00e
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `E::V::{constant#0}` 0 mir_map
+
+E::V::{constant#0}: isize = {
+    let mut _0: isize;                   // return place in scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
+
+    bb0: {
+        _0 = const 5_isize;              // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
+        return;                          // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
+    }
+}
diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir
deleted file mode 100644 (file)
index 0686af4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// MIR for `Test::X` 0 mir_map
-
-fn Test::X(_1: usize) -> Test {
-    let mut _0: Test;                    // return place in scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-
-    bb0: {
-        Deinit(_0);                      // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-        ((_0 as X).0: usize) = move _1;  // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-        discriminant(_0) = 0;            // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-        return;                          // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-    }
-}
diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir
deleted file mode 100644 (file)
index 0686af4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// MIR for `Test::X` 0 mir_map
-
-fn Test::X(_1: usize) -> Test {
-    let mut _0: Test;                    // return place in scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-
-    bb0: {
-        Deinit(_0);                      // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-        ((_0 as X).0: usize) = move _1;  // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-        discriminant(_0) = 0;            // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-        return;                          // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-    }
-}
diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir
new file mode 100644 (file)
index 0000000..0686af4
--- /dev/null
@@ -0,0 +1,12 @@
+// MIR for `Test::X` 0 mir_map
+
+fn Test::X(_1: usize) -> Test {
+    let mut _0: Test;                    // return place in scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
+
+    bb0: {
+        Deinit(_0);                      // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
+        ((_0 as X).0: usize) = move _1;  // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
+        discriminant(_0) = 0;            // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
+        return;                          // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
+    }
+}
diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir
deleted file mode 100644 (file)
index 7ffd242..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
-
-fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () {
-    let mut _0: ();                      // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _2: &mut std::vec::Vec<i32>; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _3: ();                      // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-
-    bb0: {
-        goto -> bb6;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb1: {
-        return;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb3: {
-        goto -> bb1;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb4 (cleanup): {
-        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb5: {
-        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb6: {
-        _2 = &mut (*_1);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-                                         // mir::Constant
-                                         // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) }
-    }
-}
diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir
deleted file mode 100644 (file)
index 7ffd242..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
-
-fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () {
-    let mut _0: ();                      // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _2: &mut std::vec::Vec<i32>; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _3: ();                      // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-
-    bb0: {
-        goto -> bb6;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb1: {
-        return;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb3: {
-        goto -> bb1;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb4 (cleanup): {
-        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb5: {
-        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb6: {
-        _2 = &mut (*_1);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-                                         // mir::Constant
-                                         // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) }
-    }
-}
diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir
new file mode 100644 (file)
index 0000000..7ffd242
--- /dev/null
@@ -0,0 +1,39 @@
+// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
+
+fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () {
+    let mut _0: ();                      // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _2: &mut std::vec::Vec<i32>; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    let mut _3: ();                      // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+
+    bb0: {
+        goto -> bb6;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb1: {
+        return;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb3: {
+        goto -> bb1;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb4 (cleanup): {
+        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb5: {
+        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+    }
+
+    bb6: {
+        _2 = &mut (*_1);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+        _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
+                                         // mir::Constant
+                                         // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+                                         // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) }
+    }
+}
diff --git a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir
deleted file mode 100644 (file)
index e2633f6..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// MIR for `<impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT` 0 mir_map
-
-const <impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT: i32 = {
-    let mut _0: i32;                     // return place in scope 0 at $DIR/unusual-item-types.rs:+0:32: +0:35
-
-    bb0: {
-        _0 = const 2_i32;                // scope 0 at $DIR/unusual-item-types.rs:+0:38: +0:39
-        return;                          // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:39
-    }
-}
diff --git a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir
deleted file mode 100644 (file)
index e2633f6..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// MIR for `<impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT` 0 mir_map
-
-const <impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT: i32 = {
-    let mut _0: i32;                     // return place in scope 0 at $DIR/unusual-item-types.rs:+0:32: +0:35
-
-    bb0: {
-        _0 = const 2_i32;                // scope 0 at $DIR/unusual-item-types.rs:+0:38: +0:39
-        return;                          // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:39
-    }
-}
diff --git a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir
new file mode 100644 (file)
index 0000000..e2633f6
--- /dev/null
@@ -0,0 +1,10 @@
+// MIR for `<impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT` 0 mir_map
+
+const <impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT: i32 = {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/unusual-item-types.rs:+0:32: +0:35
+
+    bb0: {
+        _0 = const 2_i32;                // scope 0 at $DIR/unusual-item-types.rs:+0:38: +0:39
+        return;                          // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:39
+    }
+}
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff
deleted file mode 100644 (file)
index eef7011..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-- // MIR for `change_loop_body` before ConstProp
-+ // MIR for `change_loop_body` after ConstProp
-  
-  fn change_loop_body() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
-      let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-      let mut _2: ();                      // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2
-      let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
-      let mut _4: isize;                   // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
-      let mut _5: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6
-      let mut _6: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
-      let _7: ();                          // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
-      let mut _8: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
-      scope 1 {
-          debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
-          scope 2 {
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-          _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19
-          StorageLive(_3);                 // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-          Deinit(_3);                      // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-          discriminant(_3) = 0;            // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
--         _4 = discriminant(_3);           // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
--         switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+         _4 = const 0_isize;              // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+         switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-      }
-  
-      bb1: {
-          switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-      }
-  
-      bb2: {
-          _1 = const 1_i32;                // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15
-          nop;                             // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
-          goto -> bb4;                     // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
-      }
-  
-      bb3: {
-          StorageLive(_7);                 // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
-          nop;                             // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
-          StorageDead(_7);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
-          goto -> bb4;                     // scope 1 at no-location
-      }
-  
-      bb4: {
-          StorageDead(_3);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
-          StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
-          return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff
deleted file mode 100644 (file)
index eef7011..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-- // MIR for `change_loop_body` before ConstProp
-+ // MIR for `change_loop_body` after ConstProp
-  
-  fn change_loop_body() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
-      let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-      let mut _2: ();                      // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2
-      let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
-      let mut _4: isize;                   // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
-      let mut _5: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6
-      let mut _6: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
-      let _7: ();                          // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
-      let mut _8: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
-      scope 1 {
-          debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
-          scope 2 {
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-          _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19
-          StorageLive(_3);                 // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-          Deinit(_3);                      // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-          discriminant(_3) = 0;            // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
--         _4 = discriminant(_3);           // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
--         switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+         _4 = const 0_isize;              // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+         switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-      }
-  
-      bb1: {
-          switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-      }
-  
-      bb2: {
-          _1 = const 1_i32;                // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15
-          nop;                             // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
-          goto -> bb4;                     // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
-      }
-  
-      bb3: {
-          StorageLive(_7);                 // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
-          nop;                             // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
-          StorageDead(_7);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
-          goto -> bb4;                     // scope 1 at no-location
-      }
-  
-      bb4: {
-          StorageDead(_3);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
-          StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
-          return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff
new file mode 100644 (file)
index 0000000..eef7011
--- /dev/null
@@ -0,0 +1,55 @@
+- // MIR for `change_loop_body` before ConstProp
++ // MIR for `change_loop_body` after ConstProp
+  
+  fn change_loop_body() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
+      let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
+      let mut _2: ();                      // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2
+      let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
+      let mut _4: isize;                   // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
+      let mut _5: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6
+      let mut _6: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
+      let _7: ();                          // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
+      let mut _8: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
+      scope 1 {
+          debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
+          scope 2 {
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
+          _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19
+          StorageLive(_3);                 // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+          Deinit(_3);                      // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+          discriminant(_3) = 0;            // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+-         _4 = discriminant(_3);           // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+-         switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
++         _4 = const 0_isize;              // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
++         switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+      }
+  
+      bb1: {
+          switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+      }
+  
+      bb2: {
+          _1 = const 1_i32;                // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15
+          nop;                             // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
+          goto -> bb4;                     // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
+      }
+  
+      bb3: {
+          StorageLive(_7);                 // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
+          nop;                             // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
+          StorageDead(_7);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
+          goto -> bb4;                     // scope 1 at no-location
+      }
+  
+      bb4: {
+          StorageDead(_3);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
+          StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
+          return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir
deleted file mode 100644 (file)
index 15b0aec..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// MIR for `change_loop_body` after PreCodegen
-
-fn change_loop_body() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
-    let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-    scope 1 {
-        debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-        StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
-        return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
-    }
-}
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir
deleted file mode 100644 (file)
index 15b0aec..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// MIR for `change_loop_body` after PreCodegen
-
-fn change_loop_body() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
-    let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-    scope 1 {
-        debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-        StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
-        return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
-    }
-}
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..15b0aec
--- /dev/null
@@ -0,0 +1,17 @@
+// MIR for `change_loop_body` after PreCodegen
+
+fn change_loop_body() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
+    let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
+    scope 1 {
+        debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
+        scope 2 {
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
+        StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
+        return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
+    }
+}
index f320a218c852c345252882e6950dbf5cfb869a9b..fc56cd6985d69a901049bb0fa65f0e4faea8a840 100644 (file)
@@ -1,6 +1,5 @@
 // EMIT_MIR while_let_loops.change_loop_body.ConstProp.diff
 // EMIT_MIR while_let_loops.change_loop_body.PreCodegen.after.mir
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 pub fn change_loop_body() {
     let mut _x = 0;
index 4475649ca927293c7a8acb47f467bc32d4da0dda..16d9a56e6bf78c472846074595c86a26aaede6b7 100644 (file)
@@ -1,5 +1,6 @@
 include ../../run-make-fulldeps/tools.mk
 
+# ignore-msvc
 # needs-rust-lld
 all:
        RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Z gcc-ld=lld -C link-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt
index b5e9415b2bec312ba2b31effabdbea0bf3ce1e98..fe74fbfd2646f40cff5b57dd0b68d07f3bd31529 100644 (file)
@@ -1,5 +1,5 @@
-#![feature(raw_dylib)]
 #![feature(abi_vectorcall)]
+#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[repr(C)]
 #[derive(Clone)]
index 5efce4e938c8ff6b7f4f808f98d41b54ee1564fa..bb25ac64c613b261a64677e606ce60e6e11e7ecb 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(raw_dylib)]
+#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[link(name = "exporter", kind = "raw-dylib")]
 extern {
index 07dd3d7be9b903a5a0b9a5ccbad6b4cec886c5c2..b7921396a0f4dd50d48fe2908d6f6c0bf1757589 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(raw_dylib)]
+#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[link(name = "exporter", kind = "raw-dylib")]
 extern "stdcall" {
diff --git a/src/test/run-make/track-pgo-dep-info/Makefile b/src/test/run-make/track-pgo-dep-info/Makefile
new file mode 100644 (file)
index 0000000..60b59c0
--- /dev/null
@@ -0,0 +1,26 @@
+# needs-profiler-support
+# ignore-windows-gnu
+
+-include ../../run-make-fulldeps/tools.mk
+
+# FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC`
+# instead of hardcoding them everywhere they're needed.
+ifeq ($(IS_MUSL_HOST),1)
+ADDITIONAL_ARGS := $(RUSTFLAGS)
+endif
+
+all:
+       # Generate PGO profiles
+       $(BARE_RUSTC) $(ADDITIONAL_ARGS) -Cprofile-generate=$(TMPDIR)/profiles --out-dir $(TMPDIR) main.rs
+       $(TMPDIR)/main
+
+       # Merge profiles
+       "$(LLVM_BIN_DIR)/llvm-profdata" merge \
+               -o "$(TMPDIR)/merged.profdata" \
+               "$(TMPDIR)/profiles" || exit 1
+
+       # Use the profile
+       $(RUSTC) -Cprofile-use=$(TMPDIR)/merged.profdata --emit dep-info main.rs
+
+       # Check that profile file is in depinfo
+       $(CGREP) "merged.profdata" < $(TMPDIR)/main.d
diff --git a/src/test/run-make/track-pgo-dep-info/main.rs b/src/test/run-make/track-pgo-dep-info/main.rs
new file mode 100644 (file)
index 0000000..f328e4d
--- /dev/null
@@ -0,0 +1 @@
+fn main() {}
index 3bed7a0a03ea5a786e764882b2e88140f6d76152..c249895503a91cc2af533991b09a7e4894498793 100644 (file)
@@ -4,8 +4,8 @@ goto: file://|DOC_PATH|/test_docs/index.html
 goto: ./fn.check_list_code_block.html
 // If the codeblock is the first element of the docblock, the information tooltip must have
 // have some top margin to avoid going over the toggle (the "[+]").
-assert-css: (".docblock > .information > .compile_fail", { "margin-top": "16px" })
+assert-css: (".docblock > .example-wrap > .information > .compile_fail", { "margin-top": "16px" })
 // Checks that the other codeblocks don't have this top margin.
-assert-css: ("ol > li > .information > .compile_fail", { "margin-top": "0px" })
-assert-css: ("ol > li > .information > .ignore", { "margin-top": "0px" })
-assert-css: (".docblock > .information > .ignore", { "margin-top": "0px" })
+assert-css: ("ol > li > .example-wrap > .information > .compile_fail", { "margin-top": "0px" })
+assert-css: ("ol > li > .example-wrap > .information > .ignore", { "margin-top": "0px" })
+assert-css: (".docblock > .example-wrap > .information > .ignore", { "margin-top": "0px" })
index 200569a28d4a43e2ad466cb0399104d134cf9e76..8d399a9a589767f21fb112d7844f11647d0ce3af 100644 (file)
@@ -1,9 +1,9 @@
 // This test ensures that items and documentation code blocks are wrapped in <pre><code>
 goto: file://|DOC_PATH|/test_docs/fn.foo.html
 size: (1080, 600)
-// There should be three doc codeblocks
+// There should be four doc codeblocks.
 // Check that their content is inside <pre><code>
-assert-count: (".example-wrap pre > code", 3)
+assert-count: (".example-wrap pre > code", 4)
 // Check that function signature is inside <pre><code>
 assert: "pre.rust.fn > code"
 
diff --git a/src/test/rustdoc-gui/codeblock-tooltip.goml b/src/test/rustdoc-gui/codeblock-tooltip.goml
new file mode 100644 (file)
index 0000000..4e85c33
--- /dev/null
@@ -0,0 +1,96 @@
+// Checking the colors of the codeblocks tooltips.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+show-text: true
+
+// Dark theme.
+local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
+reload:
+
+// compile_fail block
+assert-css: (".docblock .information .compile_fail", {"color": "rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+
+move-cursor-to: ".docblock .information .compile_fail"
+
+assert-css: (".docblock .information .compile_fail", {"color": "rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
+
+// should_panic block
+assert-css: (".docblock .information .should_panic", {"color": "rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+
+move-cursor-to: ".docblock .information .should_panic"
+
+assert-css: (".docblock .information .should_panic", {"color": "rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
+
+// ignore block
+assert-css: (".docblock .information .ignore", {"color": "rgba(255, 142, 0, 0.6)"})
+assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
+
+move-cursor-to: ".docblock .information .ignore"
+
+assert-css: (".docblock .information .ignore", {"color": "rgb(255, 142, 0)"})
+assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
+
+
+// Light theme.
+local-storage: {"rustdoc-theme": "light"}
+reload:
+
+assert-css: (".docblock .information .compile_fail", {"color": "rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+
+move-cursor-to: ".docblock .information .compile_fail"
+
+assert-css: (".docblock .information .compile_fail", {"color": "rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
+
+// should_panic block
+assert-css: (".docblock .information .should_panic", {"color": "rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+
+move-cursor-to: ".docblock .information .should_panic"
+
+assert-css: (".docblock .information .should_panic", {"color": "rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
+
+// ignore block
+assert-css: (".docblock .information .ignore", {"color": "rgba(255, 142, 0, 0.6)"})
+assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
+
+move-cursor-to: ".docblock .information .ignore"
+
+assert-css: (".docblock .information .ignore", {"color": "rgb(255, 142, 0)"})
+assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
+
+
+// Ayu theme.
+local-storage: {"rustdoc-theme": "ayu"}
+reload:
+
+assert-css: (".docblock .information .compile_fail", {"color": "rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+
+move-cursor-to: ".docblock .information .compile_fail"
+
+assert-css: (".docblock .information .compile_fail", {"color": "rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
+
+// should_panic block
+assert-css: (".docblock .information .should_panic", {"color": "rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+
+move-cursor-to: ".docblock .information .should_panic"
+
+assert-css: (".docblock .information .should_panic", {"color": "rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
+
+// ignore block
+assert-css: (".docblock .information .ignore", {"color": "rgba(255, 142, 0, 0.6)"})
+assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
+
+move-cursor-to: ".docblock .information .ignore"
+
+assert-css: (".docblock .information .ignore", {"color": "rgb(255, 142, 0)"})
+assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
index 7ef85a4c44565d8b6fa1adcf7934533368fbf630..5be1aff8d3bce7bbf2e08f128a95ae7edfdaee32 100644 (file)
@@ -2,7 +2,7 @@
 // have overflow and max-width CSS rules set because they create a bug in firefox on
 // mac. For more information: https://github.com/rust-lang/rust/issues/89185
 goto: file://|DOC_PATH|/test_docs/fn.foo.html
-assert-css: (".docblock > .information", {
+assert-css: (".docblock > .example-wrap > .information", {
     "overflow-x": "visible",
     "max-width": "none"
 }, ALL)
index db4907924faf351827c37824d805c92a93d20649..54482005fa601646de32571aca0a537d49b71814 100644 (file)
@@ -7,11 +7,11 @@ press-key: 'Enter'
 wait-for: "#crate-search"
 // The width is returned by "getComputedStyle" which returns the exact number instead of the
 // CSS rule which is "50%"...
-assert-css: (".search-results div.desc", {"width": "295px"})
+assert-css: (".search-results div.desc", {"width": "293px"})
 size: (600, 100)
 // As counter-intuitive as it may seem, in this width, the width is "100%", which is why
 // when computed it's larger.
-assert-css: (".search-results div.desc", {"width": "570px"})
+assert-css: (".search-results div.desc", {"width": "566px"})
 
 // Check that the crate filter `<select>` is correctly handled when it goes to next line.
 // To do so we need to update the length of one of its `<option>`.
index a02d5934cc2457e2a8a6198ceac300c722b0f0e4..4eedf7f15c3d4f8df273f9a726d533d1cfa178aa 100644 (file)
 /// Let's say I'm just some text will ya?
 /// ```
 ///
+/// A failing to run one:
+///
+/// ```should_panic
+/// panic!("tadam");
+/// ```
+///
 /// An inlined `code`!
 pub fn foo() {}
 
index 2eb413fb40203092f8d9c42d7a37bbbfa798a9d6..6d7f6bb969fb1b9d0b68e241a8490d8ce1b84576 100644 (file)
@@ -3,25 +3,35 @@
 pub struct Simple;
 
 impl Simple {
-    // @has "$.index[*][?(@.name=='CONSTANT')].kind" \"assoc_const\"
+    // @is "$.index[*][?(@.name=='CONSTANT')].kind" \"assoc_const\"
     pub const CONSTANT: usize = 0;
 }
 
 pub trait EasyToImpl {
-    // @has "$.index[*][?(@.name=='ToDeclare')].kind" \"assoc_type\"
-    // @has "$.index[*][?(@.name=='ToDeclare')].inner.default" null
+    // @is "$.index[*][?(@.docs=='ToDeclare trait')].kind" \"assoc_type\"
+    // @is "$.index[*][?(@.docs=='ToDeclare trait')].inner.default" null
+    // @is "$.index[*][?(@.docs=='ToDeclare trait')].inner.bounds" []
+    /// ToDeclare trait
     type ToDeclare;
-    // @has "$.index[*][?(@.name=='AN_ATTRIBUTE')].kind" \"assoc_const\"
-    // @has "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.default" null
+    // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].kind" \"assoc_const\"
+    // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.default" null
+    // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.type.kind" '"primitive"'
+    // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.type.inner" '"usize"'
+    /// AN_ATTRIBUTE trait
     const AN_ATTRIBUTE: usize;
 }
 
 impl EasyToImpl for Simple {
-    // @has "$.index[*][?(@.name=='ToDeclare')].inner.default.kind" \"primitive\"
-    // @has "$.index[*][?(@.name=='ToDeclare')].inner.default.inner" \"usize\"
+    // @is "$.index[*][?(@.docs=='ToDeclare impl')].kind" '"assoc_type"'
+    // @is "$.index[*][?(@.docs=='ToDeclare impl')].inner.default.kind" \"primitive\"
+    // @is "$.index[*][?(@.docs=='ToDeclare impl')].inner.default.inner" \"usize\"
+    /// ToDeclare impl
     type ToDeclare = usize;
-    // @has "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.type.kind" \"primitive\"
-    // @has "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.type.inner" \"usize\"
-    // @has "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.default" \"12\"
+
+    // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].kind" '"assoc_const"'
+    // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.type.kind" \"primitive\"
+    // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.type.inner" \"usize\"
+    // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.default" \"12\"
+    /// AN_ATTRIBUTE impl
     const AN_ATTRIBUTE: usize = 12;
 }
index 704ec35d2f0ba60186feb0b0818f866d6e1100a1..23b854d8d1721a1c05db3bcd017fe442a757c475 100644 (file)
@@ -1,9 +1,9 @@
-// @has "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\"
+// @is "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\"
 pub enum EnumStruct {
-    // @has "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\"
-    // @has "$.index[*][?(@.name=='x')].kind" \"struct_field\"
-    // @has "$.index[*][?(@.name=='y')].kind" \"struct_field\"
+    // @is "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\"
+    // @is "$.index[*][?(@.name=='x')].kind" \"struct_field\"
+    // @is "$.index[*][?(@.name=='y')].kind" \"struct_field\"
     VariantS {
         x: u32,
         y: String,
index 71ddd73ec76a4eddd8e08da355695d461fe9edbc..b71ec47a804ad961c1da11f06f86a6b71497c6fc 100644 (file)
@@ -1,8 +1,8 @@
-// @has "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\"
+// @is "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\"
 pub enum EnumTupleStruct {
-    // @has "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\"
-    // @has "$.index[*][?(@.name=='0')].kind" \"struct_field\"
-    // @has "$.index[*][?(@.name=='1')].kind" \"struct_field\"
+    // @is "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\"
+    // @is "$.index[*][?(@.name=='0')].kind" \"struct_field\"
+    // @is "$.index[*][?(@.name=='1')].kind" \"struct_field\"
     VariantA(u32, String),
 }
index e47c8c25513f6087cee6d706fc45014a2cb4cc50..7b70ff1df6b092b8859d1af5d017603302478c86 100644 (file)
@@ -9,16 +9,16 @@ pub trait Wham {}
 // @is    "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.where_predicates" []
 // @count "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[*]" 1
 // @is    "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].name" '"T"'
-// @has   "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" false
-// @has   "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id
+// @is    "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" false
+// @is    "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id
 // @is    "$.index[*][?(@.name=='one_generic_param_fn')].inner.decl.inputs" '[["w", {"inner": "T", "kind": "generic"}]]'
 pub fn one_generic_param_fn<T: Wham>(w: T) {}
 
 // @is    "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.where_predicates" []
 // @count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[*]" 1
 // @is    "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].name" '"impl Wham"'
-// @has   "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" true
-// @has   "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id
+// @is    "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" true
+// @is    "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id
 // @count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[*]" 1
 // @is    "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][0]" '"w"'
 // @is    "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][1].kind" '"impl_trait"'
index a34046ac12fb5356190f444de100ca99278133a0..856f7c7015b3e3025fb9c2faa709ac774e13c44b 100644 (file)
@@ -16,9 +16,7 @@ pub fn doit() {}
 // @set import = "$.index[*][?(@.kind=='import')].id"
 pub use bar::Baz;
 
-// FIXME(adotinthevoid): Use hasexact once #99474 lands
-
-// @has "$.index[*][?(@.kind=='module')].inner.items[*]" $import
-// @is  "$.index[*][?(@.kind=='import')].inner.id" $baz
-// @has "$.index[*][?(@.kind=='struct')].inner.impls[*]" $impl
-// @has "$.index[*][?(@.kind=='impl')].inner.items[*]" $doit
+// @is "$.index[*][?(@.kind=='module')].inner.items[*]" $import
+// @is "$.index[*][?(@.kind=='import')].inner.id" $baz
+// @is "$.index[*][?(@.kind=='struct')].inner.impls[*]" $impl
+// @is "$.index[*][?(@.kind=='impl')].inner.items[*]" $doit
diff --git a/src/test/rustdoc-json/intra-doc-links/non_page.rs b/src/test/rustdoc-json/intra-doc-links/non_page.rs
new file mode 100644 (file)
index 0000000..73c5334
--- /dev/null
@@ -0,0 +1,34 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/101531>,
+// where links where to the item who's HTML page had the item linked to.
+
+//! [`Struct::struct_field`]
+//! [`Enum::Variant`]
+//! [`Trait::AssocType`]
+//! [`Trait::ASSOC_CONST`]
+//! [`Trait::method`]
+
+// @set struct_field = "$.index[*][?(@.name=='struct_field')].id"
+// @set Variant = "$.index[*][?(@.name=='Variant')].id"
+// @set AssocType = "$.index[*][?(@.name=='AssocType')].id"
+// @set ASSOC_CONST = "$.index[*][?(@.name=='ASSOC_CONST')].id"
+// @set method = "$.index[*][?(@.name=='method')].id"
+
+// @is "$.index[*][?(@.name=='non_page')].links['`Struct::struct_field`']" $struct_field
+// @is "$.index[*][?(@.name=='non_page')].links['`Enum::Variant`']" $Variant
+// @is "$.index[*][?(@.name=='non_page')].links['`Trait::AssocType`']" $AssocType
+// @is "$.index[*][?(@.name=='non_page')].links['`Trait::ASSOC_CONST`']" $ASSOC_CONST
+// @is "$.index[*][?(@.name=='non_page')].links['`Trait::method`']" $method
+
+pub struct Struct {
+    pub struct_field: i32,
+}
+
+pub enum Enum {
+    Variant(),
+}
+
+pub trait Trait {
+    const ASSOC_CONST: i32;
+    type AssocType;
+    fn method();
+}
diff --git a/src/test/rustdoc-json/intra-doc-links/user_written.rs b/src/test/rustdoc-json/intra-doc-links/user_written.rs
new file mode 100644 (file)
index 0000000..6871dfe
--- /dev/null
@@ -0,0 +1,8 @@
+//! For motivation, see [the reasons](foo#reasons)
+
+/// # Reasons
+/// To test rustdoc json
+pub fn foo() {}
+
+// @set foo = "$.index[*][?(@.name=='foo')].id"
+// @is "$.index[*][?(@.name=='user_written')].links['foo#reasons']" $foo
index 73ec9392ce94bf1f86681168802594ccf0fc8e2e..ee2d2efa960e8be06730af0da18b58befb87c9ee 100644 (file)
@@ -17,7 +17,7 @@ pub mod l1 {
     pub mod l3 {
 
         // @is "$.index[*][?(@.name=='L4')].kind" \"struct\"
-        // @is "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\"
+        // @is "$.index[*][?(@.name=='L4')].inner.kind" \"unit\"
         // @set l4_id = "$.index[*][?(@.name=='L4')].id"
         // @ismany "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id
         pub struct L4;
index 491a7b1add4839e4abe6a9689d83b5ea72f02e67..8024044bc05ab3993b836da2045dce5876401734 100644 (file)
@@ -1,22 +1,22 @@
 #![feature(never_type)]
 
-// @has "$.index[*][?(@.name=='PrimNever')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='PrimNever')].inner.type.kind" \"primitive\"
-// @has "$.index[*][?(@.name=='PrimNever')].inner.type.inner" \"never\"
+// @is "$.index[*][?(@.name=='PrimNever')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='PrimNever')].inner.type.kind" \"primitive\"
+// @is "$.index[*][?(@.name=='PrimNever')].inner.type.inner" \"never\"
 pub type PrimNever = !;
 
-// @has "$.index[*][?(@.name=='PrimStr')].inner.type.kind" \"primitive\"
-// @has "$.index[*][?(@.name=='PrimStr')].inner.type.inner" \"str\"
+// @is "$.index[*][?(@.name=='PrimStr')].inner.type.kind" \"primitive\"
+// @is "$.index[*][?(@.name=='PrimStr')].inner.type.inner" \"str\"
 pub type PrimStr = str;
 
-// @has "$.index[*][?(@.name=='PrimBool')].inner.type.kind" \"primitive\"
-// @has "$.index[*][?(@.name=='PrimBool')].inner.type.inner" \"bool\"
+// @is "$.index[*][?(@.name=='PrimBool')].inner.type.kind" \"primitive\"
+// @is "$.index[*][?(@.name=='PrimBool')].inner.type.inner" \"bool\"
 pub type PrimBool = bool;
 
-// @has "$.index[*][?(@.name=='PrimChar')].inner.type.kind" \"primitive\"
-// @has "$.index[*][?(@.name=='PrimChar')].inner.type.inner" \"char\"
+// @is "$.index[*][?(@.name=='PrimChar')].inner.type.kind" \"primitive\"
+// @is "$.index[*][?(@.name=='PrimChar')].inner.type.inner" \"char\"
 pub type PrimChar = char;
 
-// @has "$.index[*][?(@.name=='PrimU8')].inner.type.kind" \"primitive\"
-// @has "$.index[*][?(@.name=='PrimU8')].inner.type.inner" \"u8\"
+// @is "$.index[*][?(@.name=='PrimU8')].inner.type.kind" \"primitive\"
+// @is "$.index[*][?(@.name=='PrimU8')].inner.type.inner" \"u8\"
 pub type PrimU8 = u8;
diff --git a/src/test/rustdoc-json/structs/plain_all_pub.rs b/src/test/rustdoc-json/structs/plain_all_pub.rs
new file mode 100644 (file)
index 0000000..b86ab93
--- /dev/null
@@ -0,0 +1,11 @@
+pub struct Demo {
+    pub x: i32,
+    pub y: i32,
+}
+
+// @set x = "$.index[*][?(@.name=='x')].id"
+// @set y = "$.index[*][?(@.name=='y')].id"
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[1]" $y
+// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 2
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" false
diff --git a/src/test/rustdoc-json/structs/plain_doc_hidden.rs b/src/test/rustdoc-json/structs/plain_doc_hidden.rs
new file mode 100644 (file)
index 0000000..7800b55
--- /dev/null
@@ -0,0 +1,11 @@
+pub struct Demo {
+    pub x: i32,
+    #[doc(hidden)]
+    pub y: i32,
+}
+
+// @set x = "$.index[*][?(@.name=='x')].id"
+// @!has "$.index[*][?(@.name=='y')].id"
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x
+// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 1
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" true
index 2ad9e86096c36b273c179836e81477336bb88605..1d01b8bc14a81819381a00d1a37346a4323246cb 100644 (file)
@@ -1,6 +1,5 @@
-// @has "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\"
-// @has "$.index[*][?(@.name=='PlainEmpty')].inner.struct_type" \"plain\"
-// @has "$.index[*][?(@.name=='PlainEmpty')].inner.fields_stripped" false
-// @has "$.index[*][?(@.name=='PlainEmpty')].inner.fields" []
+// @is "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\"
+// @is "$.index[*][?(@.name=='PlainEmpty')].inner.kind.plain.fields_stripped" false
+// @is "$.index[*][?(@.name=='PlainEmpty')].inner.kind.plain.fields" []
 pub struct PlainEmpty {}
diff --git a/src/test/rustdoc-json/structs/plain_pub_priv.rs b/src/test/rustdoc-json/structs/plain_pub_priv.rs
new file mode 100644 (file)
index 0000000..9b77122
--- /dev/null
@@ -0,0 +1,9 @@
+pub struct Demo {
+    pub x: i32,
+    y: i32,
+}
+
+// @set x = "$.index[*][?(@.name=='x')].id"
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x
+// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 1
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" true
index 91fac359422e91c4314aa162664a57a79e411105..6bdb753ee0136c7541a4b7454d9dcb60460f4fce 100644 (file)
@@ -1,5 +1,4 @@
-// @has "$.index[*][?(@.name=='Tuple')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='Tuple')].kind" \"struct\"
-// @has "$.index[*][?(@.name=='Tuple')].inner.struct_type" \"tuple\"
-// @has "$.index[*][?(@.name=='Tuple')].inner.fields_stripped" true
+// @is "$.index[*][?(@.name=='Tuple')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='Tuple')].kind" \"struct\"
+// @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" '[null, null]'
 pub struct Tuple(u32, String);
diff --git a/src/test/rustdoc-json/structs/tuple_empty.rs b/src/test/rustdoc-json/structs/tuple_empty.rs
new file mode 100644 (file)
index 0000000..0ad6a89
--- /dev/null
@@ -0,0 +1,2 @@
+// @is "$.index[*][?(@.name=='TupleUnit')].inner.kind.tuple" []
+pub struct TupleUnit();
diff --git a/src/test/rustdoc-json/structs/tuple_pub_priv.rs b/src/test/rustdoc-json/structs/tuple_pub_priv.rs
new file mode 100644 (file)
index 0000000..9d5a1d1
--- /dev/null
@@ -0,0 +1,13 @@
+pub struct Demo(
+    i32,
+    /// field
+    pub i32,
+    #[doc(hidden)] i32,
+);
+
+// @set field = "$.index[*][?(@.docs=='field')].id"
+
+// @is    "$.index[*][?(@.name=='Demo')].inner.kind.tuple[0]" null
+// @is    "$.index[*][?(@.name=='Demo')].inner.kind.tuple[1]" $field
+// @is    "$.index[*][?(@.name=='Demo')].inner.kind.tuple[2]" null
+// @count "$.index[*][?(@.name=='Demo')].inner.kind.tuple[*]" 3
index 85a515b5e78ac427c4788d2bf1c97b7b483eba52..265709717212f492e1d720cd3d14eb1264678267 100644 (file)
@@ -1,5 +1,4 @@
-// @has "$.index[*][?(@.name=='Unit')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='Unit')].kind" \"struct\"
-// @has "$.index[*][?(@.name=='Unit')].inner.struct_type" \"unit\"
-// @has "$.index[*][?(@.name=='Unit')].inner.fields" []
+// @is "$.index[*][?(@.name=='Unit')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='Unit')].kind" \"struct\"
+// @is "$.index[*][?(@.name=='Unit')].inner.kind" \"unit\"
 pub struct Unit;
index b0ad1883f8a2f6eba718354746596cd4269ff820..00474800a0e54c76328169e5b88cf9bc2d11cafc 100644 (file)
@@ -1,13 +1,13 @@
 use std::collections::HashMap;
 
-// @has "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\"
-// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\"
-// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type"
-// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\"
-// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type"
-// @has "$.index[*][?(@.name=='WithGenerics')].inner.struct_type" \"plain\"
-// @has "$.index[*][?(@.name=='WithGenerics')].inner.fields_stripped" true
+// @is "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\"
+// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\"
+// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type.bounds" []
+// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\"
+// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type.bounds" []
+// @is "$.index[*][?(@.name=='WithGenerics')].inner.kind.plain.fields_stripped" true
+// @is "$.index[*][?(@.name=='WithGenerics')].inner.kind.plain.fields" []
 pub struct WithGenerics<T, U> {
     stuff: Vec<T>,
     things: HashMap<U, U>,
index b74050dde78696c55d7342038a83bb5df02270fb..9c5a37f3957c03ab2f68eca8b02cbcec0b5c5d8a 100644 (file)
@@ -1,9 +1,9 @@
-// @has "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\"
-// @has "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\"
-// @has "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" []
-// @has "$.index[*][?(@.name=='WithPrimitives')].inner.struct_type" \"plain\"
-// @has "$.index[*][?(@.name=='WithPrimitives')].inner.fields_stripped" true
+// @is "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\"
+// @is "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\"
+// @is "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" []
+// @is "$.index[*][?(@.name=='WithPrimitives')].inner.kind.plain.fields_stripped" true
+// @is "$.index[*][?(@.name=='WithPrimitives')].inner.kind.plain.fields" []
 pub struct WithPrimitives<'a> {
     num: u32,
     s: &'a str,
index 4565aba65879d7e56c018b6fc71eb1e037a7f9ef..a57cb97d4a6a2175dffb3c6afba764eee21ec27a 100644 (file)
@@ -1,21 +1,21 @@
 // @has "$.index[*][?(@.name=='Foo')]"
 pub trait Foo {
-    // @has "$.index[*][?(@.name=='no_self')].inner.has_body" false
+    // @is "$.index[*][?(@.name=='no_self')].inner.has_body" false
     fn no_self();
-    // @has "$.index[*][?(@.name=='move_self')].inner.has_body" false
+    // @is "$.index[*][?(@.name=='move_self')].inner.has_body" false
     fn move_self(self);
-    // @has "$.index[*][?(@.name=='ref_self')].inner.has_body" false
+    // @is "$.index[*][?(@.name=='ref_self')].inner.has_body" false
     fn ref_self(&self);
 
-    // @has "$.index[*][?(@.name=='no_self_def')].inner.has_body" true
+    // @is "$.index[*][?(@.name=='no_self_def')].inner.has_body" true
     fn no_self_def() {}
-    // @has "$.index[*][?(@.name=='move_self_def')].inner.has_body" true
+    // @is "$.index[*][?(@.name=='move_self_def')].inner.has_body" true
     fn move_self_def(self) {}
-    // @has "$.index[*][?(@.name=='ref_self_def')].inner.has_body" true
+    // @is "$.index[*][?(@.name=='ref_self_def')].inner.has_body" true
     fn ref_self_def(&self) {}
 }
 
 pub trait Bar: Clone {
-    // @has "$.index[*][?(@.name=='method')].inner.has_body" false
+    // @is "$.index[*][?(@.name=='method')].inner.has_body" false
     fn method(&self, param: usize);
 }
index 03c6481f80ea29bcab2ab13b5c4d259094f2206f..eaf249252e33a1eab4745016a43f45db1b846abf 100644 (file)
@@ -5,9 +5,7 @@
 // @set sync_int_gen = "$.index[*][?(@.name=='SyncIntGen')].id"
 // @set ref_fn       = "$.index[*][?(@.name=='RefFn')].id"
 // @set weird_order  = "$.index[*][?(@.name=='WeirdOrder')].id"
-// @has "$.index[*][?(@.name=='dyn')].inner.items[*]" $sync_int_gen
-// @has "$.index[*][?(@.name=='dyn')].inner.items[*]" $ref_fn
-// @has "$.index[*][?(@.name=='dyn')].inner.items[*]" $weird_order
+// @ismany "$.index[*][?(@.name=='dyn')].inner.items[*]" $sync_int_gen $ref_fn $weird_order
 
 // @is    "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\"
 // @is    "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}'
index 8dfbbfc1baed408014329579cb1108b7dacfa711..4454a69ecd1bf35a3f4e5ea0cfc71172a1ede9d8 100644 (file)
@@ -1,14 +1,14 @@
 #![no_std]
 
-// @has "$.index[*][?(@.name=='Ux')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='Ux')].kind" \"union\"
+// @is "$.index[*][?(@.name=='Ux')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='Ux')].kind" \"union\"
 pub union Ux {
     a: u32,
     b: u64
 }
 
-// @has "$.index[*][?(@.name=='Num')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='Num')].kind" \"trait\"
+// @is "$.index[*][?(@.name=='Num')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='Num')].kind" \"trait\"
 pub trait Num {}
 
 // @count "$.index[*][?(@.name=='Ux')].inner.impls" 1
diff --git a/src/test/rustdoc/glob-shadowing-const.rs b/src/test/rustdoc/glob-shadowing-const.rs
new file mode 100644 (file)
index 0000000..5b786cf
--- /dev/null
@@ -0,0 +1,20 @@
+// https://github.com/rust-lang/rust/pull/83872#issuecomment-820101008
+#![crate_name="foo"]
+
+mod sub4 {
+    /// 0
+    pub const X: usize = 0;
+    pub mod inner {
+        pub use super::*;
+        /// 1
+        pub const X: usize = 1;
+    }
+}
+
+#[doc(inline)]
+pub use sub4::inner::*;
+
+// @has 'foo/index.html'
+// @has - '//div[@class="item-right docblock-short"]' '1'
+// @!has - '//div[@class="item-right docblock-short"]' '0'
+fn main() { assert_eq!(X, 1); }
diff --git a/src/test/rustdoc/glob-shadowing.rs b/src/test/rustdoc/glob-shadowing.rs
new file mode 100644 (file)
index 0000000..66a31c4
--- /dev/null
@@ -0,0 +1,86 @@
+// @has 'glob_shadowing/index.html'
+// @count - '//div[@class="item-left module-item"]' 6
+// @!has - '//div[@class="item-right docblock-short"]' 'sub1::describe'
+// @has - '//div[@class="item-right docblock-short"]' 'sub2::describe'
+
+// @!has - '//div[@class="item-right docblock-short"]' 'sub1::describe2'
+
+// @!has - '//div[@class="item-right docblock-short"]' 'sub1::prelude'
+// @has - '//div[@class="item-right docblock-short"]' 'mod::prelude'
+
+// @has - '//div[@class="item-right docblock-short"]' 'sub1::Foo (struct)'
+// @has - '//div[@class="item-right docblock-short"]' 'mod::Foo (function)'
+
+// @has - '//div[@class="item-right docblock-short"]' 'sub4::inner::X'
+
+// @has 'glob_shadowing/fn.describe.html'
+// @has - '//div[@class="docblock"]' 'sub2::describe'
+
+mod sub1 {
+    // this should be shadowed by sub2::describe
+    /// sub1::describe
+    pub fn describe() -> &'static str {
+        "sub1::describe"
+    }
+
+    // this should be shadowed by mod::prelude
+    /// sub1::prelude
+    pub mod prelude {
+    }
+
+    // this should *not* be shadowed, because sub1::Foo and mod::Foo are in different namespaces
+    /// sub1::Foo (struct)
+    pub struct Foo;
+
+    // this should be shadowed,
+    // because both sub1::describe2 and sub3::describe2 are from glob reexport
+    /// sub1::describe2
+    pub fn describe2() -> &'static str {
+        "sub1::describe2"
+    }
+}
+
+mod sub2 {
+    /// sub2::describe
+    pub fn describe() -> &'static str {
+        "sub2::describe"
+    }
+}
+
+mod sub3 {
+    // this should be shadowed
+    // because both sub1::describe2 and sub3::describe2 are from glob reexport
+    /// sub3::describe2
+    pub fn describe2() -> &'static str {
+        "sub3::describe2"
+    }
+}
+
+mod sub4 {
+    // this should be shadowed by sub4::inner::X
+    /// sub4::X
+    pub const X: usize = 0;
+    pub mod inner {
+        pub use super::*;
+        /// sub4::inner::X
+        pub const X: usize = 1;
+    }
+}
+
+/// mod::Foo (function)
+pub fn Foo() {}
+
+#[doc(inline)]
+pub use sub2::describe;
+
+#[doc(inline)]
+pub use sub1::*;
+
+#[doc(inline)]
+pub use sub3::*;
+
+#[doc(inline)]
+pub use sub4::inner::*;
+
+/// mod::prelude
+pub mod prelude {}
diff --git a/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs b/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs
new file mode 100644 (file)
index 0000000..d3a7a87
--- /dev/null
@@ -0,0 +1,16 @@
+#![crate_name = "foo"]
+
+pub mod sub {
+    pub struct Item;
+
+    pub mod prelude {
+        pub use super::Item;
+    }
+}
+
+#[doc(inline)]
+pub use sub::*;
+
+// @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1
+// @count foo/prelude/index.html '//div[@class="item-row"]' 0
+pub mod prelude {}
diff --git a/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs b/src/test/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs
new file mode 100644 (file)
index 0000000..b836925
--- /dev/null
@@ -0,0 +1,16 @@
+#![crate_name = "foo"]
+
+pub mod sub {
+    pub struct Item;
+
+    pub mod prelude {
+        pub use super::Item;
+    }
+}
+
+// @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1
+// @count foo/prelude/index.html '//div[@class="item-row"]' 0
+pub mod prelude {}
+
+#[doc(inline)]
+pub use sub::*;
index 802b867a301aa5611bcdba471fbad793da7299b3..03ad3ca826146a9b47aeb37e638cbcba272c66b7 100644 (file)
@@ -21,7 +21,7 @@
 #[no_mangle]
 fn __rustc_plugin_registrar(reg: &mut Registry) {
     reg.lint_store.register_lints(&[&MISSING_ALLOWED_ATTR]);
-    reg.lint_store.register_late_pass(|| Box::new(MissingAllowedAttrPass));
+    reg.lint_store.register_late_pass(|_| Box::new(MissingAllowedAttrPass));
 }
 
 declare_lint! {
index bc153faa8925a73d952df3740a1a5a5bf63d1d9a..a3b570ad8c40c5e572ba483eb4963980dfda68af 100644 (file)
@@ -74,7 +74,7 @@ fn __rustc_plugin_registrar(reg: &mut Registry) {
         &CRATE_NOT_GREY,
         &CRATE_NOT_GREEN,
     ]);
-    reg.lint_store.register_late_pass(|| Box::new(PassOkay));
-    reg.lint_store.register_late_pass(|| Box::new(PassRedBlue));
-    reg.lint_store.register_late_pass(|| Box::new(PassGreyGreen));
+    reg.lint_store.register_late_pass(|_| Box::new(PassOkay));
+    reg.lint_store.register_late_pass(|_| Box::new(PassRedBlue));
+    reg.lint_store.register_late_pass(|_| Box::new(PassGreyGreen));
 }
index 29d0abfbe53889e19ff961526ea02e8b6ed20c93..0b1534939b778fdbdd3be1e68b5a4950f9b37d11 100644 (file)
@@ -39,5 +39,5 @@ fn check_crate(&mut self, cx: &LateContext) {
 #[no_mangle]
 fn __rustc_plugin_registrar(reg: &mut Registry) {
     reg.lint_store.register_lints(&[&CRATE_NOT_OKAY]);
-    reg.lint_store.register_late_pass(|| Box::new(Pass));
+    reg.lint_store.register_late_pass(|_| Box::new(Pass));
 }
index 691cfb97d921858e5bec59e96f900620de8fbd08..2d41b5f30e975e2f7c330da40962f54dcd2d8af1 100644 (file)
@@ -36,7 +36,7 @@ fn check_item(&mut self, cx: &LateContext, it: &rustc_hir::Item) {
 #[no_mangle]
 fn __rustc_plugin_registrar(reg: &mut Registry) {
     reg.lint_store.register_lints(&[&TEST_LINT, &PLEASE_LINT]);
-    reg.lint_store.register_late_pass(|| Box::new(Pass));
+    reg.lint_store.register_late_pass(|_| Box::new(Pass));
     reg.lint_store.register_group(
         true,
         "lint_me",
index bae3ab74af676db8da8f3786edeff26580e41a3a..867c18a7d5e6b2acee746b91e0740e30a7e1bd68 100644 (file)
@@ -5,10 +5,22 @@ fn main() {
     const Foo: [i32; 3] = [1, 2, 3];
     //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
     //~| ERROR using `_` for array lengths is unstable
+    const REF_FOO: &[u8; 1] = &[1];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
     let foo: [i32; 3] = [1, 2, 3];
     //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
     //~| ERROR using `_` for array lengths is unstable
     let bar: [i32; 3] = [0; 3];
     //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
     //~| ERROR using `_` for array lengths is unstable
+    let ref_foo: &[i32; 3] = &[1, 2, 3];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
+    let ref_bar: &[i32; 3] = &[0; 3];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
+    let multiple_ref_foo: &&[i32; 3] = &&[1, 2, 3];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
 }
index b0867f4e39676f033b83cf0f984629c5fe3ea72b..f66b3d4a899912376be45458fcb781a3c292bf55 100644 (file)
@@ -5,10 +5,22 @@ fn main() {
     const Foo: [i32; _] = [1, 2, 3];
     //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
     //~| ERROR using `_` for array lengths is unstable
+    const REF_FOO: &[u8; _] = &[1];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
     let foo: [i32; _] = [1, 2, 3];
     //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
     //~| ERROR using `_` for array lengths is unstable
     let bar: [i32; _] = [0; 3];
     //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
     //~| ERROR using `_` for array lengths is unstable
+    let ref_foo: &[i32; _] = &[1, 2, 3];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
+    let ref_bar: &[i32; _] = &[0; 3];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
+    let multiple_ref_foo: &&[i32; _] = &&[1, 2, 3];
+    //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment
+    //~| ERROR using `_` for array lengths is unstable
 }
index 9000f71602850453b4c8c2c50a0b019ac990092c..16c90a04784d0e674565e6ef86f10dbc50b9211c 100644 (file)
@@ -1,21 +1,45 @@
 error: in expressions, `_` can only be used on the left-hand side of an assignment
-  --> $DIR/suggest-array-length.rs:8:20
+  --> $DIR/suggest-array-length.rs:11:20
    |
 LL |     let foo: [i32; _] = [1, 2, 3];
    |                    ^ `_` not allowed here
 
 error: in expressions, `_` can only be used on the left-hand side of an assignment
-  --> $DIR/suggest-array-length.rs:11:20
+  --> $DIR/suggest-array-length.rs:14:20
    |
 LL |     let bar: [i32; _] = [0; 3];
    |                    ^ `_` not allowed here
 
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+  --> $DIR/suggest-array-length.rs:17:25
+   |
+LL |     let ref_foo: &[i32; _] = &[1, 2, 3];
+   |                         ^ `_` not allowed here
+
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+  --> $DIR/suggest-array-length.rs:20:25
+   |
+LL |     let ref_bar: &[i32; _] = &[0; 3];
+   |                         ^ `_` not allowed here
+
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+  --> $DIR/suggest-array-length.rs:23:35
+   |
+LL |     let multiple_ref_foo: &&[i32; _] = &&[1, 2, 3];
+   |                                   ^ `_` not allowed here
+
 error: in expressions, `_` can only be used on the left-hand side of an assignment
   --> $DIR/suggest-array-length.rs:5:22
    |
 LL |     const Foo: [i32; _] = [1, 2, 3];
    |                      ^ `_` not allowed here
 
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+  --> $DIR/suggest-array-length.rs:8:26
+   |
+LL |     const REF_FOO: &[u8; _] = &[1];
+   |                          ^ `_` not allowed here
+
 error[E0658]: using `_` for array lengths is unstable
   --> $DIR/suggest-array-length.rs:5:22
    |
@@ -26,7 +50,16 @@ LL |     const Foo: [i32; _] = [1, 2, 3];
    = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
 
 error[E0658]: using `_` for array lengths is unstable
-  --> $DIR/suggest-array-length.rs:8:20
+  --> $DIR/suggest-array-length.rs:8:26
+   |
+LL |     const REF_FOO: &[u8; _] = &[1];
+   |                          ^ help: consider specifying the array length: `1`
+   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error[E0658]: using `_` for array lengths is unstable
+  --> $DIR/suggest-array-length.rs:11:20
    |
 LL |     let foo: [i32; _] = [1, 2, 3];
    |                    ^ help: consider specifying the array length: `3`
@@ -35,7 +68,7 @@ LL |     let foo: [i32; _] = [1, 2, 3];
    = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
 
 error[E0658]: using `_` for array lengths is unstable
-  --> $DIR/suggest-array-length.rs:11:20
+  --> $DIR/suggest-array-length.rs:14:20
    |
 LL |     let bar: [i32; _] = [0; 3];
    |                    ^ help: consider specifying the array length: `3`
@@ -43,6 +76,33 @@ LL |     let bar: [i32; _] = [0; 3];
    = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
    = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
 
-error: aborting due to 6 previous errors
+error[E0658]: using `_` for array lengths is unstable
+  --> $DIR/suggest-array-length.rs:17:25
+   |
+LL |     let ref_foo: &[i32; _] = &[1, 2, 3];
+   |                         ^ help: consider specifying the array length: `3`
+   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error[E0658]: using `_` for array lengths is unstable
+  --> $DIR/suggest-array-length.rs:20:25
+   |
+LL |     let ref_bar: &[i32; _] = &[0; 3];
+   |                         ^ help: consider specifying the array length: `3`
+   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error[E0658]: using `_` for array lengths is unstable
+  --> $DIR/suggest-array-length.rs:23:35
+   |
+LL |     let multiple_ref_foo: &&[i32; _] = &&[1, 2, 3];
+   |                                   ^ help: consider specifying the array length: `3`
+   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error: aborting due to 14 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index b320abdc01b721a1cea17ae89b34cf7cfe025430..49292982eec7c99dfdc19dfde108d74a2b21026f 100644 (file)
@@ -5,8 +5,8 @@ LL |         asm!("{}", in(reg) 0u8);
    |               ^^           --- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:50:15
@@ -14,8 +14,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0u16);
    |               ^^           ---- for this argument
    |
-   = help: use the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:52:15
@@ -23,8 +23,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0i32);
    |               ^^           ---- for this argument
    |
-   = help: use the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:54:15
@@ -32,8 +32,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0f32);
    |               ^^           ---- for this argument
    |
-   = help: use the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:57:15
@@ -41,8 +41,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(vreg) 0i16);
    |               ^^            ---- for this argument
    |
-   = help: use the `h` modifier to have the register formatted as `h0`
-   = help: or use the `v` modifier to keep the default formatting of `v0`
+   = help: use `{0:h}` to have the register formatted as `h0`
+   = help: or use `{0:v}` to keep the default formatting of `v0`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:59:15
@@ -50,8 +50,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(vreg) 0f32);
    |               ^^            ---- for this argument
    |
-   = help: use the `s` modifier to have the register formatted as `s0`
-   = help: or use the `v` modifier to keep the default formatting of `v0`
+   = help: use `{0:s}` to have the register formatted as `s0`
+   = help: or use `{0:v}` to keep the default formatting of `v0`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:61:15
@@ -59,8 +59,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(vreg) 0f64);
    |               ^^            ---- for this argument
    |
-   = help: use the `d` modifier to have the register formatted as `d0`
-   = help: or use the `v` modifier to keep the default formatting of `v0`
+   = help: use `{0:d}` to have the register formatted as `d0`
+   = help: or use `{0:v}` to keep the default formatting of `v0`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:63:15
@@ -68,8 +68,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(vreg_low16) 0f64);
    |               ^^                  ---- for this argument
    |
-   = help: use the `d` modifier to have the register formatted as `d0`
-   = help: or use the `v` modifier to keep the default formatting of `v0`
+   = help: use `{0:d}` to have the register formatted as `d0`
+   = help: or use `{0:v}` to keep the default formatting of `v0`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:66:15
@@ -77,8 +77,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{0} {0}", in(reg) 0i16);
    |               ^^^ ^^^           ---- for this argument
    |
-   = help: use the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:68:15
@@ -86,8 +86,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{0} {0:x}", in(reg) 0i16);
    |               ^^^                 ---- for this argument
    |
-   = help: use the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 error: type `i128` cannot be used with this register class
   --> $DIR/type-check-3.rs:73:28
index 7ef93e15f5ba1cbfc31493e5be0acab675062257..5dac693cc2740063d03e182ad3fd4237b0284fe8 100644 (file)
@@ -190,8 +190,8 @@ LL |         asm!("{:foo}", in(reg) foo);
    |               ^^^^^^           --- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 error: aborting due to 21 previous errors; 1 warning emitted
 
index 7ef93e15f5ba1cbfc31493e5be0acab675062257..5dac693cc2740063d03e182ad3fd4237b0284fe8 100644 (file)
@@ -190,8 +190,8 @@ LL |         asm!("{:foo}", in(reg) foo);
    |               ^^^^^^           --- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 error: aborting due to 21 previous errors; 1 warning emitted
 
index 250bc3be42ebb42fed995abba4b73aafb986173d..b29b74bac80b1d075938ab02f2a5636181dc3d74 100644 (file)
@@ -190,8 +190,8 @@ LL |         asm!("{:foo}", in(reg) foo);
    |               ^^^^^^           --- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `e` modifier to have the register formatted as `eax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
+   = help: use `{0:e}` to have the register formatted as `eax`
+   = help: or use `{0:r}` to keep the default formatting of `rax`
 
 error: aborting due to 21 previous errors; 1 warning emitted
 
index 250bc3be42ebb42fed995abba4b73aafb986173d..b29b74bac80b1d075938ab02f2a5636181dc3d74 100644 (file)
@@ -190,8 +190,8 @@ LL |         asm!("{:foo}", in(reg) foo);
    |               ^^^^^^           --- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `e` modifier to have the register formatted as `eax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
+   = help: use `{0:e}` to have the register formatted as `eax`
+   = help: or use `{0:r}` to keep the default formatting of `rax`
 
 error: aborting due to 21 previous errors; 1 warning emitted
 
index b38ea8cc4d8ee7bfe8dbfbd5098af4b035128754..366038fea2340ac5ddb2d6d6db1167c4c299f8c7 100644 (file)
@@ -45,8 +45,8 @@ LL |         asm!("{0} {0}", in(reg) 0i16);
    |               ^^^ ^^^           ---- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `x` modifier to have the register formatted as `ax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
+   = help: use `{0:x}` to have the register formatted as `ax`
+   = help: or use `{0:r}` to keep the default formatting of `rax`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:36:15
@@ -54,8 +54,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{0} {0:x}", in(reg) 0i16);
    |               ^^^                 ---- for this argument
    |
-   = help: use the `x` modifier to have the register formatted as `ax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
+   = help: use `{0:x}` to have the register formatted as `ax`
+   = help: or use `{0:r}` to keep the default formatting of `rax`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:38:15
@@ -63,8 +63,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0i32);
    |               ^^           ---- for this argument
    |
-   = help: use the `e` modifier to have the register formatted as `eax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
+   = help: use `{0:e}` to have the register formatted as `eax`
+   = help: or use `{0:r}` to keep the default formatting of `rax`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:41:15
@@ -72,8 +72,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(ymm_reg) 0i64);
    |               ^^               ---- for this argument
    |
-   = help: use the `x` modifier to have the register formatted as `xmm0`
-   = help: or use the `y` modifier to keep the default formatting of `ymm0`
+   = help: use `{0:x}` to have the register formatted as `xmm0`
+   = help: or use `{0:y}` to keep the default formatting of `ymm0`
 
 error: type `i8` cannot be used with this register class
   --> $DIR/type-check-3.rs:52:28
index 9d18690e96049a189cf6190449d3d1060b762e8e..499bbd6b6fad2e1a6cdcf821cbe26c39a2254487 100644 (file)
@@ -10,6 +10,7 @@ impl T<'_> for S {
 
 fn foo(x: impl Fn(<S as T<'_>>::A) -> <S as T<'_>>::A) {}
 //~^ ERROR binding for associated type `Output` references an anonymous lifetime
-//~^^ NOTE lifetimes appearing in an associated type are not considered constrained
+//~| NOTE lifetimes appearing in an associated or opaque type are not considered constrained
+//~| NOTE consider introducing a named lifetime parameter
 
 fn main() {}
index f14cd81fdfe1f43583bb1b429d07437e93894eff..04f0728f58ea86bb68a6d0df3130080757797c79 100644 (file)
@@ -4,7 +4,8 @@ error[E0582]: binding for associated type `Output` references an anonymous lifet
 LL | fn foo(x: impl Fn(<S as T<'_>>::A) -> <S as T<'_>>::A) {}
    |                                       ^^^^^^^^^^^^^^^
    |
-   = note: lifetimes appearing in an associated type are not considered constrained
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
 
 error: aborting due to previous error
 
index e2062e82725c0507fad934ec9f6720dfab28ea71..0ea685986db4057dcbf376b0913d06428de24a71 100644 (file)
@@ -1,8 +1,11 @@
 // edition:2018
 trait T {
     async fn foo() {} //~ ERROR functions in traits cannot be declared `async`
+    //~^ ERROR mismatched types
     async fn bar(&self) {} //~ ERROR functions in traits cannot be declared `async`
+    //~^ ERROR mismatched types
     async fn baz() { //~ ERROR functions in traits cannot be declared `async`
+        //~^ ERROR mismatched types
         // Nested item must not ICE.
         fn a() {}
     }
index 1eb8969a80d20047db21c886240c0dc11aebc73d..e5c584e31e8158326f67a14d306d75805cfa9d55 100644 (file)
@@ -2,40 +2,89 @@ error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/async-trait-fn.rs:3:5
    |
 LL |     async fn foo() {}
-   |     -----^^^^^^^^^^^^
+   |     -----^^^^^^^^^
    |     |
    |     `async` because of this
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/async-trait-fn.rs:4:5
+  --> $DIR/async-trait-fn.rs:5:5
    |
 LL |     async fn bar(&self) {}
-   |     -----^^^^^^^^^^^^^^^^^
+   |     -----^^^^^^^^^^^^^^
    |     |
    |     `async` because of this
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/async-trait-fn.rs:5:5
+  --> $DIR/async-trait-fn.rs:7:5
+   |
+LL |     async fn baz() {
+   |     -----^^^^^^^^^
+   |     |
+   |     `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
+error[E0308]: mismatched types
+  --> $DIR/async-trait-fn.rs:3:20
+   |
+LL |     async fn foo() {}
+   |                    ^^ expected associated type, found opaque type
+   |
+  ::: $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 associated type `impl Future<Output = ()>` (trait associated opaque type at <$DIR/async-trait-fn.rs:3:20>)
+                  found opaque type `impl Future<Output = ()>` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
+
+error[E0308]: mismatched types
+  --> $DIR/async-trait-fn.rs:5:25
+   |
+LL |     async fn bar(&self) {}
+   |                         ^^ expected associated type, found opaque type
+   |
+  ::: $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 associated type `impl Future<Output = ()>` (trait associated opaque type at <$DIR/async-trait-fn.rs:5:25>)
+                  found opaque type `impl Future<Output = ()>` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
+
+error[E0308]: mismatched types
+  --> $DIR/async-trait-fn.rs:7:20
    |
 LL |       async fn baz() {
-   |       ^----
-   |       |
-   |  _____`async` because of this
-   | |
+   |  ____________________^
+LL | |
 LL | |         // Nested item must not ICE.
 LL | |         fn a() {}
 LL | |     }
-   | |_____^
+   | |_____^ expected associated type, found opaque type
    |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+  ::: $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 associated type `impl Future<Output = ()>` (trait associated opaque type at <$DIR/async-trait-fn.rs:7:20>)
+                  found opaque type `impl Future<Output = ()>` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
 
-error: aborting due to 3 previous errors
+error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0706`.
+Some errors have detailed explanations: E0308, E0706.
+For more information about an error, try `rustc --explain E0308`.
index e5dc9c8a5fee8bee0aaafc2528c9b22e494065e3..22a61dcd25f98835921c47d2aef5a281347f73c9 100644 (file)
@@ -16,7 +16,8 @@ async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015
 
 trait Bar {
     async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015
-                      //~^ ERROR functions in traits cannot be declared `async`
+    //~^ ERROR functions in traits cannot be declared `async`
+    //~| ERROR mismatched types
 }
 
 fn main() {
index 35f9c581c7b21b254a4add1f516668fa17c24229..8c2902d9b00d137ca47e799f5f26f90fc760758e 100644 (file)
@@ -53,7 +53,7 @@ LL |     async fn foo() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:36:9
+  --> $DIR/edition-deny-async-fns-2015.rs:37:9
    |
 LL |         async fn bar() {}
    |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -62,7 +62,7 @@ LL |         async fn bar() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:26:9
+  --> $DIR/edition-deny-async-fns-2015.rs:27:9
    |
 LL |         async fn foo() {}
    |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -71,7 +71,7 @@ LL |         async fn foo() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:31:13
+  --> $DIR/edition-deny-async-fns-2015.rs:32:13
    |
 LL |             async fn bar() {}
    |             ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -83,14 +83,30 @@ error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/edition-deny-async-fns-2015.rs:18:5
    |
 LL |     async fn foo() {}
-   |     -----^^^^^^^^^^^^
+   |     -----^^^^^^^^^
    |     |
    |     `async` because of this
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
-error: aborting due to 10 previous errors
+error[E0308]: mismatched types
+  --> $DIR/edition-deny-async-fns-2015.rs:18:20
+   |
+LL |     async fn foo() {}
+   |                    ^^ expected associated type, found opaque type
+   |
+  ::: $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 associated type `impl Future<Output = ()>` (trait associated opaque type at <$DIR/edition-deny-async-fns-2015.rs:18:20>)
+                  found opaque type `impl Future<Output = ()>` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
+
+error: aborting due to 11 previous errors
 
-Some errors have detailed explanations: E0670, E0706.
-For more information about an error, try `rustc --explain E0670`.
+Some errors have detailed explanations: E0308, E0670, E0706.
+For more information about an error, try `rustc --explain E0308`.
index 29aebb719d66f506e61e68bb13c871be8456263e..1c12f1e4862e8a2b36af6d9006fd7514484cb11c 100644 (file)
@@ -8,6 +8,8 @@ LL |     async fn new() -> [u8; _];
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
 error: in expressions, `_` can only be used on the left-hand side of an assignment
   --> $DIR/issue-95307.rs:7:28
index 1651f70d5cde739dcb4b4d64463fe1625485b1a4..34826d2f4bf7ab2932657a08c53a606ded25d406 100644 (file)
@@ -6,7 +6,7 @@ LL |         x % 2 == 0
    |         |
    |         &&{integer}
    |
-help: `%` can be used on `{integer}`, you can dereference `x`
+help: `%` can be used on `&{integer}` if you dereference the left-hand side
    |
 LL |         *x % 2 == 0
    |         +
index d4f81930843bfa5f52786449030dc0bc6fc2e393..1fd1eb128511bee3f7e2e7e898e19ef69f18f9a1 100644 (file)
@@ -23,7 +23,7 @@ LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) {
    |                                                  - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         a @ [.., _] => (),
-   |         ----------- value moved here
+   |         - value moved here
 ...
 LL |     &x;
    |     ^^ value borrowed here after move
@@ -32,7 +32,7 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:28:5
    |
 LL |         ref mut foo @ [.., _] => Some(foo),
-   |         --------------------- mutable borrow occurs here
+   |         ----------- mutable borrow occurs here
 ...
 LL |     &x;
    |     ^^ immutable borrow occurs here
@@ -44,7 +44,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:50:5
    |
 LL |         [ref foo @ .., ref bar] => Some(foo),
-   |          ------------ immutable borrow occurs here
+   |          ------- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -56,7 +56,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:62:5
    |
 LL |         ref foo @ [.., ref bar] => Some(foo),
-   |         ----------------------- immutable borrow occurs here
+   |         ------- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -71,7 +71,7 @@ LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) {
    |                                       - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         foo @ Some(Test::Foo | Test::Bar) => (),
-   |         ---------------------------------
+   |         ---
    |         |
    |         value moved here
    |         value moved here
@@ -83,7 +83,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:86:5
    |
 LL |         ref foo @ Some(Test::Foo | Test::Bar) => Some(foo),
-   |         ------------------------------------- immutable borrow occurs here
+   |         ------- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -95,7 +95,7 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:98:5
    |
 LL |         ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo),
-   |         ----------------------------------------- mutable borrow occurs here
+   |         ----------- mutable borrow occurs here
 ...
 LL |     &x;
    |     ^^ immutable borrow occurs here
@@ -107,7 +107,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:112:5
    |
 LL |         ref foo @ Some(box ref s) => Some(foo),
-   |         ------------------------- immutable borrow occurs here
+   |         ------- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -122,7 +122,7 @@ LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4])
    |                                                       - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         a @ [.., Some(Test::Foo | Test::Bar)] => (),
-   |         -------------------------------------
+   |         -
    |         |
    |         value moved here
    |         value moved here
@@ -134,7 +134,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:144:5
    |
 LL |         ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a),
-   |         ------------------------------------------------- immutable borrow occurs here
+   |         ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -146,7 +146,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:156:5
    |
 LL |         ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b),
-   |                  ---------- immutable borrow occurs here
+   |                  ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -158,7 +158,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:170:5
    |
 LL |         [_, ref a @ Some(box ref b), ..] => Some(a),
-   |             ----------------------- immutable borrow occurs here
+   |             ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -170,7 +170,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:186:5
    |
 LL |         [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
-   |             ------------------------------------------- immutable borrow occurs here
+   |             ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -182,7 +182,7 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:200:5
    |
 LL |         [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
-   |             ----------------------------------------------- mutable borrow occurs here
+   |             --------- mutable borrow occurs here
 ...
 LL |     &x;
    |     ^^ immutable borrow occurs here
@@ -194,7 +194,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:214:5
    |
 LL |         ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
-   |         ------------------------------------------------------------ immutable borrow occurs here
+   |         ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
index cfcc62de4383b56be7a2b2c62ba9663a37a9763e..2c1b9c10d4660dc0cd71e3931f2224d2dd9592a5 100644 (file)
@@ -200,7 +200,7 @@ LL |         let x = &mut v;
    |                 ------ borrow of `v` occurs here
 LL |         match v {
 LL |             &[x @ ..] => println!("{:?}", x),
-   |               ^^^^^^ use of borrowed `v`
+   |               ^ use of borrowed `v`
 ...
 LL |         drop(x);
    |              - borrow later used here
@@ -212,7 +212,7 @@ LL |         let x = &mut v;
    |                 ------ borrow of `v` occurs here
 ...
 LL |             &[_, x @ ..] => println!("{:?}", x),
-   |                  ^^^^^^ use of borrowed `v`
+   |                  ^ use of borrowed `v`
 ...
 LL |         drop(x);
    |              - borrow later used here
@@ -224,7 +224,7 @@ LL |         let x = &mut v;
    |                 ------ borrow of `v` occurs here
 ...
 LL |             &[x @ .., _] => println!("{:?}", x),
-   |               ^^^^^^ use of borrowed `v`
+   |               ^ use of borrowed `v`
 ...
 LL |         drop(x);
    |              - borrow later used here
@@ -236,7 +236,7 @@ LL |         let x = &mut v;
    |                 ------ borrow of `v` occurs here
 ...
 LL |             &[_, x @ .., _] => println!("{:?}", x),
-   |                  ^^^^^^ use of borrowed `v`
+   |                  ^ use of borrowed `v`
 ...
 LL |         drop(x);
    |              - borrow later used here
index 3249aae8f44a3cfd4937025a51c98f459b8d10cb..346b82a2666442d47f9116393cf294deb80d20cf 100644 (file)
@@ -79,7 +79,7 @@ error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-match.rs:89:11
    |
 LL |         [_y @ .., _, _] => {}
-   |          ------- value moved here
+   |          -- value moved here
 ...
 LL |         [(_x, _), _, _] => {}
    |           ^^ value used here after move
@@ -90,7 +90,7 @@ error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-match.rs:99:15
    |
 LL |         [_, _, _y @ ..] => {}
-   |                ------- value moved here
+   |                -- value moved here
 ...
 LL |         [.., (_x, _)] => {}
    |               ^^ value used here after move
@@ -101,7 +101,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:110:11
    |
 LL |         [x @ .., _] => {}
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
index c198002265b730cac8e90df51049210dfa01abde..6c6a25c251e700917af065713bfebf0d4259a24d 100644 (file)
@@ -68,7 +68,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11
    |
 LL |         [_, _y @ ..] => {}
-   |             ------- value partially moved here
+   |             -- value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -79,7 +79,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11
    |
 LL |         [_y @ .., _] => {}
-   |          ------- value partially moved here
+   |          -- value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -90,7 +90,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11
    |
 LL |         [x @ .., _, _] => {}
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
index 8f2da9d203b0d064ea29bd039c0877a49e34402b..77702e145df816fb85cdb6aac915a0853efa0bba 100644 (file)
@@ -79,7 +79,7 @@ error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:89:11
    |
 LL |         [_y @ .., _, _] => {}
-   |          ------- value moved here
+   |          -- value moved here
 ...
 LL |         [(ref _x, _), _, _] => {}
    |           ^^^^^^ value borrowed here after move
@@ -90,7 +90,7 @@ error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:99:15
    |
 LL |         [_, _, _y @ ..] => {}
-   |                ------- value moved here
+   |                -- value moved here
 ...
 LL |         [.., (ref _x, _)] => {}
    |               ^^^^^^ value borrowed here after move
@@ -101,7 +101,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11
    |
 LL |         [x @ .., _] => {}
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -134,7 +134,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:139:5
    |
 LL |         [_, _, _x @ ..] => {}
-   |                ------- value partially moved here
+   |                -- value partially moved here
 LL |     }
 LL |     a[0] = Default::default();
    |     ^^^^ value used here after partial move
@@ -145,7 +145,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:147:5
    |
 LL |         [_, _, _x @ ..] => {}
-   |                ------- value partially moved here
+   |                -- value partially moved here
 LL |     }
 LL |     a[0].1 = Default::default();
    |     ^^^^ value used here after partial move
index 4b27f03dc45899631ce865d3c8e41801c6263c94..6cc2c2f7a984c7ba34275f88e826717edf4f4b25 100644 (file)
@@ -68,7 +68,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11
    |
 LL |         [_, _y @ ..] => {}
-   |             ------- value partially moved here
+   |             -- value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -79,7 +79,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11
    |
 LL |         [_y @ .., _] => {}
-   |          ------- value partially moved here
+   |          -- value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -90,7 +90,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11
    |
 LL |         [x @ .., _, _] => {}
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
index b0bad6e997887007f2bd277a1f7537737f58af44..9add7553afa70917c9b51c8cac20f391e07e9f9f 100644 (file)
@@ -34,7 +34,7 @@ error[E0382]: borrow of partially moved value: `a`
 LL |     let [_x, _, _] = a;
    |          -- value partially moved here
 LL |     let [ref _y @ .., _, _] = a;
-   |          ^^^^^^^^^^^ value borrowed here after partial move
+   |          ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -44,7 +44,7 @@ error[E0382]: borrow of partially moved value: `a`
 LL |     let [.., _x] = a;
    |              -- value partially moved here
 LL |     let [_, _, ref _y @ ..] = a;
-   |                ^^^^^^^^^^^ value borrowed here after partial move
+   |                ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -54,7 +54,7 @@ error[E0382]: borrow of partially moved value: `a`
 LL |     let [(_x, _), _, _] = a;
    |           -- value partially moved here
 LL |     let [ref _y @ .., _, _] = a;
-   |          ^^^^^^^^^^^ value borrowed here after partial move
+   |          ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
 
@@ -64,7 +64,7 @@ error[E0382]: borrow of partially moved value: `a`
 LL |     let [.., (_x, _)] = a;
    |               -- value partially moved here
 LL |     let [_, _, ref _y @ ..] = a;
-   |                ^^^^^^^^^^^ value borrowed here after partial move
+   |                ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
 
@@ -72,7 +72,7 @@ error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use.rs:54:11
    |
 LL |     let [_y @ .., _, _] = a;
-   |          ------- value moved here
+   |          -- value moved here
 LL |     let [(ref _x, _), _, _] = a;
    |           ^^^^^^ value borrowed here after move
    |
@@ -82,7 +82,7 @@ error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use.rs:60:15
    |
 LL |     let [_, _, _y @ ..] = a;
-   |                ------- value moved here
+   |                -- value moved here
 LL |     let [.., (ref _x, _)] = a;
    |               ^^^^^^ value borrowed here after move
    |
@@ -92,9 +92,9 @@ error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:68:13
    |
 LL |     let [x @ .., _] = a;
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     let [_, ref _y @ ..] = a;
-   |             ^^^^^^^^^^^ value borrowed here after partial move
+   |             ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -122,7 +122,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:88:5
    |
 LL |     let [_, _, _x @ ..] = a;
-   |                ------- value partially moved here
+   |                -- value partially moved here
 LL |     a[0] = Default::default();
    |     ^^^^ value used here after partial move
    |
@@ -132,7 +132,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:94:5
    |
 LL |     let [_, _, _x @ ..] = a;
-   |                ------- value partially moved here
+   |                -- value partially moved here
 LL |     a[0].1 = Default::default();
    |     ^^^^ value used here after partial move
    |
index 1fc2b292b84c7023bb58cbabf42cc8360a823753..363effcfe5322a579be2a699d6763eb91cacc58e 100644 (file)
@@ -34,7 +34,7 @@ error[E0382]: use of partially moved value: `a`
 LL |     let [_x, _, _] = a;
    |          -- value partially moved here
 LL |     let [_y @ .., _, _] = a;
-   |          ^^^^^^^ value used here after partial move
+   |          ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -44,7 +44,7 @@ error[E0382]: use of partially moved value: `a`
 LL |     let [.., _x] = a;
    |              -- value partially moved here
 LL |     let [_, _, _y @ ..] = a;
-   |                ^^^^^^^ value used here after partial move
+   |                ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -54,7 +54,7 @@ error[E0382]: use of partially moved value: `a`
 LL |     let [(_x, _), _, _] = a;
    |           -- value partially moved here
 LL |     let [_y @ .., _, _] = a;
-   |          ^^^^^^^ value used here after partial move
+   |          ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
 
@@ -64,7 +64,7 @@ error[E0382]: use of partially moved value: `a`
 LL |     let [.., (_x, _)] = a;
    |               -- value partially moved here
 LL |     let [_, _, _y @ ..] = a;
-   |                ^^^^^^^ value used here after partial move
+   |                ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
 
@@ -72,7 +72,7 @@ error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array.rs:54:11
    |
 LL |     let [_y @ .., _, _] = a;
-   |          ------- value moved here
+   |          -- value moved here
 LL |     let [(_x, _), _, _] = a;
    |           ^^ value used here after move
    |
@@ -82,7 +82,7 @@ error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array.rs:60:15
    |
 LL |     let [_, _, _y @ ..] = a;
-   |                ------- value moved here
+   |                -- value moved here
 LL |     let [.., (_x, _)] = a;
    |               ^^ value used here after move
    |
@@ -92,9 +92,9 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:68:13
    |
 LL |     let [x @ .., _] = a;
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     let [_, _y @ ..] = a;
-   |             ^^^^^^^ value used here after partial move
+   |             ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
index b8ac7a3a4469d4433d8c634cc323d5d5d0d69d60..f4324110ccb8ef1eed24c416f85c8d3d34b5ebee 100644 (file)
@@ -57,7 +57,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
 LL |     let [ref first, ref second, ..] = *s;
    |                     ---------- immutable borrow occurs here
 LL |     let [_, ref mut tail @ ..] = *s;
-   |             ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |             ^^^^^^^^^^^^ mutable borrow occurs here
 LL |     nop(&[first, second]);
    |                  ------ immutable borrow later used here
 
@@ -67,7 +67,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
 LL |     let [.., ref second, ref first] = *s;
    |              ---------- immutable borrow occurs here
 LL |     let [ref mut tail @ .., _] = *s;
-   |          ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |          ^^^^^^^^^^^^ mutable borrow occurs here
 LL |     nop(&[first, second]);
    |                  ------ immutable borrow later used here
 
@@ -75,9 +75,9 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
   --> $DIR/borrowck-slice-pattern-element-loan-array.rs:46:10
    |
 LL |     let [_,  ref s1 @ ..] = *s;
-   |              ----------- immutable borrow occurs here
+   |              ------ immutable borrow occurs here
 LL |     let [ref mut s2 @ .., _, _] = *s;
-   |          ^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |          ^^^^^^^^^^ mutable borrow occurs here
 LL |     nop_subslice(s1);
    |                  -- immutable borrow later used here
 
index d3388e071aa5349820cf42dc7e010d031f96f152..f9a63bd49dd57d0f18349da122a6e8d79147aba4 100644 (file)
@@ -88,7 +88,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
 LL |     if let [ref first, ref second, ..] = *s {
    |                        ---------- immutable borrow occurs here
 LL |         if let [_, ref mut tail @ ..] = *s {
-   |                    ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |                    ^^^^^^^^^^^^ mutable borrow occurs here
 LL |             nop(&[first, second]);
    |                          ------ immutable borrow later used here
 
@@ -98,7 +98,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
 LL |     if let [.., ref second, ref first] = *s {
    |                 ---------- immutable borrow occurs here
 LL |         if let [ref mut tail @ .., _] = *s {
-   |                 ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |                 ^^^^^^^^^^^^ mutable borrow occurs here
 LL |             nop(&[first, second]);
    |                          ------ immutable borrow later used here
 
@@ -106,9 +106,9 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
   --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:65:17
    |
 LL |     if let [_, _, _, ref s1 @ ..] = *s {
-   |                      ----------- immutable borrow occurs here
+   |                      ------ immutable borrow occurs here
 LL |         if let [ref mut s2 @ .., _, _, _] = *s {
-   |                 ^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |                 ^^^^^^^^^^ mutable borrow occurs here
 LL |             nop_subslice(s1);
    |                          -- immutable borrow later used here
 
index ff70ba9fcca8b5145983d135fe1cb7d6630dc868..0ac7df944d78114ad1de4c57ea5eaac14fa2a8d7 100644 (file)
@@ -2,7 +2,7 @@ error[E0506]: cannot assign to `a[_]` because it is borrowed
   --> $DIR/borrowck-vec-pattern-move-tail.rs:8:5
    |
 LL |         [1, 2, ref tail @ ..] => tail,
-   |                ------------- borrow of `a[_]` occurs here
+   |                -------- borrow of `a[_]` occurs here
 ...
 LL |     a[2] = 0;
    |     ^^^^^^^^ assignment to borrowed `a[_]` occurs here
index ddd89afe5bf917c35e5f84c3e6f2782185ee4e33..c3bcb7de65daa8fd07550695aaeaafae769f60a9 100644 (file)
@@ -14,7 +14,7 @@ error[E0506]: cannot assign to `vec[_]` because it is borrowed
   --> $DIR/borrowck-vec-pattern-nesting.rs:23:13
    |
 LL |         &mut [ref _b @ ..] => {
-   |               ----------- borrow of `vec[_]` occurs here
+   |               ------ borrow of `vec[_]` occurs here
 LL |
 LL |             vec[0] = Box::new(4);
    |             ^^^^^^ assignment to borrowed `vec[_]` occurs here
index f79a0bd35486aa388eb91d188bc60cb23dc405f2..6ac5380a5aa23b0dcd7161a40741f9c639b29902 100644 (file)
@@ -2,5 +2,4 @@ fn main() {
     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
     //~^ ERROR: invalid label name `'static`
     //~| ERROR: type annotations needed
-    //~| ERROR mismatched types
 }
index 38d9d08ce36ab4c2d6c0bd62cf44dbc7d1bee2e7..4c24a54bbbe014ddc03ee083e274aa58d97110de 100644 (file)
@@ -15,15 +15,6 @@ help: consider giving this closure parameter an explicit type
 LL |     [(); &(&'static: loop { |x: _| {}; }) as *const _ as usize]
    |                               +++
 
-error[E0308]: mismatched types
-  --> $DIR/issue-52437.rs:2:5
-   |
-LL | fn main() {
-   |           - expected `()` because of default return type
-LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[(); _]`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0282, E0308.
-For more information about an error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/codegen/issue-101585-128bit-repeat.rs b/src/test/ui/codegen/issue-101585-128bit-repeat.rs
new file mode 100644 (file)
index 0000000..c6a6865
--- /dev/null
@@ -0,0 +1,14 @@
+// Regression test for issue 101585.
+// run-pass
+
+fn main() {
+    fn min_array_ok() -> [i128; 1] {
+        [i128::MIN]
+    }
+    assert_eq!(min_array_ok(), [-170141183460469231731687303715884105728i128]);
+
+    fn min_array_nok() -> [i128; 1] {
+        [i128::MIN; 1]
+    }
+    assert_eq!(min_array_nok(), [-170141183460469231731687303715884105728i128]);
+}
index 6b33dffb434e7e351f23effe938fe1f308aaf1cc..99122c6f5e3626bc458858e6329eaeccf75720f3 100644 (file)
@@ -1,4 +1,4 @@
-error: lifetime parameters must be declared prior to const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/argument_order.rs:6:32
    |
 LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
@@ -11,7 +11,7 @@ LL |     let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
    |                       ^^^^^^^
    |
    = note: lifetime arguments must be provided before type arguments
-   = help: reorder the arguments: lifetimes, then consts: `<'a, 'b, N, T, M, U>`
+   = help: reorder the arguments: lifetimes, then type and consts: `<'a, 'b, N, T, M, U>`
 
 error: aborting due to 2 previous errors
 
index da06aca308e18bcb5a76822e9eb32fdb5e704698..cb1cebe1f68a1742e42e75c2cc8831e2a9f9f428 100644 (file)
@@ -1,5 +1,5 @@
 fn bar<const X: u8, 'a>(_: &'a ()) {
-    //~^ ERROR lifetime parameters must be declared prior to const parameters
+    //~^ ERROR lifetime parameters must be declared prior to type and const parameters
 }
 
 fn foo<const X: u8, T>(_: &T) {}
index 607d20c4a25f2654cd8a3e75739bc9f5821e0436..2c7a47bbc78cd5c9feb466894c7e741ae918c9b0 100644 (file)
@@ -1,4 +1,4 @@
-error: lifetime parameters must be declared prior to const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/const-param-before-other-params.rs:1:21
    |
 LL | fn bar<const X: u8, 'a>(_: &'a ()) {
index 578938db4c43e8affbaff63a08d19f97b42ad69f..beaf7fc6001a94ecf334753e4f0d698976092b72 100644 (file)
@@ -1,9 +1,9 @@
 // Checks that lifetimes cannot be interspersed between consts and types.
 
 struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
-//~^ Error lifetime parameters must be declared prior to const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 
 struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
-//~^ Error lifetime parameters must be declared prior to type parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 
 fn main() {}
index e27976deb2b569dddb1eb316cf2011be19aab22f..5cff61dd9fb91509eff715c0654efdddc5311507 100644 (file)
@@ -1,10 +1,10 @@
-error: lifetime parameters must be declared prior to const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/intermixed-lifetime.rs:3:28
    |
 LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
    |           -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>`
 
-error: lifetime parameters must be declared prior to type parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/intermixed-lifetime.rs:6:37
    |
 LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
index da087ffc3c4affe767d476286be9ad2d58a0e0c9..f928fc9e75b739c72998facdf78476267c54884b 100644 (file)
@@ -1,4 +1,4 @@
 struct Foo<const M: usize = 10, 'a>(&'a u32);
-//~^ Error lifetime parameters must be declared prior to const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 
 fn main() {}
index 55f5a53538537da232de7f21f503592d9e841c16..ba08b4646d0f4981816fa2ab3a401a97287ee91e 100644 (file)
@@ -1,4 +1,4 @@
-error: lifetime parameters must be declared prior to const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/param-order-err-pretty-prints-default.rs:1:33
    |
 LL | struct Foo<const M: usize = 10, 'a>(&'a u32);
index 28ddddf1be62bbd5bb32d4ed2384a1fb3a153b18..d5f914f46f873bd1fb2fd77f4545108a756c8bc3 100644 (file)
@@ -4,13 +4,13 @@ error[E0391]: cycle detected when resolving instance `<LazyUpdim<T, { T::DIM },
 LL |     const DIM: usize;
    |     ^^^^^^^^^^^^^^^^
    |
-note: ...which requires checking if `TensorDimension` fulfills its obligations...
+note: ...which requires computing candidate for `<LazyUpdim<T, { T::DIM }, DIM> as TensorDimension>`...
   --> $DIR/issue-83765.rs:4:1
    |
 LL | trait TensorDimension {
    | ^^^^^^^^^^^^^^^^^^^^^
    = note: ...which again requires resolving instance `<LazyUpdim<T, { T::DIM }, DIM> as TensorDimension>::DIM`, completing the cycle
-note: cycle used when checking if `TensorDimension` fulfills its obligations
+note: cycle used when computing candidate for `<LazyUpdim<T, { T::DIM }, DIM> as TensorDimension>`
   --> $DIR/issue-83765.rs:4:1
    |
 LL | trait TensorDimension {
index fd843105daf2a8a3a819a905e49354446536d7ba..83e10bf1213ea17ff075ab78e2628f623cf7561f 100644 (file)
@@ -4,14 +4,10 @@
 #![feature(const_raw_ptr_comparison)]
 
 const EMPTY_SLICE: &[i32] = &[];
-const EMPTY_EQ: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[] as *const _);
-const EMPTY_EQ2: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[] as *const _);
-const EMPTY_NE: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[1] as *const _);
-const EMPTY_NE2: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[1] as *const _);
+const EMPTY_EQ: Option<bool> = EMPTY_SLICE.as_ptr().guaranteed_eq(&[] as *const _);
+const EMPTY_EQ2: Option<bool> = EMPTY_SLICE.as_ptr().guaranteed_eq(&[1] as *const _);
 
 fn main() {
-    assert!(!EMPTY_EQ);
-    assert!(!EMPTY_EQ2);
-    assert!(!EMPTY_NE);
-    assert!(!EMPTY_NE2);
+    assert!(EMPTY_EQ.is_none());
+    assert!(EMPTY_EQ2.is_none());
 }
index 20233db09c90b8af70991fdd0e623f5339a2559a..0a3c2d4bedcbd5f8122efbfe5a5eae0c7f7443aa 100644 (file)
 macro_rules! check {
     (eq, $a:expr, $b:expr) => {
         pub const _: () =
-            assert!(std::intrinsics::ptr_guaranteed_eq($a as *const u8, $b as *const u8));
+            assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 1);
     };
     (ne, $a:expr, $b:expr) => {
         pub const _: () =
-            assert!(std::intrinsics::ptr_guaranteed_ne($a as *const u8, $b as *const u8));
+            assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 0);
     };
-    (!eq, $a:expr, $b:expr) => {
+    (!, $a:expr, $b:expr) => {
         pub const _: () =
-            assert!(!std::intrinsics::ptr_guaranteed_eq($a as *const u8, $b as *const u8));
-    };
-    (!ne, $a:expr, $b:expr) => {
-        pub const _: () =
-            assert!(!std::intrinsics::ptr_guaranteed_ne($a as *const u8, $b as *const u8));
+            assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 2);
     };
 }
 
 check!(eq, 0, 0);
 check!(ne, 0, 1);
-check!(!eq, 0, 1);
-check!(!ne, 0, 0);
 check!(ne, FOO as *const _, 0);
-check!(!eq, FOO as *const _, 0);
+check!(ne, unsafe { (FOO as *const usize).offset(1) }, 0);
+check!(ne, unsafe { (FOO as *const usize as *const u8).offset(3) }, 0);
+
 // We want pointers to be equal to themselves, but aren't checking this yet because
 // there are some open questions (e.g. whether function pointers to the same function
 // compare equal, they don't necessarily at runtime).
 // The case tested here should work eventually, but does not work yet.
-check!(!eq, FOO as *const _, FOO as *const _);
-check!(ne, unsafe { (FOO as *const usize).offset(1) }, 0);
-check!(!eq, unsafe { (FOO as *const usize).offset(1) }, 0);
+check!(!, FOO as *const _, FOO as *const _);
 
-check!(ne, unsafe { (FOO as *const usize as *const u8).offset(3) }, 0);
-check!(!eq, unsafe { (FOO as *const usize as *const u8).offset(3) }, 0);
 
 ///////////////////////////////////////////////////////////////////////////////
 // If any of the below start compiling, make sure to add a `check` test for it.
index 1d47f243f01cdeb6c4b5b7cdf3cc0ee12c34918c..3de2aba5b05e1f1af758fdc770a5bac28d97754a 100644 (file)
@@ -7,19 +7,19 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  out-of-bounds pointer arithmetic: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const usize>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/ptr_comparisons.rs:58:34
+  ::: $DIR/ptr_comparisons.rs:50:34
    |
 LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) };
-   |                                  ------------------------------- inside `_` at $DIR/ptr_comparisons.rs:58:34
+   |                                  ------------------------------- inside `_` at $DIR/ptr_comparisons.rs:50:34
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ptr_comparisons.rs:61:33
+  --> $DIR/ptr_comparisons.rs:53:33
    |
 LL |     unsafe { std::ptr::addr_of!((*(FOO as *const usize as *const [u8; 1000]))[999]) };
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: alloc3 has size $WORD, so pointer to 1000 bytes starting at offset 0 is out-of-bounds
 
 error: any use of this value will cause an error
-  --> $DIR/ptr_comparisons.rs:65:27
+  --> $DIR/ptr_comparisons.rs:57:27
    |
 LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 };
    | --------------            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -31,7 +31,7 @@ LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) +
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error: any use of this value will cause an error
-  --> $DIR/ptr_comparisons.rs:70:27
+  --> $DIR/ptr_comparisons.rs:62:27
    |
 LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 };
    | --------------            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -46,7 +46,7 @@ error: aborting due to 4 previous errors
 For more information about this error, try `rustc --explain E0080`.
 Future incompatibility report: Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/ptr_comparisons.rs:65:27
+  --> $DIR/ptr_comparisons.rs:57:27
    |
 LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 };
    | --------------            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
@@ -59,7 +59,7 @@ LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) +
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
-  --> $DIR/ptr_comparisons.rs:70:27
+  --> $DIR/ptr_comparisons.rs:62:27
    |
 LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 };
    | --------------            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
index 0594b1384ec2345fb6bd7f95c5e9ac9c02d671c6..fc47a9061d3c02b5f7f76c8065f8f12e3c317950 100644 (file)
@@ -1,10 +1,11 @@
+// only-x86
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal(42)]
-    //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
+    //~^ ERROR: `#[link_ordinal]` is unstable on x86
     fn foo();
     #[link_ordinal(5)]
-    //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
+    //~^ ERROR: `#[link_ordinal]` is unstable on x86
     static mut imported_variable: i32;
 }
 
index d39969b61cac23986498fca82859c3e58f99bc62..0e900760d245e44b628d93ce54cdf9c859089ec0 100644 (file)
@@ -1,5 +1,5 @@
-error[E0658]: the `#[link_ordinal]` attribute is an experimental feature
-  --> $DIR/feature-gate-raw-dylib-2.rs:3:5
+error[E0658]: `#[link_ordinal]` is unstable on x86
+  --> $DIR/feature-gate-raw-dylib-2.rs:4:5
    |
 LL |     #[link_ordinal(42)]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -7,8 +7,8 @@ LL |     #[link_ordinal(42)]
    = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
    = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
 
-error[E0658]: the `#[link_ordinal]` attribute is an experimental feature
-  --> $DIR/feature-gate-raw-dylib-2.rs:6:5
+error[E0658]: `#[link_ordinal]` is unstable on x86
+  --> $DIR/feature-gate-raw-dylib-2.rs:7:5
    |
 LL |     #[link_ordinal(5)]
    |     ^^^^^^^^^^^^^^^^^^
index 33655cf8bdc7ebc64f377702d165c9bba5d55dc1..295f502d6a3e57f200195a1fae8b0ebf3cc33c2b 100644 (file)
@@ -1,7 +1,7 @@
 // only-windows
 // only-x86
 #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
-//~^ ERROR link kind `raw-dylib` is unstable
+//~^ ERROR link kind `raw-dylib` is unstable on x86
 //~| ERROR import name type is unstable
 extern "C" {}
 
index be82dd119264f0e8e6c24d859baf5376b0e47bd8..d6b165b7610a55c453a29ad6d00f2cf79b378d3c 100644 (file)
@@ -1,4 +1,4 @@
-error[E0658]: link kind `raw-dylib` is unstable
+error[E0658]: link kind `raw-dylib` is unstable on x86
   --> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:29
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
index f894f517b38df9ea27b4253b17ab415371466fb3..291cca8fd25737262db3b46b827440bb72c3b89d 100644 (file)
@@ -1,6 +1,7 @@
 // only-windows
+// only-x86
 #[link(name = "foo", kind = "raw-dylib")]
-//~^ ERROR: link kind `raw-dylib` is unstable
+//~^ ERROR: link kind `raw-dylib` is unstable on x86
 extern "C" {}
 
 fn main() {}
index ca7a61f64134fbdfec16007fa2782ae7b0051316..f02241e4908c091b16d5a3e75d4a77d4018ba1df 100644 (file)
@@ -1,5 +1,5 @@
-error[E0658]: link kind `raw-dylib` is unstable
-  --> $DIR/feature-gate-raw-dylib.rs:2:29
+error[E0658]: link kind `raw-dylib` is unstable on x86
+  --> $DIR/feature-gate-raw-dylib.rs:3:29
    |
 LL | #[link(name = "foo", kind = "raw-dylib")]
    |                             ^^^^^^^^^^^
diff --git a/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.rs b/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.rs
new file mode 100644 (file)
index 0000000..de7966c
--- /dev/null
@@ -0,0 +1,5 @@
+trait Foo {
+    fn bar() -> impl Sized; //~ ERROR `impl Trait` only allowed in function and inherent method return types, not in trait method return
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr b/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr
new file mode 100644 (file)
index 0000000..36177bb
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return
+  --> $DIR/feature-gate-return_position_impl_trait_in_trait.rs:2:17
+   |
+LL |     fn bar() -> impl Sized;
+   |                 ^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
index 2315810a47ace850f1f6b27ae385604690f2cfc7..ee758f19ec105345066f5437ce2e17aaf125cc63 100644 (file)
@@ -24,7 +24,7 @@ impl<B: Add + Add<Output = B>> Add for C<B> {
 
 struct D<B>(B);
 
-impl<B: std::ops::Add<Output=B>> Add for D<B> {
+impl<B: std::ops::Add<Output = B>> Add for D<B> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
index 138c642dd7952181918a88d5e492b826d6af4cbb..c913483a8747c15ef849f859570306d64a177578 100644 (file)
@@ -66,8 +66,8 @@ LL |         Self(self.0 + rhs.0)
    |
 help: consider restricting type parameter `B`
    |
-LL | impl<B: std::ops::Add<Output=B>> Add for D<B> {
-   |       +++++++++++++++++++++++++
+LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
+   |       +++++++++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/missing-bounds.rs:42:14
index 7e1dd77070441fa317cfeb57fc60ebca79dc71ff..8e27749e8fc6b06d53d69492a19080c79167e61f 100644 (file)
@@ -8,7 +8,7 @@
 
 impl A {
     pub fn do_things<T, 'a, 'b: 'a>() {
-    //~^ ERROR lifetime parameters must be declared prior to type parameters
+    //~^ ERROR lifetime parameters must be declared prior to type and const parameters
         println!("panic");
     }
 }
index d162365ea4bff9c010a2df6b2cdf994614f1abbb..1c510044f806fb1d45a26c9b5bf6702a82dce558 100644 (file)
@@ -1,4 +1,4 @@
-error: lifetime parameters must be declared prior to type parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/issue-59508-1.rs:10:25
    |
 LL |     pub fn do_things<T, 'a, 'b: 'a>() {
index b5c60a1626f53584d522b01f9c92a055197c92bd..de8f47d4cff89d29c6336d8b5a4c920ea0b1a8dd 100644 (file)
@@ -8,7 +8,7 @@ struct A;
 
 impl A {
     pub fn do_things<'a, 'b: 'a, T>() {
-    //~^ ERROR lifetime parameters must be declared prior to type parameters
+    //~^ ERROR lifetime parameters must be declared prior to type and const parameters
         println!("panic");
     }
 }
index 0b39c5d8f2aec802e4a1e80b33232e89778d9010..a4c7d4ff26266e1f9bed72b658f8e4e26cc29093 100644 (file)
@@ -8,7 +8,7 @@
 
 impl A {
     pub fn do_things<T, 'a, 'b: 'a>() {
-    //~^ ERROR lifetime parameters must be declared prior to type parameters
+    //~^ ERROR lifetime parameters must be declared prior to type and const parameters
         println!("panic");
     }
 }
index c52ae4182b86bf0ad4547d6be74d0eb2a6553908..fd23b6276f92b5b55c33b941cdfad6c02cfe8627 100644 (file)
@@ -1,4 +1,4 @@
-error: lifetime parameters must be declared prior to type parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/issue-59508.rs:10:25
    |
 LL |     pub fn do_things<T, 'a, 'b: 'a>() {
index fe3e4fbc7e0b603527289236a6cabf3e8066ac88..0e208818ed4593f6094221db58e3c53f6d339d5e 100644 (file)
@@ -1,4 +1,4 @@
 #![crate_type = "lib"]
 
 struct S<T = (), 'a>(&'a T);
-//~^ ERROR lifetime parameters must be declared prior to type parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
index 119b1a0d2070ec79ca6502eb2d04fea6b46c7517..70793a9c92084b040df1a5ad496142a2d30303d4 100644 (file)
@@ -1,4 +1,4 @@
-error: lifetime parameters must be declared prior to type parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/issue-80512-param-reordering-with-defaults.rs:3:18
    |
 LL | struct S<T = (), 'a>(&'a T);
index 5a71d6efeda62bb81e836fd23e4b2ec61575a04f..d64b1b0b44f65f78acc71f56d22801f79dbfd971 100644 (file)
@@ -1,11 +1,11 @@
 #![allow(unused)]
 fn first<T, 'a, 'b>() {}
-//~^ ERROR lifetime parameters must be declared prior to type parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 fn second<'a, T, 'b>() {}
-//~^ ERROR lifetime parameters must be declared prior to type parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 fn third<T, U, 'a>() {}
-//~^ ERROR lifetime parameters must be declared prior to type parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 fn fourth<'a, T, 'b, U, 'c, V>() {}
-//~^ ERROR lifetime parameters must be declared prior to type parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 
 fn main() {}
index 62d95e45329f92f7c93ac98eabf6a3854cbe4261..84825eb4ceb211fe406e298d0c007e5cbf9d59ae 100644 (file)
@@ -1,22 +1,22 @@
-error: lifetime parameters must be declared prior to type parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/lifetime-before-type-params.rs:2:13
    |
 LL | fn first<T, 'a, 'b>() {}
    |         ----^^--^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
 
-error: lifetime parameters must be declared prior to type parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/lifetime-before-type-params.rs:4:18
    |
 LL | fn second<'a, T, 'b>() {}
    |          --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
 
-error: lifetime parameters must be declared prior to type parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/lifetime-before-type-params.rs:6:16
    |
 LL | fn third<T, U, 'a>() {}
    |         -------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, U>`
 
-error: lifetime parameters must be declared prior to type parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/lifetime-before-type-params.rs:8:18
    |
 LL | fn fourth<'a, T, 'b, U, 'c, V>() {}
diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr
new file mode 100644 (file)
index 0000000..fd2e454
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied
+  --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13
+   |
+LL | fn ice() -> impl AsRef<Fn(&())> {
+   |             ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr
new file mode 100644 (file)
index 0000000..c01c33a
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:24
+   |
+LL | fn ice() -> impl AsRef<Fn(&())> {
+   |                        ^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - fn ice() -> impl AsRef<Fn(&())> {
+LL + fn ice() -> impl AsRef<dyn Fn(&())> {
+   |
+
+error[E0277]: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied
+  --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13
+   |
+LL | fn ice() -> impl AsRef<Fn(&())> {
+   |             ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not implemented for `()`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0782.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs
new file mode 100644 (file)
index 0000000..856dc7a
--- /dev/null
@@ -0,0 +1,12 @@
+// revisions: edition2015 edition2021
+//[edition2021]edition:2021
+
+#![allow(warnings)]
+
+fn ice() -> impl AsRef<Fn(&())> {
+    //~^ ERROR: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied [E0277]
+    //[edition2021]~| ERROR: trait objects must include the `dyn` keyword [E0782]
+    todo!()
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/in-trait/deep-match-works.rs b/src/test/ui/impl-trait/in-trait/deep-match-works.rs
new file mode 100644 (file)
index 0000000..772da84
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+struct Wrapper<T>(T);
+
+trait Foo {
+    fn bar() -> Wrapper<impl Sized>;
+}
+
+impl Foo for () {
+    fn bar() -> Wrapper<i32> { Wrapper(0) }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/in-trait/deep-match.rs b/src/test/ui/impl-trait/in-trait/deep-match.rs
new file mode 100644 (file)
index 0000000..5a220bc
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+struct Wrapper<T>(T);
+
+trait Foo {
+    fn bar() -> Wrapper<impl Sized>;
+}
+
+impl Foo for () {
+    fn bar() -> i32 { 0 }
+    //~^ ERROR method `bar` has an incompatible type for trait
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/in-trait/deep-match.stderr b/src/test/ui/impl-trait/in-trait/deep-match.stderr
new file mode 100644 (file)
index 0000000..af44986
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0053]: method `bar` has an incompatible type for trait
+  --> $DIR/deep-match.rs:11:17
+   |
+LL |     fn bar() -> i32 { 0 }
+   |                 ^^^
+   |                 |
+   |                 expected struct `Wrapper`, found `i32`
+   |                 help: change the output type to match the trait: `Wrapper<_>`
+   |
+note: type in trait
+  --> $DIR/deep-match.rs:7:17
+   |
+LL |     fn bar() -> Wrapper<impl Sized>;
+   |                 ^^^^^^^^^^^^^^^^^^^
+   = note: expected fn pointer `fn() -> Wrapper<_>`
+              found fn pointer `fn() -> i32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/src/test/ui/impl-trait/in-trait/doesnt-satisfy.rs b/src/test/ui/impl-trait/in-trait/doesnt-satisfy.rs
new file mode 100644 (file)
index 0000000..bb4e0d4
--- /dev/null
@@ -0,0 +1,13 @@
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    fn bar() -> impl std::fmt::Display;
+}
+
+impl Foo for () {
+    fn bar() -> () {}
+    //~^ ERROR `()` doesn't implement `std::fmt::Display`
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/src/test/ui/impl-trait/in-trait/doesnt-satisfy.stderr
new file mode 100644 (file)
index 0000000..aa5492d
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+  --> $DIR/doesnt-satisfy.rs:9:17
+   |
+LL |     fn bar() -> () {}
+   |                 ^^ `()` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `()`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `Foo::bar::{opaque#0}`
+  --> $DIR/doesnt-satisfy.rs:5:22
+   |
+LL |     fn bar() -> impl std::fmt::Display;
+   |                      ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::bar::{opaque#0}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/in-trait/nested-rpitit.rs b/src/test/ui/impl-trait/in-trait/nested-rpitit.rs
new file mode 100644 (file)
index 0000000..65285e3
--- /dev/null
@@ -0,0 +1,32 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Display;
+use std::ops::Deref;
+
+trait Foo {
+    fn bar(self) -> impl Deref<Target = impl Display + ?Sized>;
+}
+
+struct A;
+
+impl Foo for A {
+    fn bar(self) -> &'static str {
+        "Hello, world"
+    }
+}
+
+struct B;
+
+impl Foo for B {
+    fn bar(self) -> Box<i32> {
+        Box::new(42)
+    }
+}
+
+fn main() {
+    println!("Message for you: {:?}", &*A.bar());
+    println!("Another for you: {:?}", &*B.bar());
+}
diff --git a/src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs b/src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
new file mode 100644 (file)
index 0000000..3ac264e
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Display;
+
+trait Foo {
+    fn bar(&self) -> impl Display;
+}
+
+impl Foo for () {
+    fn bar(&self) -> impl Display {
+        "Hello, world"
+    }
+}
+
+fn main() {
+    let x: &str = ().bar();
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr b/src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr
new file mode 100644 (file)
index 0000000..15edda4
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/opaque-in-impl-is-opaque.rs:17:19
+   |
+LL |     fn bar(&self) -> impl Display {
+   |                      ------------ the found opaque type
+...
+LL |     let x: &str = ().bar();
+   |            ----   ^^^^^^^^ expected `&str`, found opaque type
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&str`
+            found opaque type `impl std::fmt::Display`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/impl-trait/in-trait/opaque-in-impl.rs b/src/test/ui/impl-trait/in-trait/opaque-in-impl.rs
new file mode 100644 (file)
index 0000000..2e06629
--- /dev/null
@@ -0,0 +1,48 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Debug;
+
+trait Foo {
+    fn foo(&self) -> impl Debug;
+}
+
+impl Foo for () {
+    fn foo(&self) -> impl Debug {
+        "Hello, world"
+    }
+}
+
+impl<T: Default + Debug> Foo for std::marker::PhantomData<T> {
+    fn foo(&self) -> impl Debug {
+        T::default()
+    }
+}
+
+trait Bar {
+    fn bar<T>(&self) -> impl Debug;
+}
+
+impl Bar for () {
+    fn bar<T>(&self) -> impl Debug {
+        format!("Hello with generic {}", std::any::type_name::<T>())
+    }
+}
+
+trait Baz {
+    fn baz(&self) -> impl Debug + '_;
+}
+
+impl Baz for String {
+    fn baz(&self) -> impl Debug + '_ {
+        (self,)
+    }
+}
+
+fn main() {
+    println!("{:?}", ().foo());
+    println!("{:?}", ().bar::<u64>());
+    println!("{:?}", "hi".to_string().baz());
+}
diff --git a/src/test/ui/impl-trait/in-trait/reveal.rs b/src/test/ui/impl-trait/in-trait/reveal.rs
new file mode 100644 (file)
index 0000000..d6ede1c
--- /dev/null
@@ -0,0 +1,18 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    fn f() -> Box<impl Sized>;
+}
+
+impl Foo for () {
+    fn f() -> Box<String> {
+        Box::new(String::new())
+    }
+}
+
+fn main() {
+    let x: Box<String> = <() as Foo>::f();
+}
diff --git a/src/test/ui/impl-trait/in-trait/success.rs b/src/test/ui/impl-trait/in-trait/success.rs
new file mode 100644 (file)
index 0000000..4cbe682
--- /dev/null
@@ -0,0 +1,40 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Display;
+
+trait Foo {
+    fn bar(&self) -> impl Display;
+}
+
+impl Foo for i32 {
+    fn bar(&self) -> i32 {
+        *self
+    }
+}
+
+impl Foo for &'static str {
+    fn bar(&self) -> &'static str {
+        *self
+    }
+}
+
+struct Yay;
+
+impl Foo for Yay {
+    fn bar(&self) -> String {
+        String::from(":^)")
+    }
+}
+
+fn foo_generically<T: Foo>(t: T) {
+    println!("{}", t.bar());
+}
+
+fn main() {
+    println!("{}", "Hello, world.".bar());
+    println!("The answer is {}!", 42.bar());
+    foo_generically(Yay);
+}
index 58a2f79efb4c643e5f0cecdfbbb25faf395064b1..9b346387d61064cbf9bd4d01a47fb4fd0cc1028a 100644 (file)
@@ -162,12 +162,18 @@ error[E0562]: `impl Trait` only allowed in function and inherent method return t
    |
 LL |     fn in_return() -> impl Debug;
    |                       ^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return
   --> $DIR/where-allowed.rs:125:34
    |
 LL |     fn in_trait_impl_return() -> impl Debug { () }
    |                                  ^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` param
   --> $DIR/where-allowed.rs:138:33
index 03aa37f52075f73b9a70fb8401136f06273e4363..02c5dd5bfb77198e526206170e5e915089f7d92c 100644 (file)
@@ -31,12 +31,16 @@ error[E0552]: unrecognized representation hint
    |
 LL |     #[repr(nothing)]
    |            ^^^^^^^
+   |
+   = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
 
 error[E0552]: unrecognized representation hint
   --> $DIR/issue-43988.rs:18:12
    |
 LL |     #[repr(something_not_real)]
    |            ^^^^^^^^^^^^^^^^^^
+   |
+   = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
 
 error[E0518]: attribute should be applied to function or closure
   --> $DIR/issue-43988.rs:30:5
index 5b84f7ed62c3a18239eb36191ebbe7795660b496..9998ee0e8d0c69c801528a509eb6371d10af4f86 100644 (file)
@@ -4,7 +4,8 @@ error[E0581]: return type references an anonymous lifetime, which is not constra
 LL | fn f(_: X) -> X {
    |               ^
    |
-   = note: lifetimes appearing in an associated type are not considered constrained
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
 
 error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
   --> $DIR/issue-47511.rs:12:23
index 4585bcc8cd57fac92d54a14143465527e85b8259..835fdfae86c033790b72681ddb11d7454b35d3de 100644 (file)
@@ -2,7 +2,6 @@ fn a() {
     [0; [|_: _ &_| ()].len()]
     //~^ ERROR expected `,`, found `&`
     //~| ERROR type annotations needed
-    //~| ERROR mismatched types
 }
 
 fn b() {
@@ -13,13 +12,11 @@ fn b() {
 fn c() {
     [0; [|&_: _ &_| {}; 0 ].len()]
     //~^ ERROR expected `,`, found `&`
-    //~| ERROR mismatched types
 }
 
 fn d() {
     [0; match [|f @ &ref _| () ] {} ]
     //~^ ERROR expected identifier, found reserved identifier `_`
-    //~| ERROR mismatched types
 }
 
 fn main() {}
index 1c55560cb7c723f8e37f0dc6275000d2fa715ec9..8a30c0cad39c5167ee855721d865d2c0169370ba 100644 (file)
@@ -7,13 +7,13 @@ LL |     [0; [|_: _ &_| ()].len()]
    |               help: missing `,`
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/issue-66706.rs:9:20
+  --> $DIR/issue-66706.rs:8:20
    |
 LL |     [0; [|f @ &ref _| {} ; 0 ].len() ];
    |                    ^ expected identifier, found reserved identifier
 
 error: expected `,`, found `&`
-  --> $DIR/issue-66706.rs:14:17
+  --> $DIR/issue-66706.rs:13:17
    |
 LL |     [0; [|&_: _ &_| {}; 0 ].len()]
    |                -^ expected `,`
@@ -21,7 +21,7 @@ LL |     [0; [|&_: _ &_| {}; 0 ].len()]
    |                help: missing `,`
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/issue-66706.rs:20:26
+  --> $DIR/issue-66706.rs:18:26
    |
 LL |     [0; match [|f @ &ref _| () ] {} ]
    |                          ^ expected identifier, found reserved identifier
@@ -32,31 +32,6 @@ error[E0282]: type annotations needed
 LL |     [0; [|_: _ &_| ()].len()]
    |           ^ cannot infer type
 
-error[E0308]: mismatched types
-  --> $DIR/issue-66706.rs:2:5
-   |
-LL | fn a() {
-   |        - help: try adding a return type: `-> [i32; _]`
-LL |     [0; [|_: _ &_| ()].len()]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]`
-
-error[E0308]: mismatched types
-  --> $DIR/issue-66706.rs:14:5
-   |
-LL | fn c() {
-   |        - help: try adding a return type: `-> [i32; _]`
-LL |     [0; [|&_: _ &_| {}; 0 ].len()]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]`
-
-error[E0308]: mismatched types
-  --> $DIR/issue-66706.rs:20:5
-   |
-LL | fn d() {
-   |        - help: try adding a return type: `-> [i32; _]`
-LL |     [0; match [|f @ &ref _| () ] {} ]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]`
-
-error: aborting due to 8 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0282, E0308.
-For more information about an error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0282`.
index 6deb1f271a72870f21157ff37e12dafa1d9615e7..bfabe2d12f7ffcc8a73d1c3c27aec08efc91be15 100644 (file)
@@ -411,7 +411,7 @@ error: layout_of(NicheFirst) = Layout {
                    valid_range: 0..=4,
                },
                tag_encoding: Niche {
-                   dataful_variant: 0,
+                   untagged_variant: 0,
                    niche_variants: 1..=2,
                    niche_start: 3,
                },
@@ -555,7 +555,7 @@ error: layout_of(NicheSecond) = Layout {
                    valid_range: 0..=4,
                },
                tag_encoding: Niche {
-                   dataful_variant: 0,
+                   untagged_variant: 0,
                    niche_variants: 1..=2,
                    niche_start: 3,
                },
index 56d3a52bb7ff9133a2f0fcdcf0ea3f95572d30b2..a3e82070e0f529cd8287ba75c8e7454a41063856 100644 (file)
@@ -353,7 +353,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed<U16IsZero>>) = Layout {
                    valid_range: 0..=1,
                },
                tag_encoding: Niche {
-                   dataful_variant: 1,
+                   untagged_variant: 1,
                    niche_variants: 0..=0,
                    niche_start: 1,
                },
index fd682e56ae1de444885fa48015d38a7331ed6dfb..0caa0b83a4c7cbe00939ab4cc0ed8a43ec7de3db 100644 (file)
@@ -13,7 +13,7 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array
   --> $DIR/move-out-of-array-ref.rs:13:27
    |
 LL |     let [_, s @ .. , _] = *a;
-   |             ------        ^^
+   |             -             ^^
    |             |             |
    |             |             cannot move out of here
    |             |             help: consider borrowing here: `&*a`
@@ -35,7 +35,7 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array
   --> $DIR/move-out-of-array-ref.rs:23:27
    |
 LL |     let [_, s @ .. , _] = *a;
-   |             ------        ^^
+   |             -             ^^
    |             |             |
    |             |             cannot move out of here
    |             |             help: consider borrowing here: `&*a`
index 9a863bf31a7fb79d0735cd725038bfb03944ce0a..93b0dcfc2d18af210bd8307640d65d7414e2ff24 100644 (file)
@@ -14,7 +14,7 @@ LL |     match *a {
    |           ^^ cannot move out of here
 LL |
 LL |         [a @ ..] => {}
-   |          ------
+   |          -
    |          |
    |          data moved here
    |          move occurs because `a` has type `[A]`, which does not implement the `Copy` trait
@@ -26,7 +26,7 @@ LL |     match *b {
    |           ^^ cannot move out of here
 LL |
 LL |         [_, _, b @ .., _] => {}
-   |                ------
+   |                -
    |                |
    |                data moved here
    |                move occurs because `b` has type `[A]`, which does not implement the `Copy` trait
@@ -38,7 +38,7 @@ LL |     match *c {
    |           ^^ cannot move out of here
 LL |
 LL |         [c @ ..] => {}
-   |          ------
+   |          -
    |          |
    |          data moved here
    |          move occurs because `c` has type `[C]`, which does not implement the `Copy` trait
@@ -50,7 +50,7 @@ LL |     match *d {
    |           ^^ cannot move out of here
 LL |
 LL |         [_, _, d @ .., _] => {}
-   |                ------
+   |                -
    |                |
    |                data moved here
    |                move occurs because `d` has type `[C]`, which does not implement the `Copy` trait
index 19f0223a357a53e1fee7727c77516654b4e3a158..dcb6f9fec18b6eb94aec31ecd326569227f1674c 100644 (file)
@@ -2,7 +2,7 @@ error[E0594]: cannot assign to `*my_ref`, which is behind a `&` reference
   --> $DIR/issue-51244.rs:3:5
    |
 LL |     let ref my_ref @ _ = 0;
-   |         -------------- help: consider changing this to be a mutable reference: `ref mut my_ref @ _`
+   |         ---------- help: consider changing this to be a mutable reference: `ref mut my_ref`
 LL |     *my_ref = 0;
    |     ^^^^^^^^^^^ `my_ref` is a `&` reference, so the data it refers to cannot be written
 
diff --git a/src/test/ui/parser/do-not-suggest-semicolon-before-array.rs b/src/test/ui/parser/do-not-suggest-semicolon-before-array.rs
new file mode 100644 (file)
index 0000000..7ebf3f6
--- /dev/null
@@ -0,0 +1,8 @@
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+    foo()
+    [1, 3) //~ ERROR expected one of `.`, `?`, `]`, or an operator, found `,`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/do-not-suggest-semicolon-before-array.stderr b/src/test/ui/parser/do-not-suggest-semicolon-before-array.stderr
new file mode 100644 (file)
index 0000000..a9dd526
--- /dev/null
@@ -0,0 +1,10 @@
+error: expected one of `.`, `?`, `]`, or an operator, found `,`
+  --> $DIR/do-not-suggest-semicolon-before-array.rs:5:5
+   |
+LL |     [1, 3)
+   |     ^ ^ help: `]` may belong here
+   |     |
+   |     unclosed delimiter
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs b/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs
new file mode 100644 (file)
index 0000000..d6f7981
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    let _x = vec[1, 2, 3]; //~ ERROR expected one of `.`, `?`, `]`, or an operator
+}
diff --git a/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr b/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr
new file mode 100644 (file)
index 0000000..2fe6a28
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected one of `.`, `?`, `]`, or an operator, found `,`
+  --> $DIR/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs:2:19
+   |
+LL |     let _x = vec[1, 2, 3];
+   |                   ^ expected one of `.`, `?`, `]`, or an operator
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs
deleted file mode 100644 (file)
index 7ebf3f6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-fn foo() {}
-
-fn bar() -> [u8; 2] {
-    foo()
-    [1, 3) //~ ERROR expected one of `.`, `?`, `]`, or an operator, found `,`
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr
deleted file mode 100644 (file)
index d6e8db8..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-error: expected one of `.`, `?`, `]`, or an operator, found `,`
-  --> $DIR/do-not-suggest-suggest-semicolon-before-array.rs:5:5
-   |
-LL |     [1, 3)
-   |     ^ ^ help: `]` may belong here
-   |     |
-   |     unclosed delimiter
-
-error: aborting due to previous error
-
index 8ff14fb1f304aee283b93b1bf8256a9d90c1ad83..cf5d3dab4aadad1f5b3e73b5f4b98db565906d25 100644 (file)
@@ -27,7 +27,6 @@ trait X {
     struct Y;
     impl X for Y {
         async fn ft1() {} //~ ERROR functions in traits cannot be declared `async`
-        //~^ ERROR has an incompatible type for trait
         unsafe fn ft2() {} // OK.
         const fn ft3() {} //~ ERROR functions in traits cannot be declared const
         extern "C" fn ft4() {}
@@ -36,7 +35,6 @@ extern "C" fn ft4() {}
         //~| ERROR functions in traits cannot be declared const
         //~| ERROR functions cannot be both `const` and `async`
         //~| ERROR cycle detected
-        //~| ERROR has an incompatible type for trait
     }
 
     impl Y {
index bc51ba8b8c5c51971799f77b3dea857c71f7243d..36304779df36fa6ee620f90cd7c15cbb98266da7 100644 (file)
@@ -7,17 +7,6 @@ LL |     const async unsafe extern "C" fn ff5() {}
    |     |     `async` because of this
    |     `const` because of this
 
-error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:17:9
-   |
-LL |         async fn ft1();
-   |         -----^^^^^^^^^^
-   |         |
-   |         `async` because of this
-   |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 error[E0379]: functions in traits cannot be declared const
   --> $DIR/fn-header-semantic-fail.rs:19:9
    |
@@ -30,17 +19,6 @@ error[E0379]: functions in traits cannot be declared const
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^ functions in traits cannot be const
 
-error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:21:9
-   |
-LL |         const async unsafe extern "C" fn ft5();
-   |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |               |
-   |               `async` because of this
-   |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 error: functions cannot be both `const` and `async`
   --> $DIR/fn-header-semantic-fail.rs:21:9
    |
@@ -50,42 +28,20 @@ LL |         const async unsafe extern "C" fn ft5();
    |         |     `async` because of this
    |         `const` because of this
 
-error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:29:9
-   |
-LL |         async fn ft1() {}
-   |         -----^^^^^^^^^^^^
-   |         |
-   |         `async` because of this
-   |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:32:9
+  --> $DIR/fn-header-semantic-fail.rs:31:9
    |
 LL |         const fn ft3() {}
    |         ^^^^^ functions in traits cannot be const
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:33:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^ functions in traits cannot be const
 
-error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:34:9
-   |
-LL |         const async unsafe extern "C" fn ft5() {}
-   |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |               |
-   |               `async` because of this
-   |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:33:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^-^^^^^------------------------------
@@ -94,7 +50,7 @@ LL |         const async unsafe extern "C" fn ft5() {}
    |         `const` because of this
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:47:9
+  --> $DIR/fn-header-semantic-fail.rs:45:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^-^^^^^------------------------------
@@ -103,7 +59,7 @@ LL |         const async unsafe extern "C" fn fi5() {}
    |         `const` because of this
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:53:18
+  --> $DIR/fn-header-semantic-fail.rs:51:18
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -116,7 +72,7 @@ LL |         fn fe1();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:54:19
+  --> $DIR/fn-header-semantic-fail.rs:52:19
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -130,7 +86,7 @@ LL |         fn fe2();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:55:18
+  --> $DIR/fn-header-semantic-fail.rs:53:18
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -144,7 +100,7 @@ LL |         fn fe3();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:56:23
+  --> $DIR/fn-header-semantic-fail.rs:54:23
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -158,7 +114,7 @@ LL |         fn fe4();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:57:42
+  --> $DIR/fn-header-semantic-fail.rs:55:42
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -172,7 +128,7 @@ LL |         fn fe5();
    |         ~~
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:57:9
+  --> $DIR/fn-header-semantic-fail.rs:55:9
    |
 LL |         const async unsafe extern "C" fn fe5();
    |         ^^^^^-^^^^^----------------------------
@@ -180,6 +136,58 @@ LL |         const async unsafe extern "C" fn fe5();
    |         |     `async` because of this
    |         `const` because of this
 
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:17:9
+   |
+LL |         async fn ft1();
+   |         -----^^^^^^^^^^
+   |         |
+   |         `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:21:9
+   |
+LL |         const async unsafe extern "C" fn ft5();
+   |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |               |
+   |               `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:29:9
+   |
+LL |         async fn ft1() {}
+   |         -----^^^^^^^^^
+   |         |
+   |         `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:33:9
+   |
+LL |         const async unsafe extern "C" fn ft5() {}
+   |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |               |
+   |               `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
 error[E0391]: cycle detected when computing type of `main::ff5::{opaque#0}`
   --> $DIR/fn-header-semantic-fail.rs:12:44
    |
@@ -216,60 +224,24 @@ LL | |     }
 LL | | }
    | |_^
 
-error[E0053]: method `ft1` has an incompatible type for trait
-  --> $DIR/fn-header-semantic-fail.rs:29:24
-   |
-LL |         async fn ft1() {}
-   |                        ^
-   |                        |
-   |                        checked the `Output` of this `async fn`, found opaque type
-   |                        expected `()`, found opaque type
-   |
-   = note: while checking the return type of the `async fn`
-note: type in trait
-  --> $DIR/fn-header-semantic-fail.rs:17:23
-   |
-LL |         async fn ft1();
-   |                       ^
-   = note: expected fn pointer `fn()`
-              found fn pointer `fn() -> impl Future<Output = ()>`
-
-error[E0053]: method `ft5` has an incompatible type for trait
-  --> $DIR/fn-header-semantic-fail.rs:34:48
-   |
-LL |         const async unsafe extern "C" fn ft5() {}
-   |                                                ^
-   |                                                |
-   |                                                checked the `Output` of this `async fn`, found opaque type
-   |                                                expected `()`, found opaque type
-   |
-   = note: while checking the return type of the `async fn`
-note: type in trait
-  --> $DIR/fn-header-semantic-fail.rs:21:47
-   |
-LL |         const async unsafe extern "C" fn ft5();
-   |                                               ^
-   = note: expected fn pointer `unsafe extern "C" fn()`
-              found fn pointer `unsafe extern "C" fn() -> impl Future<Output = ()>`
-
 error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}`
-  --> $DIR/fn-header-semantic-fail.rs:34:48
+  --> $DIR/fn-header-semantic-fail.rs:33:48
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |                                                ^
    |
 note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5`...
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:33:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5`...
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:33:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5`...
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:33:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -288,30 +260,30 @@ LL | |     }
 LL | | }
    | |_^
 
-error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 42:11>::fi5::{opaque#0}`
-  --> $DIR/fn-header-semantic-fail.rs:47:48
+error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}`
+  --> $DIR/fn-header-semantic-fail.rs:45:48
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |                                                ^
    |
-note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 42:11>::fi5`...
-  --> $DIR/fn-header-semantic-fail.rs:47:9
+note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5`...
+  --> $DIR/fn-header-semantic-fail.rs:45:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 42:11>::fi5`...
-  --> $DIR/fn-header-semantic-fail.rs:47:9
+note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5`...
+  --> $DIR/fn-header-semantic-fail.rs:45:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 42:11>::fi5`...
-  --> $DIR/fn-header-semantic-fail.rs:47:9
+note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5`...
+  --> $DIR/fn-header-semantic-fail.rs:45:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
    = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
-   = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 42:11>::fi5::{opaque#0}`, completing the cycle
+   = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in top-level module
   --> $DIR/fn-header-semantic-fail.rs:5:1
    |
@@ -324,7 +296,7 @@ LL | |     }
 LL | | }
    | |_^
 
-error: aborting due to 23 previous errors
+error: aborting due to 21 previous errors
 
-Some errors have detailed explanations: E0053, E0379, E0391, E0706.
-For more information about an error, try `rustc --explain E0053`.
+Some errors have detailed explanations: E0379, E0391, E0706.
+For more information about an error, try `rustc --explain E0379`.
diff --git a/src/test/ui/parser/issue-101477-enum.fixed b/src/test/ui/parser/issue-101477-enum.fixed
new file mode 100644 (file)
index 0000000..1dfeae2
--- /dev/null
@@ -0,0 +1,10 @@
+// run-rustfix
+
+#[allow(dead_code)]
+enum Demo {
+    A = 1,
+    B = 2 //~ ERROR unexpected `==`
+    //~^ expected item, found `==`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-101477-enum.rs b/src/test/ui/parser/issue-101477-enum.rs
new file mode 100644 (file)
index 0000000..ea7051d
--- /dev/null
@@ -0,0 +1,10 @@
+// run-rustfix
+
+#[allow(dead_code)]
+enum Demo {
+    A = 1,
+    B == 2 //~ ERROR unexpected `==`
+    //~^ expected item, found `==`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-101477-enum.stderr b/src/test/ui/parser/issue-101477-enum.stderr
new file mode 100644 (file)
index 0000000..bffc881
--- /dev/null
@@ -0,0 +1,14 @@
+error: unexpected `==`
+  --> $DIR/issue-101477-enum.rs:6:7
+   |
+LL |     B == 2
+   |       ^^ help: try using `=` instead
+
+error: expected item, found `==`
+  --> $DIR/issue-101477-enum.rs:6:7
+   |
+LL |     B == 2
+   |       ^^ expected item
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/issue-101477-let.fixed b/src/test/ui/parser/issue-101477-let.fixed
new file mode 100644 (file)
index 0000000..9989ad8
--- /dev/null
@@ -0,0 +1,6 @@
+// run-rustfix
+
+fn main() {
+    let x = 2; //~ ERROR unexpected `==`
+    println!("x: {}", x)
+}
diff --git a/src/test/ui/parser/issue-101477-let.rs b/src/test/ui/parser/issue-101477-let.rs
new file mode 100644 (file)
index 0000000..8b0e8be
--- /dev/null
@@ -0,0 +1,6 @@
+// run-rustfix
+
+fn main() {
+    let x == 2; //~ ERROR unexpected `==`
+    println!("x: {}", x)
+}
diff --git a/src/test/ui/parser/issue-101477-let.stderr b/src/test/ui/parser/issue-101477-let.stderr
new file mode 100644 (file)
index 0000000..1b30d4b
--- /dev/null
@@ -0,0 +1,8 @@
+error: unexpected `==`
+  --> $DIR/issue-101477-let.rs:4:11
+   |
+LL |     let x == 2;
+   |           ^^ help: try using `=` instead
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/issues/issue-14303-enum.rs b/src/test/ui/parser/issues/issue-14303-enum.rs
deleted file mode 100644 (file)
index a610615..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-enum X<'a, T, 'b> {
-//~^ ERROR lifetime parameters must be declared prior to type parameters
-    A(&'a &'b T)
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/issues/issue-14303-enum.stderr b/src/test/ui/parser/issues/issue-14303-enum.stderr
deleted file mode 100644 (file)
index 55cef4c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: lifetime parameters must be declared prior to type parameters
-  --> $DIR/issue-14303-enum.rs:1:15
-   |
-LL | enum X<'a, T, 'b> {
-   |       --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/parser/issues/issue-14303-fn-def.rs b/src/test/ui/parser/issues/issue-14303-fn-def.rs
deleted file mode 100644 (file)
index 221bd31..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-fn foo<'a, T, 'b>(x: &'a T) {}
-//~^ ERROR lifetime parameters must be declared prior to type parameters
-
-fn main() {}
diff --git a/src/test/ui/parser/issues/issue-14303-fn-def.stderr b/src/test/ui/parser/issues/issue-14303-fn-def.stderr
deleted file mode 100644 (file)
index bacc922..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: lifetime parameters must be declared prior to type parameters
-  --> $DIR/issue-14303-fn-def.rs:1:15
-   |
-LL | fn foo<'a, T, 'b>(x: &'a T) {}
-   |       --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/parser/issues/issue-14303-impl.rs b/src/test/ui/parser/issues/issue-14303-impl.rs
deleted file mode 100644 (file)
index 4dc2c66..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-struct X<T>(T);
-
-impl<'a, T, 'b> X<T> {}
-//~^ ERROR lifetime parameters must be declared prior to type parameters
-
-fn main() {}
diff --git a/src/test/ui/parser/issues/issue-14303-impl.stderr b/src/test/ui/parser/issues/issue-14303-impl.stderr
deleted file mode 100644 (file)
index d6be02f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: lifetime parameters must be declared prior to type parameters
-  --> $DIR/issue-14303-impl.rs:3:13
-   |
-LL | impl<'a, T, 'b> X<T> {}
-   |     --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/parser/issues/issue-14303-path.rs b/src/test/ui/parser/issues/issue-14303-path.rs
deleted file mode 100644 (file)
index 89ef914..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-mod foo {
-    pub struct X<'a, 'b, 'c, T> {
-        a: &'a str,
-        b: &'b str,
-        c: &'c str,
-        t: T,
-    }
-}
-
-fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {}
-//~^ ERROR type provided when a lifetime was expected
-
-fn main() {}
diff --git a/src/test/ui/parser/issues/issue-14303-path.stderr b/src/test/ui/parser/issues/issue-14303-path.stderr
deleted file mode 100644 (file)
index 841e63e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0747]: type provided when a lifetime was expected
-  --> $DIR/issue-14303-path.rs:10:37
-   |
-LL | fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {}
-   |                                     ^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/ui/parser/issues/issue-14303-struct.rs b/src/test/ui/parser/issues/issue-14303-struct.rs
deleted file mode 100644 (file)
index 0bd10b4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-struct X<'a, T, 'b> {
-//~^ ERROR lifetime parameters must be declared prior to type parameters
-    x: &'a &'b T
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/issues/issue-14303-struct.stderr b/src/test/ui/parser/issues/issue-14303-struct.stderr
deleted file mode 100644 (file)
index fa62a39..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: lifetime parameters must be declared prior to type parameters
-  --> $DIR/issue-14303-struct.rs:1:17
-   |
-LL | struct X<'a, T, 'b> {
-   |         --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/parser/issues/issue-14303-trait.rs b/src/test/ui/parser/issues/issue-14303-trait.rs
deleted file mode 100644 (file)
index f253de9..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-trait Foo<'a, T, 'b> {}
-//~^ ERROR lifetime parameters must be declared prior to type parameters
-
-fn main() {}
diff --git a/src/test/ui/parser/issues/issue-14303-trait.stderr b/src/test/ui/parser/issues/issue-14303-trait.stderr
deleted file mode 100644 (file)
index 75cd67a..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: lifetime parameters must be declared prior to type parameters
-  --> $DIR/issue-14303-trait.rs:1:18
-   |
-LL | trait Foo<'a, T, 'b> {}
-   |          --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/parser/issues/issue-14303.rs b/src/test/ui/parser/issues/issue-14303.rs
new file mode 100644 (file)
index 0000000..82850d7
--- /dev/null
@@ -0,0 +1,33 @@
+enum Enum<'a, T, 'b> {
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
+    A(&'a &'b T)
+}
+
+struct Struct<'a, T, 'b> {
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
+    x: &'a &'b T
+}
+
+trait Trait<'a, T, 'b> {}
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
+
+fn foo<'a, T, 'b>(x: &'a T) {}
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
+
+struct Y<T>(T);
+impl<'a, T, 'b> Y<T> {}
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
+
+mod bar {
+    pub struct X<'a, 'b, 'c, T> {
+        a: &'a str,
+        b: &'b str,
+        c: &'c str,
+        t: T,
+    }
+}
+
+fn bar<'a, 'b, 'c, T>(x: bar::X<'a, T, 'b, 'c>) {}
+//~^ ERROR type provided when a lifetime was expected
+
+fn main() {}
diff --git a/src/test/ui/parser/issues/issue-14303.stderr b/src/test/ui/parser/issues/issue-14303.stderr
new file mode 100644 (file)
index 0000000..f121107
--- /dev/null
@@ -0,0 +1,39 @@
+error: lifetime parameters must be declared prior to type and const parameters
+  --> $DIR/issue-14303.rs:1:18
+   |
+LL | enum Enum<'a, T, 'b> {
+   |          --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
+
+error: lifetime parameters must be declared prior to type and const parameters
+  --> $DIR/issue-14303.rs:6:22
+   |
+LL | struct Struct<'a, T, 'b> {
+   |              --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
+
+error: lifetime parameters must be declared prior to type and const parameters
+  --> $DIR/issue-14303.rs:11:20
+   |
+LL | trait Trait<'a, T, 'b> {}
+   |            --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
+
+error: lifetime parameters must be declared prior to type and const parameters
+  --> $DIR/issue-14303.rs:14:15
+   |
+LL | fn foo<'a, T, 'b>(x: &'a T) {}
+   |       --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
+
+error: lifetime parameters must be declared prior to type and const parameters
+  --> $DIR/issue-14303.rs:18:13
+   |
+LL | impl<'a, T, 'b> Y<T> {}
+   |     --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
+
+error[E0747]: type provided when a lifetime was expected
+  --> $DIR/issue-14303.rs:30:37
+   |
+LL | fn bar<'a, 'b, 'c, T>(x: bar::X<'a, T, 'b, 'c>) {}
+   |                                     ^
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/ui/parser/suggest-semicolon-before-array.fixed b/src/test/ui/parser/suggest-semicolon-before-array.fixed
new file mode 100644 (file)
index 0000000..a06b58b
--- /dev/null
@@ -0,0 +1,11 @@
+// run-rustfix
+#![allow(dead_code)]
+
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+    foo();
+    [1, 3] //~ ERROR expected `;`, found `[`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/suggest-semicolon-before-array.rs b/src/test/ui/parser/suggest-semicolon-before-array.rs
new file mode 100644 (file)
index 0000000..f601ca2
--- /dev/null
@@ -0,0 +1,11 @@
+// run-rustfix
+#![allow(dead_code)]
+
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+    foo()
+    [1, 3] //~ ERROR expected `;`, found `[`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/suggest-semicolon-before-array.stderr b/src/test/ui/parser/suggest-semicolon-before-array.stderr
new file mode 100644 (file)
index 0000000..8a33321
--- /dev/null
@@ -0,0 +1,13 @@
+error: expected `;`, found `[`
+  --> $DIR/suggest-semicolon-before-array.rs:8:5
+   |
+LL |     [1, 3]
+   |     ^
+   |
+help: consider adding `;` here
+   |
+LL |     foo();
+   |          +
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed b/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed
deleted file mode 100644 (file)
index a06b58b..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// run-rustfix
-#![allow(dead_code)]
-
-fn foo() {}
-
-fn bar() -> [u8; 2] {
-    foo();
-    [1, 3] //~ ERROR expected `;`, found `[`
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs
deleted file mode 100644 (file)
index f601ca2..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// run-rustfix
-#![allow(dead_code)]
-
-fn foo() {}
-
-fn bar() -> [u8; 2] {
-    foo()
-    [1, 3] //~ ERROR expected `;`, found `[`
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr
deleted file mode 100644 (file)
index bf86b43..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-error: expected `;`, found `[`
-  --> $DIR/suggest-suggest-semicolon-before-array.rs:8:5
-   |
-LL |     [1, 3]
-   |     ^
-   |
-help: consider adding `;` here
-   |
-LL |     foo();
-   |          +
-
-error: aborting due to previous error
-
index 4249a74b3ed62d3f77a37c361cb53cea9e68335b..fad84dda0e192ea46dec8291315542d205cb6585 100644 (file)
@@ -40,9 +40,8 @@ error[E0382]: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14
    |
 LL |         Some(ref _y @ _z) => {}
-   |              ^^^^^^^^^--
-   |              |        |
-   |              |        value moved here
+   |              ^^^^^^   -- value moved here
+   |              |
    |              value borrowed here after move
    |
    = note: move occurs because value has type `X`, which does not implement the `Copy` trait
@@ -55,9 +54,8 @@ error[E0382]: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
    |
 LL |         Some(ref mut _y @ _z) => {}
-   |              ^^^^^^^^^^^^^--
-   |              |            |
-   |              |            value moved here
+   |              ^^^^^^^^^^   -- value moved here
+   |              |
    |              value borrowed here after move
    |
    = note: move occurs because value has type `X`, which does not implement the `Copy` trait
index ee0885a014aa44c15ccdbb2d2f20d4e1b2584a55..a481ca46833827fc64cc0ee58cc6b23f4a2ca246 100644 (file)
@@ -2,9 +2,8 @@ error[E0382]: use of partially moved value
   --> $DIR/bind-by-move-no-subbindings-fun-param.rs:7:6
    |
 LL | fn f(a @ A(u): A) -> Box<u8> {
-   |      ^^^^^^-^
-   |      |     |
-   |      |     value partially moved here
+   |      ^     - value partially moved here
+   |      |
    |      value used here after partial move
    |
    = note: partial move occurs because value has type `Box<u8>`, which does not implement the `Copy` trait
index 8e00bf5c328be6fcac7781d88d090c0447ceec45..83751843b1b81b09741d51eac2d4a17e802d1d94 100644 (file)
@@ -2,7 +2,7 @@ error[E0382]: use of moved value
   --> $DIR/borrowck-move-and-move.rs:11:9
    |
 LL |     let a @ b = U;
-   |         ^^^^-   - move occurs because value has type `U`, which does not implement the `Copy` trait
+   |         ^   -   - move occurs because value has type `U`, which does not implement the `Copy` trait
    |         |   |
    |         |   value moved here
    |         value used here after move
@@ -11,9 +11,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:13:9
    |
 LL |     let a @ (b, c) = (U, U);
-   |         ^^^^^^^^-^
-   |         |       |
-   |         |       value partially moved here
+   |         ^       - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -22,9 +21,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:15:9
    |
 LL |     let a @ (b, c) = (u(), u());
-   |         ^^^^^^^^-^
-   |         |       |
-   |         |       value partially moved here
+   |         ^       - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -35,9 +33,8 @@ error[E0382]: use of moved value
 LL |     match Ok(U) {
    |           ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait
 LL |         a @ Ok(b) | a @ Err(b) => {}
-   |         -------^-
-   |         |      |
-   |         |      value used here after move
+   |         -      ^ value used here after move
+   |         |
    |         value moved here
 
 error[E0382]: use of moved value
@@ -46,18 +43,16 @@ error[E0382]: use of moved value
 LL |     match Ok(U) {
    |           ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait
 LL |         a @ Ok(b) | a @ Err(b) => {}
-   |                     --------^-
-   |                     |       |
-   |                     |       value used here after move
+   |                     -       ^ value used here after move
+   |                     |
    |                     value moved here
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:25:9
    |
 LL |         xs @ [a, .., b] => {}
-   |         ^^^^^^^^^^^^^-^
-   |         |            |
-   |         |            value partially moved here
+   |         ^^           - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -66,9 +61,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:29:9
    |
 LL |         xs @ [_, ys @ .., _] => {}
-   |         ^^^^^^^^^-------^^^^
-   |         |        |
-   |         |        value partially moved here
+   |         ^^       -- value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -77,7 +71,7 @@ error[E0382]: use of moved value
   --> $DIR/borrowck-move-and-move.rs:22:12
    |
 LL |     fn fun(a @ b: U) {}
-   |            ^^^^-
+   |            ^----
    |            |   |
    |            |   value moved here
    |            value used here after move
index 4b2048855ebb42ea383307b3044892872c6e85d0..002c7609f61093c6c3c499a14a7a6f88c7ffc1d1 100644 (file)
@@ -74,9 +74,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-at-and-box.rs:31:9
    |
 LL |     let ref a @ box b = Box::new(NC);
-   |         ^^^^^^^^^^^^-
-   |         |           |
-   |         |           value moved here
+   |         ^^^^^       - value moved here
+   |         |
    |         value borrowed here after move
    |
    = note: move occurs because value has type `NC`, which does not implement the `Copy` trait
@@ -85,9 +84,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-at-and-box.rs:38:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
-   |         ^^^^^^^^^^^^---------
-   |         |           |
-   |         |           mutable borrow occurs here
+   |         ^^^^^       --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = NC;
@@ -97,9 +95,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-at-and-box.rs:42:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
-   |         ^^^^^^^^^^^^---------
-   |         |           |
-   |         |           mutable borrow occurs here
+   |         ^^^^^       --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = NC;
@@ -109,9 +106,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-at-and-box.rs:48:9
    |
 LL |     let ref mut a @ box ref b = Box::new(NC);
-   |         ^^^^^^^^^^^^^^^^-----
-   |         |               |
-   |         |               immutable borrow occurs here
+   |         ^^^^^^^^^       ----- immutable borrow occurs here
+   |         |
    |         mutable borrow occurs here
 ...
 LL |     drop(b);
@@ -121,9 +117,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-at-and-box.rs:62:9
    |
 LL |         ref mut a @ box ref b => {
-   |         ^^^^^^^^^^^^^^^^-----
-   |         |               |
-   |         |               immutable borrow occurs here
+   |         ^^^^^^^^^       ----- immutable borrow occurs here
+   |         |
    |         mutable borrow occurs here
 ...
 LL |             drop(b);
@@ -133,9 +128,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-at-and-box.rs:54:11
    |
 LL |     fn f5(ref mut a @ box ref b: Box<NC>) {
-   |           ^^^^^^^^^^^^^^^^-----
-   |           |               |
-   |           |               immutable borrow occurs here
+   |           ^^^^^^^^^       ----- immutable borrow occurs here
+   |           |
    |           mutable borrow occurs here
 ...
 LL |         drop(b);
index bc2c1625fd0ef7275da5b1526ff92d4da7d45b9c..a9e66de084242f560ae2e78d0683f85fc44ca4b1 100644 (file)
@@ -262,9 +262,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^---------^
-   |         |                       |
-   |         |                       value partially moved here
+   |         ^                       - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -273,9 +272,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^---------^
-   |         |                       |
-   |         |                       value partially moved here
+   |         ^                       - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -286,10 +284,7 @@ error[E0382]: use of moved value
 LL |     match Some((U, U)) {
    |           ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
-   |         -----------------------------^^^^^^^^^--
-   |         |                            |
-   |         |                            value used here after move
-   |         value moved here
+   |         - value moved here           ^ value used here after move
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:30
@@ -297,9 +292,8 @@ error[E0382]: borrow of moved value
 LL |     match Some([U, U]) {
    |           ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
 LL |         mut a @ Some([ref b, ref mut c]) => {}
-   |         ---------------------^^^^^^^^^--
-   |         |                    |
-   |         |                    value borrowed here after move
+   |         -----                ^^^^^^^^^ value borrowed here after move
+   |         |
    |         value moved here
 
 error[E0382]: borrow of moved value
@@ -308,9 +302,8 @@ error[E0382]: borrow of moved value
 LL |     match Some(u()) {
    |           --------- move occurs because value has type `Option<U>`, which does not implement the `Copy` trait
 LL |         a @ Some(ref b) => {}
-   |         ---------^^^^^-
-   |         |        |
-   |         |        value borrowed here after move
+   |         -        ^^^^^ value borrowed here after move
+   |         |
    |         value moved here
 
 error[E0382]: use of moved value
@@ -319,10 +312,7 @@ error[E0382]: use of moved value
 LL |     match Some((u(), u())) {
    |           ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
-   |         -----------------------------^^^^^^^^^--
-   |         |                            |
-   |         |                            value used here after move
-   |         value moved here
+   |         - value moved here           ^ value used here after move
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:30
@@ -330,18 +320,16 @@ error[E0382]: borrow of moved value
 LL |     match Some([u(), u()]) {
    |           ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
 LL |         mut a @ Some([ref b, ref mut c]) => {}
-   |         ---------------------^^^^^^^^^--
-   |         |                    |
-   |         |                    value borrowed here after move
+   |         -----                ^^^^^^^^^ value borrowed here after move
+   |         |
    |         value moved here
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
-   |           ^^^^^^^^^^^^^^^^^^^^-------------^
-   |           |                   |
-   |           |                   value partially moved here
+   |           ^^^^^               ----- value partially moved here
+   |           |
    |           value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
index c019aae3dfc9c10612e295c0f526433ed92c85c4..e03a9298214e4b55281bd21e0b50563fbd5c11e3 100644 (file)
@@ -237,9 +237,8 @@ error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
    |
 LL |     let ref mut a @ [b, mut c] = [U, U];
-   |         ^^^^^^^^^^^^^^^^-----^
-   |         |               |
-   |         |               value partially moved here
+   |         ^^^^^^^^^       ----- value partially moved here
+   |         |
    |         value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -248,7 +247,7 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
    |
 LL |     let ref a @ b = u();
-   |         ^^^^^^^^-   --- move occurs because value has type `U`, which does not implement the `Copy` trait
+   |         ^^^^^   -   --- move occurs because value has type `U`, which does not implement the `Copy` trait
    |         |       |
    |         |       value moved here
    |         value borrowed here after move
@@ -257,9 +256,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
-   |                  ^^^^^^^^-----
-   |                  |       |
-   |                  |       value moved here
+   |                  ^^^^^   ----- value moved here
+   |                  |
    |                  value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -268,9 +266,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
-   |                                 ^^^^^^^^-
-   |                                 |       |
-   |                                 |       value moved here
+   |                                 ^^^^^   - value moved here
+   |                                 |
    |                                 value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -279,9 +276,8 @@ error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
    |
 LL |     let ref mut a @ [b, mut c] = [u(), u()];
-   |         ^^^^^^^^^^^^^^^^-----^
-   |         |               |
-   |         |               value partially moved here
+   |         ^^^^^^^^^       ----- value partially moved here
+   |         |
    |         value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -290,9 +286,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
-   |                       ^^^^^^^^-----
-   |                       |       |
-   |                       |       value moved here
+   |                       ^^^^^   ----- value moved here
+   |                       |
    |                       value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -305,9 +300,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
-   |                                      ^^^^^^^^-
-   |                                      |       |
-   |                                      |       value moved here
+   |                                      ^^^^^   - value moved here
+   |                                      |
    |                                      value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -320,7 +314,7 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11
    |
 LL |     fn f1(ref a @ b: U) {}
-   |           ^^^^^^^^-
+   |           ^^^^^----
    |           |       |
    |           |       value moved here
    |           value borrowed here after move
@@ -330,9 +324,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
-   |                    ^^^^^^^^-----
-   |                    |       |
-   |                    |       value moved here
+   |                    ^^^^^   ----- value moved here
+   |                    |
    |                    value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -341,9 +334,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
-   |                                   ^^^^^^^^-
-   |                                   |       |
-   |                                   |       value moved here
+   |                                   ^^^^^   - value moved here
+   |                                   |
    |                                   value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -352,9 +344,8 @@ error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
    |
 LL |     fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
-   |           ^^^^^^^^^^^^^^^^-----^
-   |           |               |
-   |           |               value partially moved here
+   |           ^^^^^^^^^       ----- value partially moved here
+   |           |
    |           value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
index 2ae78d1084e0e4263eb423b8664cdb55b68f109d..9fd5e229afd0a2fd4d5bf0d01efcfbd93496e789 100644 (file)
@@ -298,9 +298,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:31
    |
 LL |         ref mut z @ &mut Some(ref a) => {
-   |         ----------------------^^^^^-
-   |         |                     |
-   |         |                     immutable borrow occurs here
+   |         ---------             ^^^^^ immutable borrow occurs here
+   |         |
    |         mutable borrow occurs here
 ...
 LL |             **z = None;
@@ -310,9 +309,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9
    |
 LL |     let ref mut a @ ref b = u();
-   |         ^^^^^^^^^^^^-----
-   |         |           |
-   |         |           immutable borrow occurs here
+   |         ^^^^^^^^^   ----- immutable borrow occurs here
+   |         |
    |         mutable borrow occurs here
 ...
 LL |     drop(b);
@@ -322,9 +320,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9
    |
 LL |     let ref a @ ref mut b = u();
-   |         ^^^^^^^^---------
-   |         |       |
-   |         |       mutable borrow occurs here
+   |         ^^^^^   --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = u();
@@ -334,9 +331,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:20
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
-   |         -----------^^^^^^^^^-
-   |         |          |
-   |         |          mutable borrow occurs here
+   |         -----      ^^^^^^^^^ mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |             drop(a);
@@ -346,9 +342,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:45
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
-   |                                 ------------^^^^^^^^^-
-   |                                 |           |
-   |                                 |           mutable borrow occurs here
+   |                                 -----       ^^^^^^^^^ mutable borrow occurs here
+   |                                 |
    |                                 immutable borrow occurs here
 ...
 LL |             drop(a);
@@ -406,9 +401,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         ^^^^^^^^^---------^^^^^^^^^^^^
-   |         |        |
-   |         |        mutable borrow occurs here
+   |         ^^^^^    --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = U;
@@ -418,9 +412,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         ^^^^^^^^^---------^^^^^^^^^^^^
-   |         |        |
-   |         |        mutable borrow occurs here
+   |         ^^^^^    --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = U;
@@ -430,9 +423,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         ^^^^^^^^^---------^^^^^^^^^^^^
-   |         |        |
-   |         |        mutable borrow occurs here
+   |         ^^^^^    --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 LL |
 LL |     *b = U;
@@ -442,7 +434,7 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30
    |
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
-   |                      --------^^^^^^^^^^^^-
+   |                      --------^^^^^^^^^----
    |                      |       |           |
    |                      |       |           value moved here
    |                      |       value borrowed here after move
index aa02230419b5e4956577a2b7cb0319c66a98feb8..e47aea9c77e6c1bcf9ed4e8d4bed246f7c69879e 100644 (file)
@@ -262,9 +262,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
    |
 LL |     let ref mut a @ ref mut b = U;
-   |         ^^^^^^^^^^^^---------
-   |         |           |
-   |         |           first mutable borrow occurs here
+   |         ^^^^^^^^^   --------- first mutable borrow occurs here
+   |         |
    |         second mutable borrow occurs here
 ...
 LL |     drop(b);
@@ -274,9 +273,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9
    |
 LL |     let ref mut a @ ref mut b = U;
-   |         ^^^^^^^^^^^^---------
-   |         |           |
-   |         |           first mutable borrow occurs here
+   |         ^^^^^^^^^   --------- first mutable borrow occurs here
+   |         |
    |         second mutable borrow occurs here
 ...
 LL |     *b = U;
@@ -286,9 +284,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:89:24
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |         ---------------^^^^^^^^^-
-   |         |              |
-   |         |              second mutable borrow occurs here
+   |         ---------      ^^^^^^^^^ second mutable borrow occurs here
+   |         |
    |         first mutable borrow occurs here
 ...
 LL |             *a = Err(U);
@@ -298,9 +295,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:89:53
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |                                     ----------------^^^^^^^^^-
-   |                                     |               |
-   |                                     |               second mutable borrow occurs here
+   |                                     ---------       ^^^^^^^^^ second mutable borrow occurs here
+   |                                     |
    |                                     first mutable borrow occurs here
 ...
 LL |             *a = Err(U);
@@ -310,9 +306,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:101:24
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |         ---------------^^^^^^^^^-
-   |         |              |
-   |         |              second mutable borrow occurs here
+   |         ---------      ^^^^^^^^^ second mutable borrow occurs here
+   |         |
    |         first mutable borrow occurs here
 ...
 LL |             drop(a);
@@ -322,9 +317,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:101:53
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |                                     ----------------^^^^^^^^^-
-   |                                     |               |
-   |                                     |               second mutable borrow occurs here
+   |                                     ---------       ^^^^^^^^^ second mutable borrow occurs here
+   |                                     |
    |                                     first mutable borrow occurs here
 ...
 LL |             drop(a);
@@ -334,7 +328,7 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34
    |
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
-   |                      ------------^^^^^^^^^^^^-
+   |                      ------------^^^^^^^^^----
    |                      |           |           |
    |                      |           |           value moved here
    |                      |           value borrowed here after move
index d290144b6155a6fa9cbf449c530737a8460f3200..cd3234952fa54c13db85096ca76839836285d706 100644 (file)
@@ -2,9 +2,8 @@ error[E0382]: use of partially moved value
   --> $DIR/copy-and-move-mixed.rs:12:9
    |
 LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
-   |         ^^^^^^^^^^------------^
-   |         |         |
-   |         |         value partially moved here
+   |         ^         - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait
index d78faa682b5078f5590a78e8743183de2597cd84..840a513d6c67d5595e4432f5067f09f33099c2a9 100644 (file)
@@ -48,7 +48,7 @@ error[E0382]: borrow of moved value
   --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
    |
 LL |     let ref mut a @ b = NotCopy;
-   |         ^^^^^^^^^^^^-   ------- move occurs because value has type `NotCopy`, which does not implement the `Copy` trait
+   |         ^^^^^^^^^   -   ------- move occurs because value has type `NotCopy`, which does not implement the `Copy` trait
    |         |           |
    |         |           value moved here
    |         value borrowed here after move
index 3180bd0afc10492fecd61808999343a6e57e4c58..70beb5d423223888072bf6072c552320a1d5c96b 100644 (file)
@@ -11,7 +11,7 @@ error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutab
   --> $DIR/nested-binding-modes-mut.rs:9:5
    |
 LL |     let not_mut @ mut is_mut = 42;
-   |         -------------------- help: consider changing this to be mutable: `mut not_mut`
+   |         ------- help: consider changing this to be mutable: `mut not_mut`
 LL |     &mut is_mut;
 LL |     &mut not_mut;
    |     ^^^^^^^^^^^^ cannot borrow as mutable
index 5beca04d285901aafc840a7b0aba00f63903e7f7..bac2db6ce825c5964f1aff96cffde29a513ebe1a 100644 (file)
@@ -35,7 +35,7 @@ error[E0502]: cannot borrow `arr[..]` as mutable because it is also borrowed as
   --> $DIR/borrowck-move-ref-pattern.rs:13:16
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
-   |                             ---------------- immutable borrow occurs here
+   |                             ----------- immutable borrow occurs here
 ...
 LL |     let [_, _, ref mut _x2, _x3, mut _x4] = arr;
    |                ^^^^^^^^^^^ mutable borrow occurs here
@@ -47,7 +47,7 @@ error[E0505]: cannot move out of `arr[..]` because it is borrowed
   --> $DIR/borrowck-move-ref-pattern.rs:13:29
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
-   |                             ---------------- borrow of `arr[..]` occurs here
+   |                             ----------- borrow of `arr[..]` occurs here
 ...
 LL |     let [_, _, ref mut _x2, _x3, mut _x4] = arr;
    |                             ^^^ move out of `arr[..]` occurs here
@@ -59,7 +59,7 @@ error[E0505]: cannot move out of `arr[..]` because it is borrowed
   --> $DIR/borrowck-move-ref-pattern.rs:13:34
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
-   |                             ---------------- borrow of `arr[..]` occurs here
+   |                             ----------- borrow of `arr[..]` occurs here
 ...
 LL |     let [_, _, ref mut _x2, _x3, mut _x4] = arr;
    |                                  ^^^^^^^ move out of `arr[..]` occurs here
diff --git a/src/test/ui/repr/invalid_repr_list_help.rs b/src/test/ui/repr/invalid_repr_list_help.rs
new file mode 100644 (file)
index 0000000..c320984
--- /dev/null
@@ -0,0 +1,17 @@
+#![crate_type = "lib"]
+
+#[repr(uwu)] //~ERROR: unrecognized representation hint
+pub struct OwO;
+
+#[repr(uwu = "a")] //~ERROR: unrecognized representation hint
+pub struct OwO2(i32);
+
+#[repr(uwu(4))] //~ERROR: unrecognized representation hint
+pub struct OwO3 {
+    x: i32,
+}
+
+#[repr(uwu, u8)] //~ERROR: unrecognized representation hint
+pub enum OwO4 {
+    UwU = 1,
+}
diff --git a/src/test/ui/repr/invalid_repr_list_help.stderr b/src/test/ui/repr/invalid_repr_list_help.stderr
new file mode 100644 (file)
index 0000000..2acd56d
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0552]: unrecognized representation hint
+  --> $DIR/invalid_repr_list_help.rs:3:8
+   |
+LL | #[repr(uwu)]
+   |        ^^^
+   |
+   = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error[E0552]: unrecognized representation hint
+  --> $DIR/invalid_repr_list_help.rs:6:8
+   |
+LL | #[repr(uwu = "a")]
+   |        ^^^^^^^^^
+   |
+   = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error[E0552]: unrecognized representation hint
+  --> $DIR/invalid_repr_list_help.rs:9:8
+   |
+LL | #[repr(uwu(4))]
+   |        ^^^^^^
+   |
+   = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error[E0552]: unrecognized representation hint
+  --> $DIR/invalid_repr_list_help.rs:14:8
+   |
+LL | #[repr(uwu, u8)]
+   |        ^^^
+   |
+   = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0552`.
index aaf0f7eaef0dcdd3969dcb3d743d0b4fba8f69f0..49462f52fb4c2355375bd633eb76b28dcd730501 100644 (file)
@@ -14,7 +14,6 @@ trait B {
 impl B for A {
     async fn associated(); //~ ERROR without body
     //~^ ERROR cannot be declared `async`
-    //~| ERROR has an incompatible type for trait
 }
 
 fn main() {}
index d3214458eac13cc8f89bedfcf498812c5aad6116..55c3b66f1363df29fbb58a8bd48d844aa9ff699d 100644 (file)
@@ -14,17 +14,6 @@ LL |     async fn inherent();
    |                        |
    |                        help: provide a definition for the function: `{ <body> }`
 
-error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:5
-   |
-LL |     async fn associated();
-   |     -----^^^^^^^^^^^^^^^^^
-   |     |
-   |     `async` because of this
-   |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 error: associated function in `impl` without body
   --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5
    |
@@ -34,7 +23,7 @@ LL |     async fn associated();
    |                          help: provide a definition for the function: `{ <body> }`
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:5
    |
 LL |     async fn associated();
    |     -----^^^^^^^^^^^^^^^^^
@@ -43,26 +32,22 @@ LL |     async fn associated();
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
-error[E0053]: method `associated` has an incompatible type for trait
-  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:26
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5
    |
 LL |     async fn associated();
-   |                          ^
-   |                          |
-   |                          checked the `Output` of this `async fn`, found opaque type
-   |                          expected `()`, found opaque type
-   |
-   = note: while checking the return type of the `async fn`
-note: type in trait
-  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:26
+   |     -----^^^^^^^^^^^^^^^^^
+   |     |
+   |     `async` because of this
    |
-LL |     async fn associated();
-   |                          ^
-   = note: expected fn pointer `fn()`
-              found fn pointer `fn() -> impl Future<Output = ()>`
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0053, E0706.
-For more information about an error, try `rustc --explain E0053`.
+For more information about this error, try `rustc --explain E0706`.
index 9e739c02dc8e7c64139120bbd35d014e72eea853..22d57f8bedddc01a6981693d58a4b2643dd2e021 100644 (file)
@@ -1,7 +1,6 @@
 // only-windows
 // only-x86
 #![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
 
 #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)]
 //~^ ERROR import name type must be of the form `import_name_type = "string"`
index ee10b0114a47822b18cbc2768e0e9454c90d8d74..0e95fec29d2575087e17fbfdb52dd1752f167727 100644 (file)
@@ -1,17 +1,8 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/import-name-type-invalid-format.rs:3:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: import name type must be of the form `import_name_type = "string"`
-  --> $DIR/import-name-type-invalid-format.rs:6:42
+  --> $DIR/import-name-type-invalid-format.rs:5:42
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)]
    |                                          ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
index c404dbae46866b8feab0d279a665efdedadae98b..7ccb0082fb976d78fa587c07bd73f10e0e6c8b2a 100644 (file)
@@ -2,7 +2,6 @@
 // only-windows
 // only-x86
 #![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
 
 #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")]
 //~^ ERROR multiple `import_name_type` arguments in a single `#[link]` attribute
index 936c8aa7359679ce3852ed5439f54734b7c5f444..7c0e0be911f73fb0ad00c29b45e376448e667a06 100644 (file)
@@ -1,17 +1,8 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/import-name-type-multiple.rs:4:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: multiple `import_name_type` arguments in a single `#[link]` attribute
-  --> $DIR/import-name-type-multiple.rs:7:74
+  --> $DIR/import-name-type-multiple.rs:6:74
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")]
    |                                                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
index 350b0294641ab85c52f83c94f73c408528902da2..f728a578d3b8a7bb5624b520e847f7621ebd9786 100644 (file)
@@ -1,7 +1,6 @@
 // only-windows
 // only-x86
 #![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
 
 #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")]
 //~^ ERROR unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated
index b6871a0d317025bd2e82e04bbfb7f38761458872..2b299f2fea316c6da4395e1de73851761b52fdf0 100644 (file)
@@ -1,17 +1,8 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/import-name-type-unknown-value.rs:3:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated
-  --> $DIR/import-name-type-unknown-value.rs:6:42
+  --> $DIR/import-name-type-unknown-value.rs:5:42
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")]
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
index b467917bacc3a13eeae618dd4fffd9ba440cc081..ae9207864a2aea0c8a55832dfda7acf22573aafd 100644 (file)
@@ -1,7 +1,6 @@
 // only-windows
 // only-x86
 #![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
 
 #[link(name = "foo", import_name_type = "decorated")]
 //~^ ERROR import name type can only be used with link kind `raw-dylib`
index c35333fb88df89df9b196cba8daba516c9c5ace1..5898cd875a1c852fe4d4c6523396e30570001620 100644 (file)
@@ -1,23 +1,14 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/import-name-type-unsupported-link-kind.rs:3:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: import name type can only be used with link kind `raw-dylib`
-  --> $DIR/import-name-type-unsupported-link-kind.rs:6:22
+  --> $DIR/import-name-type-unsupported-link-kind.rs:5:22
    |
 LL | #[link(name = "foo", import_name_type = "decorated")]
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: import name type can only be used with link kind `raw-dylib`
-  --> $DIR/import-name-type-unsupported-link-kind.rs:10:39
+  --> $DIR/import-name-type-unsupported-link-kind.rs:9:39
    |
 LL | #[link(name = "bar", kind = "static", import_name_type = "decorated")]
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
index 4e6de7d6ac37c1b9f17258bbeeb8908e6a170a61..346ea18a8f8eb6fc1d1106cdff53782a63aaf138 100644 (file)
@@ -1,7 +1,5 @@
 // only-windows
 // ignore-x86
-#![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
 #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
 //~^ ERROR import name type is only supported on x86
 extern "C" { }
index d8a585145a73ebaf5a2e00c0e85cef00558d29fc..b56449299b71e8ea9b79829aebcf674826a8d2df 100644 (file)
@@ -1,17 +1,8 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/import-name-type-x86-only.rs:3:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: import name type is only supported on x86
-  --> $DIR/import-name-type-x86-only.rs:5:42
+  --> $DIR/import-name-type-x86-only.rs:3:42
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
index 77f425c3e4530200e234caaa7b56c807b3367e79..1a128c87a0c30921eb64f603c0d1ff2512c94620 100644 (file)
@@ -1,5 +1,4 @@
-#![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
+#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[link(name="foo")]
 extern "C" {
index dfe9d031c776d7faec47c722bfb18010663d9934..481a06d2797d5442855af8891cc76fb7d7fe0eb1 100644 (file)
@@ -1,23 +1,14 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/link-ordinal-and-name.rs:1:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: cannot use `#[link_name]` with `#[link_ordinal]`
-  --> $DIR/link-ordinal-and-name.rs:7:5
+  --> $DIR/link-ordinal-and-name.rs:6:5
    |
 LL |     #[link_ordinal(42)]
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: cannot use `#[link_name]` with `#[link_ordinal]`
-  --> $DIR/link-ordinal-and-name.rs:11:5
+  --> $DIR/link-ordinal-and-name.rs:10:5
    |
 LL |     #[link_ordinal(5)]
    |     ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
index 4687fe47f906e0124905f80c74bb4667c0518fc9..7c8da050cf62432ab78128bab9066a7212e5de54 100644 (file)
@@ -1,5 +1,4 @@
-#![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
+#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[link(name = "foo")]
 extern "C" {
index 1d0fad6cb49db11d804eadd71d0bddbf49d1ea3d..55cdcad75a4ad04c17bc0b4ab1476730a3fd0e37 100644 (file)
@@ -1,14 +1,5 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/link-ordinal-invalid-format.rs:1:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: illegal ordinal format in `link_ordinal`
-  --> $DIR/link-ordinal-invalid-format.rs:6:5
+  --> $DIR/link-ordinal-invalid-format.rs:5:5
    |
 LL |     #[link_ordinal("JustMonika")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,12 +7,12 @@ LL |     #[link_ordinal("JustMonika")]
    = note: an unsuffixed integer value, e.g., `1`, is expected
 
 error: illegal ordinal format in `link_ordinal`
-  --> $DIR/link-ordinal-invalid-format.rs:9:5
+  --> $DIR/link-ordinal-invalid-format.rs:8:5
    |
 LL |     #[link_ordinal("JustMonika")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: an unsuffixed integer value, e.g., `1`, is expected
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
index becf2700aebc55518133d133e7e72baa29dd7998..9feed394110467107d22b7054eea4e4d765e5b2c 100644 (file)
@@ -1,5 +1,4 @@
-#![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
+#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[link(name = "foo")]
 extern "C" {
index 5b0ec869d03b8225995fa9b6d8d3cd3ec0c33261..853cdad8c1c541c3397e96e78bb6847d4c0c241b 100644 (file)
@@ -1,14 +1,5 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/link-ordinal-missing-argument.rs:1:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-missing-argument.rs:6:5
+  --> $DIR/link-ordinal-missing-argument.rs:5:5
    |
 LL |     #[link_ordinal()]
    |     ^^^^^^^^^^^^^^^^^
@@ -16,12 +7,12 @@ LL |     #[link_ordinal()]
    = note: the attribute requires exactly one argument
 
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-missing-argument.rs:9:5
+  --> $DIR/link-ordinal-missing-argument.rs:8:5
    |
 LL |     #[link_ordinal()]
    |     ^^^^^^^^^^^^^^^^^
    |
    = note: the attribute requires exactly one argument
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
index 7b07d09e72a5d3b64258a6807c362067cbfef28e..631c363d4ba1594dc06dbfb3f780bc0a88ff11d8 100644 (file)
@@ -1,6 +1,5 @@
 // only-windows
-#![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
+#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[link(name = "foo", kind = "raw-dylib")]
 extern "C" {
index 92a39b3d1b09951672a895cc5e570b72530e9186..c0453d2bf0118edfbc13c91f897cc7a85b72d508 100644 (file)
@@ -1,35 +1,26 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/link-ordinal-multiple.rs:2:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: multiple `link_ordinal` attributes
-  --> $DIR/link-ordinal-multiple.rs:7:5
+  --> $DIR/link-ordinal-multiple.rs:6:5
    |
 LL |     #[link_ordinal(1)]
    |     ^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/link-ordinal-multiple.rs:8:5
+  --> $DIR/link-ordinal-multiple.rs:7:5
    |
 LL |     #[link_ordinal(2)]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: multiple `link_ordinal` attributes
-  --> $DIR/link-ordinal-multiple.rs:10:5
+  --> $DIR/link-ordinal-multiple.rs:9:5
    |
 LL |     #[link_ordinal(1)]
    |     ^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/link-ordinal-multiple.rs:11:5
+  --> $DIR/link-ordinal-multiple.rs:10:5
    |
 LL |     #[link_ordinal(2)]
    |     ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
index 5d273d52a928e41eb3a720f83d7611c764c84028..54e614164b3a50cb52232065f69800061f1ae7b9 100644 (file)
@@ -1,5 +1,4 @@
-#![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
+#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[link_ordinal(123)]
 //~^ ERROR attribute should be applied to a foreign function or static
index 8fa2f16f44df9a4362d31ba95e0fa5aea928fc7b..ec4104fbe50003b623eb704e2c65f0e3f31acb8f 100644 (file)
@@ -1,29 +1,20 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/link-ordinal-not-foreign-fn.rs:1:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: attribute should be applied to a foreign function or static
-  --> $DIR/link-ordinal-not-foreign-fn.rs:4:1
+  --> $DIR/link-ordinal-not-foreign-fn.rs:3:1
    |
 LL | #[link_ordinal(123)]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: attribute should be applied to a foreign function or static
-  --> $DIR/link-ordinal-not-foreign-fn.rs:8:1
+  --> $DIR/link-ordinal-not-foreign-fn.rs:7:1
    |
 LL | #[link_ordinal(123)]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: attribute should be applied to a foreign function or static
-  --> $DIR/link-ordinal-not-foreign-fn.rs:12:1
+  --> $DIR/link-ordinal-not-foreign-fn.rs:11:1
    |
 LL | #[link_ordinal(42)]
    | ^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors
 
index 99d7d9d0b7edabb06785e145dcf4566dee329eeb..46731581ebcb0c2ba29957cfa462ced6f834eb98 100644 (file)
@@ -1,5 +1,4 @@
-#![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
+#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[link(name = "foo")]
 extern "C" {
index 36f278bd85645e09391e9cd488f587b436db270e..fef6de6aedfe45a01c40e7dac0f646df6c346bed 100644 (file)
@@ -1,14 +1,5 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/link-ordinal-too-large.rs:1:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: ordinal value in `link_ordinal` is too large: `72436`
-  --> $DIR/link-ordinal-too-large.rs:6:5
+  --> $DIR/link-ordinal-too-large.rs:5:5
    |
 LL |     #[link_ordinal(72436)]
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -16,12 +7,12 @@ LL |     #[link_ordinal(72436)]
    = note: the value may not exceed `u16::MAX`
 
 error: ordinal value in `link_ordinal` is too large: `72436`
-  --> $DIR/link-ordinal-too-large.rs:9:5
+  --> $DIR/link-ordinal-too-large.rs:8:5
    |
 LL |     #[link_ordinal(72436)]
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the value may not exceed `u16::MAX`
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
index eca4186e593e82c4180b5bb4addaf656c14a4ff4..71e0ac9f3ee4bc7d5578deda7c906f6fc6fcd95d 100644 (file)
@@ -1,5 +1,4 @@
-#![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
+#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[link(name = "foo")]
 extern "C" {
index 745aab24dc768ce6a498757807920192e44ded1d..7e0fcd845cbde5829d35048d197eda9da6e13708 100644 (file)
@@ -1,14 +1,5 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/link-ordinal-too-many-arguments.rs:1:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-too-many-arguments.rs:6:5
+  --> $DIR/link-ordinal-too-many-arguments.rs:5:5
    |
 LL |     #[link_ordinal(3, 4)]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -16,12 +7,12 @@ LL |     #[link_ordinal(3, 4)]
    = note: the attribute requires exactly one argument
 
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-too-many-arguments.rs:9:5
+  --> $DIR/link-ordinal-too-many-arguments.rs:8:5
    |
 LL |     #[link_ordinal(3, 4)]
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the attribute requires exactly one argument
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
index 99f317399d768c439c46929248323c7b78fd9e32..329c93fc19637c6ab7ffecb8f04f6cdfcf3c5a6a 100644 (file)
@@ -1,5 +1,4 @@
-#![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
+#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[link(name = "foo")]
 extern "C" {
index f1eeb22da59c94b698cb36c93d8cf4474f29cf5c..5fbffbda570af49dfa9b0b87dbeeadfd6ec3395a 100644 (file)
@@ -1,23 +1,14 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/link-ordinal-unsupported-link-kind.rs:1:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
-  --> $DIR/link-ordinal-unsupported-link-kind.rs:6:5
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:5:5
    |
 LL |     #[link_ordinal(3)]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
-  --> $DIR/link-ordinal-unsupported-link-kind.rs:13:5
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:12:5
    |
 LL |     #[link_ordinal(3)]
    |     ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
 
index 13c9aa01e34ae8126858fb760bf1b32f37f5d2e8..6542faad2641248b35d513a8c7c307b7ed4500d5 100644 (file)
@@ -3,7 +3,6 @@
 // compile-flags: --crate-type lib --emit link
 #![allow(clashing_extern_declarations)]
 #![feature(raw_dylib)]
-//~^ WARN the feature `raw_dylib` is incomplete
 #[link(name = "foo", kind = "raw-dylib")]
 extern "C" {
     fn f(x: i32);
index 93ca8f4d8d448e1780f22d56a80e32d43898f8e3..c6808bec7b5c5f4ae0a82268211ff5109c71680b 100644 (file)
@@ -1,17 +1,8 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/multiple-declarations.rs:5:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error: multiple declarations of external function `f` from library `foo.dll` have different calling conventions
-  --> $DIR/multiple-declarations.rs:15:9
+  --> $DIR/multiple-declarations.rs:14:9
    |
 LL |         fn f(x: i32);
    |         ^^^^^^^^^^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
index 5856b18aa160c6c7bf99634d0daba4d08dbd4043..4efffbd532e133aa26d188d03880b083b449e430 100644 (file)
@@ -1,7 +1,6 @@
 // ignore-windows
 // compile-flags: --crate-type lib
-#![feature(raw_dylib)]
-//~^ WARNING: the feature `raw_dylib` is incomplete
+#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 #[link(name = "foo", kind = "raw-dylib")]
 //~^ ERROR: link kind `raw-dylib` is only supported on Windows targets
 extern "C" {}
index 600aac81a35932d0a6b4abd5db6dff38c47f6f87..14e791f1fb9a1199b1446cefb0360a1b58b415f2 100644 (file)
@@ -1,18 +1,9 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/raw-dylib-windows-only.rs:3:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
 error[E0455]: link kind `raw-dylib` is only supported on Windows targets
-  --> $DIR/raw-dylib-windows-only.rs:5:29
+  --> $DIR/raw-dylib-windows-only.rs:4:29
    |
 LL | #[link(name = "foo", kind = "raw-dylib")]
    |                             ^^^^^^^^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0455`.
index dc647fd63f527651746d09a4298c1ed1cd028649..2f5a23e47a74963e5d9341b9e8553f1444f5448f 100644 (file)
@@ -1,8 +1,6 @@
 // only-x86_64
 // only-windows
 // compile-flags: --crate-type lib --emit link
-#![allow(incomplete_features)]
-#![feature(raw_dylib)]
 #[link(name = "foo", kind = "raw-dylib")]
 extern "stdcall" {
     fn f(x: i32);
index d8a2a6af9c19e5dcd0ebc0270dfd1926d2c2326c..f8265ae691948948f0610495797ad854762b4b60 100644 (file)
@@ -1,5 +1,5 @@
 error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
-  --> $DIR/unsupported-abi.rs:8:5
+  --> $DIR/unsupported-abi.rs:6:5
    |
 LL |     fn f(x: i32);
    |     ^^^^^^^^^^^^^
diff --git a/src/test/ui/sanitize/memory-eager.rs b/src/test/ui/sanitize/memory-eager.rs
new file mode 100644 (file)
index 0000000..cc0593e
--- /dev/null
@@ -0,0 +1,38 @@
+// needs-sanitizer-support
+// needs-sanitizer-memory
+// min-llvm-version: 14.0.0
+//
+// revisions: unoptimized optimized
+//
+// [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
+// [unoptimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins
+//
+// run-fail
+// error-pattern: MemorySanitizer: use-of-uninitialized-value
+// error-pattern: Uninitialized value was created by an allocation
+// error-pattern: in the stack frame
+//
+// This test case intentionally limits the usage of the std,
+// since it will be linked with an uninstrumented version of it.
+
+#![feature(core_intrinsics)]
+#![feature(start)]
+#![feature(bench_black_box)]
+
+use std::hint::black_box;
+use std::mem::MaybeUninit;
+
+#[inline(never)]
+#[no_mangle]
+#[allow(invalid_value)]
+fn random() -> char {
+    let r = unsafe { MaybeUninit::uninit().assume_init() };
+    // Avoid optimizing everything out.
+    black_box(r)
+}
+
+#[start]
+fn main(_: isize, _: *const *const u8) -> isize {
+    random();
+    0
+}
index adda51f6be0ecb97eddee6bae8a86136153594ce..14d4de65dd378ed0358cbda7de43503b7a1e5630 100644 (file)
@@ -1,7 +1,10 @@
 // needs-sanitizer-support
 // needs-sanitizer-memory
 //
-// compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
+// revisions: unoptimized optimized
+//
+// [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
+// [unoptimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins
 //
 // run-fail
 // error-pattern: MemorySanitizer: use-of-uninitialized-value
@@ -22,9 +25,9 @@
 #[inline(never)]
 #[no_mangle]
 fn random() -> [isize; 32] {
-    let r = unsafe { MaybeUninit::uninit().assume_init() };
+    let r = MaybeUninit::uninit();
     // Avoid optimizing everything out.
-    black_box(r)
+    unsafe { std::intrinsics::volatile_load(r.as_ptr()) }
 }
 
 #[inline(never)]
@@ -39,6 +42,6 @@ fn xor(a: &[isize]) -> isize {
 
 #[start]
 fn main(_: isize, _: *const *const u8) -> isize {
-    let r = random();
+    let r = black_box(random as fn() -> [isize; 32])();
     xor(&r)
 }
index b280c8ab6e2b270e61fc77ec2204d56975ce4a32..94f578af209a8593e10a87e0928556d558833152 100644 (file)
@@ -12,7 +12,8 @@ async fn create(path: impl AsRef<std::path::Path>)  { //~ ERROR  `async fn` is n
 
 trait C{async fn new(val: T) {} //~ ERROR  `async fn` is not permitted in Rust 2015
 //~^ ERROR functions in traits cannot be declared `async`
-//~^^ ERROR cannot find type `T` in this scope
-//~^^^ WARN changes to closure capture in Rust 2021 will affect drop order [rust_2021_incompatible_closure_captures]
+//~| ERROR mismatched types
+//~| ERROR cannot find type `T` in this scope
+//~| WARN changes to closure capture in Rust 2021 will affect drop order [rust_2021_incompatible_closure_captures]
 
 //~ ERROR  this file contains an unclosed delimiter
index 50de2322907edb3a3e2ca20133d2cd7426112174..3814c568e72c1b555c30e67a61d57f6e8e57725c 100644 (file)
@@ -1,5 +1,5 @@
 error: this file contains an unclosed delimiter
-  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:18:53
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:19:53
    |
 LL | trait C{async fn new(val: T) {}
    |        - unclosed delimiter
@@ -25,17 +25,6 @@ LL | trait C{async fn new(val: T) {}
    = 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`
-  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:9
-   |
-LL | trait C{async fn new(val: T) {}
-   |         -----^^^^^^^^^^^^^^^^^^
-   |         |
-   |         `async` because of this
-   |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 error[E0423]: expected function, found module `crate`
   --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:9:5
    |
@@ -51,6 +40,19 @@ LL | pub struct A {}
 LL | trait C{async fn new(val: T) {}
    |                           ^ help: a struct with a similar name exists: `A`
 
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:9
+   |
+LL | trait C{async fn new(val: T) {}
+   |         -----^^^^^^^^^^^^^^^
+   |         |
+   |         `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
 warning: changes to closure capture in Rust 2021 will affect drop order
   --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:6:57
    |
@@ -72,6 +74,20 @@ help: add a dummy let to cause `path` to be fully captured
 LL |     async fn create(path: impl AsRef<std::path::Path>)  { let _ = &path;
    |                                                           ++++++++++++++
 
+error[E0308]: mismatched types
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:30
+   |
+LL | trait C{async fn new(val: T) {}
+   |                              ^^ expected associated type, found opaque type
+   |
+  ::: $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 associated type `impl Future<Output = ()>` (trait associated opaque type at <$DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:30>)
+                  found opaque type `impl Future<Output = ()>` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
+
 warning: changes to closure capture in Rust 2021 will affect drop order
   --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:30
    |
@@ -87,7 +103,7 @@ help: add a dummy let to cause `val` to be fully captured
 LL | trait C{async fn new(val: T) { let _ = &val;}
    |                                +++++++++++++
 
-error: aborting due to 6 previous errors; 2 warnings emitted
+error: aborting due to 7 previous errors; 2 warnings emitted
 
-Some errors have detailed explanations: E0412, E0423, E0670, E0706.
-For more information about an error, try `rustc --explain E0412`.
+Some errors have detailed explanations: E0308, E0412, E0423, E0670, E0706.
+For more information about an error, try `rustc --explain E0308`.
index a24b3ada57e59547d67f0e7761b38984dccdd12f..5102574d4be3ece384bfef2a5e2ec50172e9d5ff 100644 (file)
@@ -1,6 +1,7 @@
 // check-pass
 // compile-flags: -Zhir-stats
 // only-x86_64
+// ignore-stage1
 
 // The aim here is to include at least one of every different type of top-level
 // AST/HIR node reported by `-Zhir-stats`.
index 0a736f7be834e6da66083c655a68db6dd3999ac2..8d977606530819efa8130b87708010ad839d81f3 100644 (file)
@@ -21,39 +21,39 @@ ast-stats-1 - MacCall                   32 ( 0.4%)             1
 ast-stats-1 - Expr                      96 ( 1.1%)             3
 ast-stats-1 Param                    160 ( 1.9%)             4            40
 ast-stats-1 FnDecl                   200 ( 2.4%)             5            40
-ast-stats-1 Variant                  240 ( 2.8%)             2           120
+ast-stats-1 Variant                  240 ( 2.9%)             2           120
 ast-stats-1 Block                    288 ( 3.4%)             6            48
 ast-stats-1 GenericBound             352 ( 4.2%)             4            88
 ast-stats-1 - Trait                    352 ( 4.2%)             4
 ast-stats-1 AssocItem                416 ( 4.9%)             4           104
 ast-stats-1 - TyAlias                  208 ( 2.5%)             2
 ast-stats-1 - Fn                       208 ( 2.5%)             2
-ast-stats-1 GenericParam             520 ( 6.1%)             5           104
-ast-stats-1 PathSegment              720 ( 8.5%)            30            24
-ast-stats-1 Expr                     832 ( 9.8%)             8           104
+ast-stats-1 GenericParam             480 ( 5.7%)             5            96
+ast-stats-1 PathSegment              720 ( 8.6%)            30            24
+ast-stats-1 Expr                     832 ( 9.9%)             8           104
 ast-stats-1 - Path                     104 ( 1.2%)             1
 ast-stats-1 - Match                    104 ( 1.2%)             1
 ast-stats-1 - Struct                   104 ( 1.2%)             1
 ast-stats-1 - Lit                      208 ( 2.5%)             2
 ast-stats-1 - Block                    312 ( 3.7%)             3
-ast-stats-1 Pat                      840 ( 9.9%)             7           120
+ast-stats-1 Pat                      840 (10.0%)             7           120
 ast-stats-1 - Struct                   120 ( 1.4%)             1
 ast-stats-1 - Wild                     120 ( 1.4%)             1
 ast-stats-1 - Ident                    600 ( 7.1%)             5
-ast-stats-1 Ty                     1_344 (15.9%)            14            96
+ast-stats-1 Ty                     1_344 (16.0%)            14            96
 ast-stats-1 - Rptr                      96 ( 1.1%)             1
 ast-stats-1 - Ptr                       96 ( 1.1%)             1
 ast-stats-1 - ImplicitSelf             192 ( 2.3%)             2
 ast-stats-1 - Path                     960 (11.4%)            10
-ast-stats-1 Item                   1_656 (19.6%)             9           184
+ast-stats-1 Item                   1_656 (19.7%)             9           184
 ast-stats-1 - Trait                    184 ( 2.2%)             1
 ast-stats-1 - Enum                     184 ( 2.2%)             1
 ast-stats-1 - ForeignMod               184 ( 2.2%)             1
 ast-stats-1 - Impl                     184 ( 2.2%)             1
 ast-stats-1 - Fn                       368 ( 4.4%)             2
-ast-stats-1 - Use                      552 ( 6.5%)             3
+ast-stats-1 - Use                      552 ( 6.6%)             3
 ast-stats-1 ----------------------------------------------------------------
-ast-stats-1 Total                  8_456
+ast-stats-1 Total                  8_416
 ast-stats-1
 ast-stats-2 POST EXPANSION AST STATS
 ast-stats-2 Name                Accumulated Size         Count     Item Size
@@ -86,12 +86,12 @@ ast-stats-2 - Trait                    352 ( 3.8%)             4
 ast-stats-2 AssocItem                416 ( 4.5%)             4           104
 ast-stats-2 - TyAlias                  208 ( 2.3%)             2
 ast-stats-2 - Fn                       208 ( 2.3%)             2
-ast-stats-2 GenericParam             520 ( 5.7%)             5           104
-ast-stats-2 PathSegment              792 ( 8.6%)            33            24
-ast-stats-2 Pat                      840 ( 9.1%)             7           120
+ast-stats-2 GenericParam             480 ( 5.2%)             5            96
+ast-stats-2 PathSegment              792 ( 8.7%)            33            24
+ast-stats-2 Pat                      840 ( 9.2%)             7           120
 ast-stats-2 - Struct                   120 ( 1.3%)             1
 ast-stats-2 - Wild                     120 ( 1.3%)             1
-ast-stats-2 - Ident                    600 ( 6.5%)             5
+ast-stats-2 - Ident                    600 ( 6.6%)             5
 ast-stats-2 Expr                     936 (10.2%)             9           104
 ast-stats-2 - Path                     104 ( 1.1%)             1
 ast-stats-2 - Match                    104 ( 1.1%)             1
@@ -99,12 +99,12 @@ ast-stats-2 - Struct                   104 ( 1.1%)             1
 ast-stats-2 - InlineAsm                104 ( 1.1%)             1
 ast-stats-2 - Lit                      208 ( 2.3%)             2
 ast-stats-2 - Block                    312 ( 3.4%)             3
-ast-stats-2 Ty                     1_344 (14.6%)            14            96
+ast-stats-2 Ty                     1_344 (14.7%)            14            96
 ast-stats-2 - Rptr                      96 ( 1.0%)             1
 ast-stats-2 - Ptr                       96 ( 1.0%)             1
 ast-stats-2 - ImplicitSelf             192 ( 2.1%)             2
 ast-stats-2 - Path                     960 (10.5%)            10
-ast-stats-2 Item                   2_024 (22.0%)            11           184
+ast-stats-2 Item                   2_024 (22.1%)            11           184
 ast-stats-2 - Trait                    184 ( 2.0%)             1
 ast-stats-2 - Enum                     184 ( 2.0%)             1
 ast-stats-2 - ExternCrate              184 ( 2.0%)             1
@@ -113,65 +113,66 @@ ast-stats-2 - Impl                     184 ( 2.0%)             1
 ast-stats-2 - Fn                       368 ( 4.0%)             2
 ast-stats-2 - Use                      736 ( 8.0%)             4
 ast-stats-2 ----------------------------------------------------------------
-ast-stats-2 Total                  9_184
+ast-stats-2 Total                  9_144
 ast-stats-2
 hir-stats HIR STATS
 hir-stats Name                Accumulated Size         Count     Item Size
 hir-stats ----------------------------------------------------------------
 hir-stats ForeignItemRef            24 ( 0.2%)             1            24
+hir-stats Lifetime                  32 ( 0.3%)             1            32
 hir-stats Mod                       32 ( 0.3%)             1            32
 hir-stats ExprField                 40 ( 0.4%)             1            40
-hir-stats TraitItemRef              56 ( 0.5%)             2            28
-hir-stats Param                     64 ( 0.6%)             2            32
-hir-stats Local                     64 ( 0.6%)             1            64
+hir-stats TraitItemRef              56 ( 0.6%)             2            28
+hir-stats Local                     64 ( 0.7%)             1            64
+hir-stats Param                     64 ( 0.7%)             2            32
 hir-stats InlineAsm                 72 ( 0.7%)             1            72
 hir-stats ImplItemRef               72 ( 0.7%)             2            36
-hir-stats FieldDef                  96 ( 0.9%)             2            48
-hir-stats Arm                       96 ( 0.9%)             2            48
-hir-stats Body                      96 ( 0.9%)             3            32
-hir-stats Stmt                      96 ( 0.9%)             3            32
+hir-stats Body                      96 ( 1.0%)             3            32
+hir-stats GenericArg                96 ( 1.0%)             4            24
+hir-stats - Type                      24 ( 0.2%)             1
+hir-stats - Lifetime                  72 ( 0.7%)             3
+hir-stats FieldDef                  96 ( 1.0%)             2            48
+hir-stats Arm                       96 ( 1.0%)             2            48
+hir-stats Stmt                      96 ( 1.0%)             3            32
 hir-stats - Local                     32 ( 0.3%)             1
 hir-stats - Semi                      32 ( 0.3%)             1
 hir-stats - Expr                      32 ( 0.3%)             1
 hir-stats FnDecl                   120 ( 1.2%)             3            40
 hir-stats Attribute                128 ( 1.3%)             4            32
-hir-stats GenericArgs              144 ( 1.4%)             3            48
-hir-stats Variant                  160 ( 1.6%)             2            80
-hir-stats GenericArg               160 ( 1.6%)             4            40
-hir-stats - Type                      40 ( 0.4%)             1
-hir-stats - Lifetime                 120 ( 1.2%)             3
-hir-stats GenericBound             192 ( 1.9%)             4            48
-hir-stats - Trait                    192 ( 1.9%)             4
-hir-stats WherePredicate           216 ( 2.1%)             3            72
-hir-stats - BoundPredicate           216 ( 2.1%)             3
-hir-stats Block                    288 ( 2.8%)             6            48
-hir-stats GenericParam             400 ( 3.9%)             5            80
-hir-stats Pat                      440 ( 4.3%)             5            88
-hir-stats - Wild                      88 ( 0.9%)             1
-hir-stats - Struct                    88 ( 0.9%)             1
-hir-stats - Binding                  264 ( 2.6%)             3
-hir-stats Generics                 560 ( 5.5%)            10            56
-hir-stats Expr                     768 ( 7.5%)            12            64
-hir-stats - Path                      64 ( 0.6%)             1
-hir-stats - Struct                    64 ( 0.6%)             1
-hir-stats - Match                     64 ( 0.6%)             1
-hir-stats - InlineAsm                 64 ( 0.6%)             1
+hir-stats GenericArgs              144 ( 1.5%)             3            48
+hir-stats Variant                  160 ( 1.7%)             2            80
+hir-stats WherePredicate           168 ( 1.7%)             3            56
+hir-stats - BoundPredicate           168 ( 1.7%)             3
+hir-stats GenericBound             192 ( 2.0%)             4            48
+hir-stats - Trait                    192 ( 2.0%)             4
+hir-stats Block                    288 ( 3.0%)             6            48
+hir-stats Pat                      360 ( 3.7%)             5            72
+hir-stats - Wild                      72 ( 0.7%)             1
+hir-stats - Struct                    72 ( 0.7%)             1
+hir-stats - Binding                  216 ( 2.2%)             3
+hir-stats GenericParam             400 ( 4.1%)             5            80
+hir-stats Generics                 560 ( 5.8%)            10            56
+hir-stats Ty                       720 ( 7.4%)            15            48
+hir-stats - Ptr                       48 ( 0.5%)             1
+hir-stats - Rptr                      48 ( 0.5%)             1
+hir-stats - Path                     624 ( 6.4%)            13
+hir-stats Expr                     768 ( 7.9%)            12            64
+hir-stats - Path                      64 ( 0.7%)             1
+hir-stats - Struct                    64 ( 0.7%)             1
+hir-stats - Match                     64 ( 0.7%)             1
+hir-stats - InlineAsm                 64 ( 0.7%)             1
 hir-stats - Lit                      128 ( 1.3%)             2
-hir-stats - Block                    384 ( 3.8%)             6
-hir-stats Item                     960 ( 9.4%)            12            80
+hir-stats - Block                    384 ( 4.0%)             6
+hir-stats Item                     960 ( 9.9%)            12            80
 hir-stats - Trait                     80 ( 0.8%)             1
 hir-stats - Enum                      80 ( 0.8%)             1
 hir-stats - ExternCrate               80 ( 0.8%)             1
 hir-stats - ForeignMod                80 ( 0.8%)             1
 hir-stats - Impl                      80 ( 0.8%)             1
-hir-stats - Fn                       160 ( 1.6%)             2
-hir-stats - Use                      400 ( 3.9%)             5
-hir-stats Ty                     1_080 (10.6%)            15            72
-hir-stats - Ptr                       72 ( 0.7%)             1
-hir-stats - Rptr                      72 ( 0.7%)             1
-hir-stats - Path                     936 ( 9.2%)            13
-hir-stats Path                   1_536 (15.1%)            32            48
-hir-stats PathSegment            2_240 (22.0%)            40            56
+hir-stats - Fn                       160 ( 1.7%)             2
+hir-stats - Use                      400 ( 4.1%)             5
+hir-stats Path                   1_536 (15.9%)            32            48
+hir-stats PathSegment            2_240 (23.1%)            40            56
 hir-stats ----------------------------------------------------------------
-hir-stats Total                 10_200
+hir-stats Total                  9_680
 hir-stats
index 73a11a5e743f6a7f85810bfbcc0d86d54cf7fd3d..7a23f13630a43fabcfdbea1251b182fce6a890f7 100644 (file)
@@ -120,6 +120,54 @@ pub enum AlwaysTaggedBecauseItHasNoNiche {
     B
 }
 
+pub enum NicheFilledMultipleFields {
+    A(bool, u8),
+    B(u8),
+    C(u8),
+    D(bool),
+    E,
+    F,
+    G,
+}
+
+struct BoolInTheMiddle(std::num::NonZeroU16, bool, u8);
+
+enum NicheWithData {
+    A,
+    B([u16; 5]),
+    Largest { a1: u32, a2: BoolInTheMiddle, a3: u32 },
+    C,
+    D(u32, u32),
+}
+
+// A type with almost 2^16 invalid values.
+#[repr(u16)]
+pub enum NicheU16 {
+    _0,
+}
+
+pub enum EnumManyVariant<X> {
+    Dataful(u8, X),
+
+    // 0x100 niche variants.
+    _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F,
+    _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F,
+    _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F,
+    _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F,
+    _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F,
+    _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F,
+    _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F,
+    _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F,
+    _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F,
+    _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F,
+    _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF,
+    _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF,
+    _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF,
+    _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF,
+    _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF,
+    _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF,
+}
+
 pub fn main() {
     assert_eq!(size_of::<u8>(), 1 as usize);
     assert_eq!(size_of::<u32>(), 4 as usize);
@@ -170,4 +218,35 @@ pub fn main() {
     assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
     assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
     assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
+
+    assert_eq!(size_of::<NicheFilledMultipleFields>(), 2);
+    assert_eq!(size_of::<Option<NicheFilledMultipleFields>>(), 2);
+    assert_eq!(size_of::<Option<Option<NicheFilledMultipleFields>>>(), 2);
+
+    struct S1{ a: u16, b: std::num::NonZeroU16, c: u16, d: u8, e: u32, f: u64, g:[u8;2] }
+    assert_eq!(size_of::<S1>(), 24);
+    assert_eq!(size_of::<Option<S1>>(), 24);
+
+    assert_eq!(size_of::<NicheWithData>(), 12);
+    assert_eq!(size_of::<Option<NicheWithData>>(), 12);
+    assert_eq!(size_of::<Option<Option<NicheWithData>>>(), 12);
+    assert_eq!(
+        size_of::<Option<Option2<&(), Option<NicheWithData>>>>(),
+        size_of::<(&(), NicheWithData)>()
+    );
+
+    pub enum FillPadding { A(std::num::NonZeroU8, u32), B }
+    assert_eq!(size_of::<FillPadding>(), 8);
+    assert_eq!(size_of::<Option<FillPadding>>(), 8);
+    assert_eq!(size_of::<Option<Option<FillPadding>>>(), 8);
+
+    assert_eq!(size_of::<Result<(std::num::NonZeroU8, u8, u8), u16>>(), 4);
+    assert_eq!(size_of::<Option<Result<(std::num::NonZeroU8, u8, u8), u16>>>(), 4);
+    assert_eq!(size_of::<Result<(std::num::NonZeroU8, u8, u8, u8), u16>>(), 4);
+
+    assert_eq!(size_of::<EnumManyVariant<u16>>(), 6);
+    assert_eq!(size_of::<EnumManyVariant<NicheU16>>(), 4);
+    assert_eq!(size_of::<EnumManyVariant<Option<NicheU16>>>(), 4);
+    assert_eq!(size_of::<EnumManyVariant<Option2<NicheU16,u8>>>(), 6);
+    assert_eq!(size_of::<EnumManyVariant<Option<(NicheU16,u8)>>>(), 6);
 }
index e43a4e79bfe8c54c1e433d7ef0ddf184fe7567ce..77cef485f30e9a477108aa3e29914a0544e46f80 100644 (file)
@@ -91,7 +91,7 @@ LL |   pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
    |                                             ------------------------------- the found opaque type
    |
    = note:   expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>`
-           found opaque type `impl Future`
+           found opaque type `impl Future<Output = {integer}>`
 help: you need to pin and box this expression
    |
 LL ~     Box::pin(async {
index 73ca9f97b43a360b986a47f9be217e01ba766851..1e7569fa45106c60b8660a83af58f6c6c3757648 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-fn add_ten<N: std::ops::Add<i32, Output=N>>(n: N) -> N {
+fn add_ten<N: std::ops::Add<i32, Output = N>>(n: N) -> N {
     n + 10
     //~^ ERROR cannot add `{integer}` to `N`
 }
index 069b184ac636c45bdfaa6dc045afca4f647f3c57..575d79267f20d718957f456241a28b7ec1c3d66a 100644 (file)
@@ -8,8 +8,8 @@ LL |     n + 10
    |
 help: consider restricting type parameter `N`
    |
-LL | fn add_ten<N: std::ops::Add<i32, Output=N>>(n: N) -> N {
-   |             ++++++++++++++++++++++++++++++
+LL | fn add_ten<N: std::ops::Add<i32, Output = N>>(n: N) -> N {
+   |             ++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/restrict-type-not-param.rs b/src/test/ui/suggestions/restrict-type-not-param.rs
new file mode 100644 (file)
index 0000000..60f5ba4
--- /dev/null
@@ -0,0 +1,12 @@
+use std::ops::Add;
+
+struct Wrapper<T>(T);
+
+trait Foo {}
+
+fn qux<T>(a: Wrapper<T>, b: T) -> T {
+    a + b
+    //~^ ERROR cannot add `T` to `Wrapper<T>`
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/restrict-type-not-param.stderr b/src/test/ui/suggestions/restrict-type-not-param.stderr
new file mode 100644 (file)
index 0000000..e7d9c5e
--- /dev/null
@@ -0,0 +1,26 @@
+error[E0369]: cannot add `T` to `Wrapper<T>`
+  --> $DIR/restrict-type-not-param.rs:8:7
+   |
+LL |     a + b
+   |     - ^ - T
+   |     |
+   |     Wrapper<T>
+   |
+note: an implementation of `Add<_>` might be missing for `Wrapper<T>`
+  --> $DIR/restrict-type-not-param.rs:3:1
+   |
+LL | struct Wrapper<T>(T);
+   | ^^^^^^^^^^^^^^^^^ must implement `Add<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | pub trait Add<Rhs = Self> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn qux<T>(a: Wrapper<T>, b: T) -> T where Wrapper<T>: Add<T, Output = T> {
+   |                                     ++++++++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0369`.
index f52631caed173caec745c09ca43d4d9dc2610f37..b1a49447d4601c9bcae50a6dc383f548379f3c45 100644 (file)
@@ -1,22 +1,22 @@
-error: lifetime parameters must be declared prior to type parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/suggest-move-lifetimes.rs:1:13
    |
 LL | struct A<T, 'a> {
    |         ----^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T>`
 
-error: lifetime parameters must be declared prior to type parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/suggest-move-lifetimes.rs:5:13
    |
 LL | struct B<T, 'a, U> {
    |         ----^^---- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, U>`
 
-error: lifetime parameters must be declared prior to type parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/suggest-move-lifetimes.rs:10:16
    |
 LL | struct C<T, U, 'a> {
    |         -------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, U>`
 
-error: lifetime parameters must be declared prior to type parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/suggest-move-lifetimes.rs:15:16
    |
 LL | struct D<T, U, 'a, 'b, V, 'c> {
index 1a6032db0010a7a15a5029dab155f387e84b6c94..b222e8142bab5148a5e24ae3b64bd0626420e9d0 100644 (file)
@@ -121,7 +121,7 @@ LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=()
    |                                                        ^^
    |
    = note: lifetime arguments must be provided before type arguments
-   = help: reorder the arguments: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
+   = help: reorder the arguments: lifetimes, then type and consts: `<'a, 'b, 'c, T, U, V>`
 
 error[E0747]: lifetime provided when a type was expected
   --> $DIR/suggest-move-types.rs:82:56
@@ -130,7 +130,7 @@ LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, '
    |                                                        ^^
    |
    = note: lifetime arguments must be provided before type arguments
-   = help: reorder the arguments: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
+   = help: reorder the arguments: lifetimes, then type and consts: `<'a, 'b, 'c, T, U, V>`
 
 error: aborting due to 12 previous errors
 
index 34fae64e4d20fe9b2d682c78125d25ec812dab79..fe5e1d6d2854de0b98f0588d188734ff3404213b 100644 (file)
@@ -8,8 +8,8 @@ LL |     a * b
    |
 help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
-LL | fn foo<T: MyMul<f64, f64>>(a: &T, b: f64) -> f64 where &T: Mul<f64> {
-   |                                                  ++++++++++++++++++
+LL | fn foo<T: MyMul<f64, f64>>(a: &T, b: f64) -> f64 where &T: Mul<f64, Output = f64> {
+   |                                                  ++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
index c32174288ee684069c391825a168785e6c0d8aef..03fb64b7b94d7ea02224ae7cc4b5060e847a1133 100644 (file)
@@ -1,17 +1,33 @@
-// check-pass
-
 #![feature(type_alias_impl_trait)]
 
-mod foo {
+mod lifetime_params {
     type Ty<'a> = impl Sized;
     fn defining(s: &str) -> Ty<'_> { s }
     fn execute(ty: Ty<'_>) -> &str { todo!() }
+    //~^ ERROR return type references an anonymous lifetime, which is not constrained by the fn input types
+
+    type BadFnSig = fn(Ty<'_>) -> &str;
+    //~^ ERROR return type references an anonymous lifetime, which is not constrained by the fn input types
+    type BadTraitRef = dyn Fn(Ty<'_>) -> &str;
+    //~^ ERROR binding for associated type `Output` references an anonymous lifetime
 }
 
-mod bar {
+mod lifetime_params_2 {
     type Ty<'a> = impl FnOnce() -> &'a str;
     fn defining(s: &str) -> Ty<'_> { move || s }
     fn execute(ty: Ty<'_>) -> &str { ty() }
+    //~^ ERROR return type references an anonymous lifetime, which is not constrained by the fn input types
+}
+
+// regression test for https://github.com/rust-lang/rust/issues/97104
+mod type_params {
+    type Ty<T> = impl Sized;
+    fn define<T>(s: T) -> Ty<T> { s }
+
+    type BadFnSig = fn(Ty<&str>) -> &str;
+    //~^ ERROR return type references an anonymous lifetime, which is not constrained by the fn input types
+    type BadTraitRef = dyn Fn(Ty<&str>) -> &str;
+    //~^ ERROR binding for associated type `Output` references an anonymous lifetime
 }
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs.stderr b/src/test/ui/type-alias-impl-trait/constrain_inputs.stderr
new file mode 100644 (file)
index 0000000..93953fd
--- /dev/null
@@ -0,0 +1,58 @@
+error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
+  --> $DIR/constrain_inputs.rs:6:31
+   |
+LL |     fn execute(ty: Ty<'_>) -> &str { todo!() }
+   |                               ^^^^
+   |
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
+
+error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
+  --> $DIR/constrain_inputs.rs:9:35
+   |
+LL |     type BadFnSig = fn(Ty<'_>) -> &str;
+   |                                   ^^^^
+   |
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
+
+error[E0582]: binding for associated type `Output` references an anonymous lifetime, which does not appear in the trait input types
+  --> $DIR/constrain_inputs.rs:11:42
+   |
+LL |     type BadTraitRef = dyn Fn(Ty<'_>) -> &str;
+   |                                          ^^^^
+   |
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
+
+error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
+  --> $DIR/constrain_inputs.rs:18:31
+   |
+LL |     fn execute(ty: Ty<'_>) -> &str { ty() }
+   |                               ^^^^
+   |
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
+
+error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
+  --> $DIR/constrain_inputs.rs:27:37
+   |
+LL |     type BadFnSig = fn(Ty<&str>) -> &str;
+   |                                     ^^^^
+   |
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
+
+error[E0582]: binding for associated type `Output` references an anonymous lifetime, which does not appear in the trait input types
+  --> $DIR/constrain_inputs.rs:29:44
+   |
+LL |     type BadTraitRef = dyn Fn(Ty<&str>) -> &str;
+   |                                            ^^^^
+   |
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0581, E0582.
+For more information about an error, try `rustc --explain E0581`.
diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs b/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs
new file mode 100644 (file)
index 0000000..3bae0f1
--- /dev/null
@@ -0,0 +1,31 @@
+#![feature(type_alias_impl_trait)]
+
+trait Static: 'static {}
+impl Static for () {}
+
+type Gal<T> = impl Static;
+fn _defining<T>() -> Gal<T> {}
+
+trait Callable<Arg> { type Output; }
+
+/// We can infer `<C as Callable<Arg>>::Output: 'static`,
+/// because we know `C: 'static` and `Arg: 'static`,
+fn box_str<C, Arg>(s: C::Output) -> Box<dyn AsRef<str> + 'static>
+where
+    Arg: Static,
+    C: ?Sized + Callable<Arg> + 'static,
+    C::Output: AsRef<str>,
+{
+    Box::new(s)
+}
+
+fn extend_lifetime(s: &str) -> Box<dyn AsRef<str> + 'static> {
+    type MalformedTy = dyn for<'a> Callable<Gal<&'a ()>, Output = &'a str>;
+    //~^ ERROR binding for associated type `Output` references lifetime `'a`
+    box_str::<MalformedTy, _>(s)
+}
+
+fn main() {
+    let extended = extend_lifetime(&String::from("hello"));
+    println!("{}", extended.as_ref().as_ref());
+}
diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.stderr b/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.stderr
new file mode 100644 (file)
index 0000000..d5fc46c
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types
+  --> $DIR/constrain_inputs_unsound.rs:23:58
+   |
+LL |     type MalformedTy = dyn for<'a> Callable<Gal<&'a ()>, Output = &'a str>;
+   |                                                          ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0582`.
index a6fcdfe21f481a3fb99435827c80454274974b32..e394cf8206edef45077760f28886f310e09c0e3c 100644 (file)
@@ -19,7 +19,7 @@ LL |     x.lock().unwrap() += 1;
    |     |
    |     cannot use `+=` on type `MutexGuard<'_, usize>`
    |
-help: `+=` can be used on `usize`, you can dereference `x.lock().unwrap()`
+help: `+=` can be used on `usize` if you dereference the left-hand side
    |
 LL |     *x.lock().unwrap() += 1;
    |     +
@@ -47,7 +47,7 @@ LL |     y += 1;
    |     |
    |     cannot use `+=` on type `MutexGuard<'_, usize>`
    |
-help: `+=` can be used on `usize`, you can dereference `y`
+help: `+=` can be used on `usize` if you dereference the left-hand side
    |
 LL |     *y += 1;
    |     +
index be2e9fe95e87144a3e27ffcfe1d4d14267c2d14e..cbdc960baab8e7cafaa456825299b800c3c122ad 100644 (file)
@@ -19,7 +19,7 @@ LL |     x.last_mut().unwrap() += 1;
    |     |
    |     cannot use `+=` on type `&mut usize`
    |
-help: `+=` can be used on `usize`, you can dereference `x.last_mut().unwrap()`
+help: `+=` can be used on `usize` if you dereference the left-hand side
    |
 LL |     *x.last_mut().unwrap() += 1;
    |     +
@@ -45,7 +45,7 @@ LL |     y += 1;
    |     |
    |     cannot use `+=` on type `&mut usize`
    |
-help: `+=` can be used on `usize`, you can dereference `y`
+help: `+=` can be used on `usize` if you dereference the left-hand side
    |
 LL |     *y += 1;
    |     +
index c488c142e46fc2847fe41d7c3c3582508a705eac..d847e4c749481fbc06566e2c3bde97064e77f0f0 100644 (file)
@@ -3583,7 +3583,7 @@ Released 2018-09-13
 [`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range
 [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
 [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
-[`arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic
+[`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects
 [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
 [`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore
 [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
@@ -3603,6 +3603,7 @@ Released 2018-09-13
 [`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions
 [`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison
 [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
+[`bool_to_int_with_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_to_int_with_if
 [`borrow_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr
 [`borrow_deref_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_deref_ref
 [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
index be05e67d724dfc120acfec0d1385dda0cd3df741..331b76484b8a5d5f62992a34d73de6fadbf72c93 100644 (file)
@@ -120,15 +120,17 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
 
     let new_lint = if enable_msrv {
         format!(
-            "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n    ",
+            "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv)));\n    ",
             lint_pass = lint.pass,
+            ctor_arg = if lint.pass == "late" { "_" } else { "" },
             module_name = lint.name,
             camel_name = to_camel_case(lint.name),
         )
     } else {
         format!(
-            "store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n    ",
+            "store.register_{lint_pass}_pass(|{ctor_arg}| Box::new({module_name}::{camel_name}));\n    ",
             lint_pass = lint.pass,
+            ctor_arg = if lint.pass == "late" { "_" } else { "" },
             module_name = lint.name,
             camel_name = to_camel_case(lint.name),
         )
index c503142e5e4552b1cdc28877dca9ab3734ba2083..b95061bf81a25e3b5290a95571cf50d87f0e235f 100644 (file)
@@ -3,7 +3,7 @@
 use indoc::writedoc;
 use itertools::Itertools;
 use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
-use std::collections::{HashMap, HashSet};
+use std::collections::{BTreeSet, HashMap, HashSet};
 use std::ffi::OsStr;
 use std::fmt::Write;
 use std::fs::{self, OpenOptions};
@@ -124,6 +124,8 @@ fn generate_lint_files(
     let content = gen_lint_group_list("all", all_group_lints);
     process_file("clippy_lints/src/lib.register_all.rs", update_mode, &content);
 
+    update_docs(update_mode, &usable_lints);
+
     for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) {
         let content = gen_lint_group_list(&lint_group, lints.iter());
         process_file(
@@ -140,6 +142,62 @@ fn generate_lint_files(
     process_file("tests/ui/rename.rs", update_mode, &content);
 }
 
+fn update_docs(update_mode: UpdateMode, usable_lints: &[Lint]) {
+    replace_region_in_file(update_mode, Path::new("src/docs.rs"), "docs! {\n", "\n}\n", |res| {
+        for name in usable_lints.iter().map(|lint| lint.name.clone()).sorted() {
+            writeln!(res, r#"    "{name}","#).unwrap();
+        }
+    });
+
+    if update_mode == UpdateMode::Check {
+        let mut extra = BTreeSet::new();
+        let mut lint_names = usable_lints
+            .iter()
+            .map(|lint| lint.name.clone())
+            .collect::<BTreeSet<_>>();
+        for file in std::fs::read_dir("src/docs").unwrap() {
+            let filename = file.unwrap().file_name().into_string().unwrap();
+            if let Some(name) = filename.strip_suffix(".txt") {
+                if !lint_names.remove(name) {
+                    extra.insert(name.to_string());
+                }
+            }
+        }
+
+        let failed = print_lint_names("extra lint docs:", &extra) | print_lint_names("missing lint docs:", &lint_names);
+
+        if failed {
+            exit_with_failure();
+        }
+    } else {
+        if std::fs::remove_dir_all("src/docs").is_err() {
+            eprintln!("could not remove src/docs directory");
+        }
+        if std::fs::create_dir("src/docs").is_err() {
+            eprintln!("could not recreate src/docs directory");
+        }
+    }
+    for lint in usable_lints {
+        process_file(
+            Path::new("src/docs").join(lint.name.clone() + ".txt"),
+            update_mode,
+            &lint.documentation,
+        );
+    }
+}
+
+fn print_lint_names(header: &str, lints: &BTreeSet<String>) -> bool {
+    if lints.is_empty() {
+        return false;
+    }
+    println!("{}", header);
+    for lint in lints.iter().sorted() {
+        println!("    {}", lint);
+    }
+    println!();
+    true
+}
+
 pub fn print_lints() {
     let (lint_list, _, _) = gather_all();
     let usable_lints = Lint::usable_lints(&lint_list);
@@ -589,17 +647,26 @@ struct Lint {
     desc: String,
     module: String,
     declaration_range: Range<usize>,
+    documentation: String,
 }
 
 impl Lint {
     #[must_use]
-    fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Range<usize>) -> Self {
+    fn new(
+        name: &str,
+        group: &str,
+        desc: &str,
+        module: &str,
+        declaration_range: Range<usize>,
+        documentation: String,
+    ) -> Self {
         Self {
             name: name.to_lowercase(),
             group: group.into(),
             desc: remove_line_splices(desc),
             module: module.into(),
             declaration_range,
+            documentation,
         }
     }
 
@@ -852,27 +919,35 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
          }| token_kind == &TokenKind::Ident && *content == "declare_clippy_lint",
     ) {
         let start = range.start;
-
-        let mut iter = iter
-            .by_ref()
-            .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
+        let mut docs = String::with_capacity(128);
+        let mut iter = iter.by_ref().filter(|t| !matches!(t.token_kind, TokenKind::Whitespace));
         // matches `!{`
         match_tokens!(iter, Bang OpenBrace);
-        match iter.next() {
-            // #[clippy::version = "version"] pub
-            Some(LintDeclSearchResult {
-                token_kind: TokenKind::Pound,
-                ..
-            }) => {
-                match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident);
-            },
-            // pub
-            Some(LintDeclSearchResult {
-                token_kind: TokenKind::Ident,
-                ..
-            }) => (),
-            _ => continue,
+        let mut in_code = false;
+        while let Some(t) = iter.next() {
+            match t.token_kind {
+                TokenKind::LineComment { .. } => {
+                    if let Some(line) = t.content.strip_prefix("/// ").or_else(|| t.content.strip_prefix("///")) {
+                        if line.starts_with("```") {
+                            docs += "```\n";
+                            in_code = !in_code;
+                        } else if !(in_code && line.starts_with("# ")) {
+                            docs += line;
+                            docs.push('\n');
+                        }
+                    }
+                },
+                TokenKind::Pound => {
+                    match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident);
+                    break;
+                },
+                TokenKind::Ident => {
+                    break;
+                },
+                _ => {},
+            }
         }
+        docs.pop(); // remove final newline
 
         let (name, group, desc) = match_tokens!(
             iter,
@@ -890,7 +965,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
             ..
         }) = iter.next()
         {
-            lints.push(Lint::new(name, group, desc, module, start..range.end));
+            lints.push(Lint::new(name, group, desc, module, start..range.end, docs));
         }
     }
 }
@@ -977,7 +1052,11 @@ fn remove_line_splices(s: &str) -> String {
         .and_then(|s| s.strip_suffix('"'))
         .unwrap_or_else(|| panic!("expected quoted string, found `{}`", s));
     let mut res = String::with_capacity(s.len());
-    unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, _| res.push_str(&s[range]));
+    unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, ch| {
+        if ch.is_ok() {
+            res.push_str(&s[range]);
+        }
+    });
     res
 }
 
@@ -1116,6 +1195,7 @@ fn test_parse_contents() {
                 "\"really long text\"",
                 "module_name",
                 Range::default(),
+                String::new(),
             ),
             Lint::new(
                 "doc_markdown",
@@ -1123,6 +1203,7 @@ fn test_parse_contents() {
                 "\"single line\"",
                 "module_name",
                 Range::default(),
+                String::new(),
             ),
         ];
         assert_eq!(expected, result);
@@ -1162,6 +1243,7 @@ fn test_usable_lints() {
                 "\"abc\"",
                 "module_name",
                 Range::default(),
+                String::new(),
             ),
             Lint::new(
                 "should_assert_eq2",
@@ -1169,6 +1251,7 @@ fn test_usable_lints() {
                 "\"abc\"",
                 "module_name",
                 Range::default(),
+                String::new(),
             ),
             Lint::new(
                 "should_assert_eq2",
@@ -1176,6 +1259,7 @@ fn test_usable_lints() {
                 "\"abc\"",
                 "module_name",
                 Range::default(),
+                String::new(),
             ),
         ];
         let expected = vec![Lint::new(
@@ -1184,6 +1268,7 @@ fn test_usable_lints() {
             "\"abc\"",
             "module_name",
             Range::default(),
+            String::new(),
         )];
         assert_eq!(expected, Lint::usable_lints(&lints));
     }
@@ -1191,22 +1276,51 @@ fn test_usable_lints() {
     #[test]
     fn test_by_lint_group() {
         let lints = vec![
-            Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
+            Lint::new(
+                "should_assert_eq",
+                "group1",
+                "\"abc\"",
+                "module_name",
+                Range::default(),
+                String::new(),
+            ),
             Lint::new(
                 "should_assert_eq2",
                 "group2",
                 "\"abc\"",
                 "module_name",
                 Range::default(),
+                String::new(),
+            ),
+            Lint::new(
+                "incorrect_match",
+                "group1",
+                "\"abc\"",
+                "module_name",
+                Range::default(),
+                String::new(),
             ),
-            Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
         ];
         let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
         expected.insert(
             "group1".to_string(),
             vec![
-                Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
-                Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
+                Lint::new(
+                    "should_assert_eq",
+                    "group1",
+                    "\"abc\"",
+                    "module_name",
+                    Range::default(),
+                    String::new(),
+                ),
+                Lint::new(
+                    "incorrect_match",
+                    "group1",
+                    "\"abc\"",
+                    "module_name",
+                    Range::default(),
+                    String::new(),
+                ),
             ],
         );
         expected.insert(
@@ -1217,6 +1331,7 @@ fn test_by_lint_group() {
                 "\"abc\"",
                 "module_name",
                 Range::default(),
+                String::new(),
             )],
         );
         assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
@@ -1255,9 +1370,30 @@ fn test_gen_deprecated() {
     #[test]
     fn test_gen_lint_group_list() {
         let lints = vec![
-            Lint::new("abc", "group1", "\"abc\"", "module_name", Range::default()),
-            Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
-            Lint::new("internal", "internal_style", "\"abc\"", "module_name", Range::default()),
+            Lint::new(
+                "abc",
+                "group1",
+                "\"abc\"",
+                "module_name",
+                Range::default(),
+                String::new(),
+            ),
+            Lint::new(
+                "should_assert_eq",
+                "group1",
+                "\"abc\"",
+                "module_name",
+                Range::default(),
+                String::new(),
+            ),
+            Lint::new(
+                "internal",
+                "internal_style",
+                "\"abc\"",
+                "module_name",
+                Range::default(),
+                String::new(),
+            ),
         ];
         let expected = GENERATED_FILE_COMMENT.to_string()
             + &[
index 27c2896e1e5cee71bfc27e48d7ecee0aff5edda5..9464694a3b55ad16e0531810740e49fefd80f255 100644 (file)
@@ -54,7 +54,7 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
                     hir_id: body.value.hir_id,
                 };
                 let typeck_results = cx.tcx.typeck_body(body_id);
-                let expr_ty = typeck_results.expr_ty(&body.value);
+                let expr_ty = typeck_results.expr_ty(body.value);
 
                 if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
                     let return_expr_span = match &body.value.kind {
index 4bcbeacf9feb59abd13704dcfcaf163bb31a4628..732dc2b433091b047abdffa296f7521ebbd7e3e9 100644 (file)
@@ -475,7 +475,7 @@ fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem
 
 fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
     if let ItemKind::Fn(_, _, eid) = item.kind {
-        is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
+        is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value)
     } else {
         true
     }
@@ -483,7 +483,7 @@ fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
 
 fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool {
     match item.kind {
-        ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value),
+        ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value),
         _ => false,
     }
 }
@@ -492,7 +492,7 @@ fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool {
     match item.kind {
         TraitItemKind::Fn(_, TraitFn::Required(_)) => true,
         TraitItemKind::Fn(_, TraitFn::Provided(eid)) => {
-            is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
+            is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value)
         },
         _ => false,
     }
diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
new file mode 100644 (file)
index 0000000..a4b8cbb
--- /dev/null
@@ -0,0 +1,125 @@
+use rustc_ast::{ExprPrecedence, LitKind};
+use rustc_hir::{Block, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, source::snippet_block_with_applicability};
+use rustc_errors::Applicability;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Instead of using an if statement to convert a bool to an int,
+    /// this lint suggests using a `from()` function or an `as` coercion.
+    ///
+    /// ### Why is this bad?
+    /// Coercion or `from()` is idiomatic way to convert bool to a number.
+    /// Both methods are guaranteed to return 1 for true, and 0 for false.
+    ///
+    /// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let condition = false;
+    /// if condition {
+    ///     1_i64
+    /// } else {
+    ///     0
+    /// };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # let condition = false;
+    /// i64::from(condition);
+    /// ```
+    /// or
+    /// ```rust
+    /// # let condition = false;
+    /// condition as i64;
+    /// ```
+    #[clippy::version = "1.65.0"]
+    pub BOOL_TO_INT_WITH_IF,
+    style,
+    "using if to convert bool to int"
+}
+declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
+
+impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
+    fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+        if !expr.span.from_expansion() {
+            check_if_else(ctx, expr);
+        }
+    }
+}
+
+fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+    if let ExprKind::If(check, then, Some(else_)) = expr.kind
+        && let Some(then_lit) = int_literal(then)
+        && let Some(else_lit) = int_literal(else_)
+        && check_int_literal_equals_val(then_lit, 1)
+        && check_int_literal_equals_val(else_lit, 0)
+    {
+        let mut applicability = Applicability::MachineApplicable;
+        let snippet = snippet_block_with_applicability(ctx, check.span, "..", None, &mut applicability);
+        let snippet_with_braces = {
+            let need_parens = should_have_parentheses(check);
+            let (left_paren, right_paren) = if need_parens {("(", ")")} else {("", "")};
+            format!("{left_paren}{snippet}{right_paren}")
+        };
+
+        let ty = ctx.typeck_results().expr_ty(then_lit); // then and else must be of same type
+
+        let suggestion = {
+            let wrap_in_curly = is_else_clause(ctx.tcx, expr);
+            let (left_curly, right_curly) = if wrap_in_curly {("{", "}")} else {("", "")};
+            format!(
+                "{left_curly}{ty}::from({snippet}){right_curly}"
+            )
+        }; // when used in else clause if statement should be wrapped in curly braces
+
+        span_lint_and_then(ctx,
+            BOOL_TO_INT_WITH_IF,
+            expr.span,
+            "boolean to int conversion using if",
+            |diag| {
+            diag.span_suggestion(
+                expr.span,
+                "replace with from",
+                suggestion,
+                applicability,
+            );
+            diag.note(format!("`{snippet_with_braces} as {ty}` or `{snippet_with_braces}.into()` can also be valid options"));
+        });
+    };
+}
+
+// If block contains only a int literal expression, return literal expression
+fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> {
+    if let ExprKind::Block(block, _) = expr.kind
+        && let Block {
+            stmts: [],       // Shouldn't lint if statements with side effects
+            expr: Some(expr),
+            ..
+        } = block
+        && let ExprKind::Lit(lit) = &expr.kind
+        && let LitKind::Int(_, _) = lit.node
+    {
+        Some(expr)
+    } else {
+        None
+    }
+}
+
+fn check_int_literal_equals_val<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>, expected_value: u128) -> bool {
+    if let ExprKind::Lit(lit) = &expr.kind
+        && let LitKind::Int(val, _) = lit.node
+        && val == expected_value
+    {
+        true
+    } else {
+        false
+    }
+}
+
+fn should_have_parentheses<'tcx>(check: &'tcx rustc_hir::Expr<'tcx>) -> bool {
+    check.precedence().order() < ExprPrecedence::Cast.order()
+}
index 74f7df611778ec32d61d9a056f23dccd727756ec..4e68d6810e29b0101aca9f22d8c454f5bdc65c38 100644 (file)
@@ -142,7 +142,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
                 if adt.is_struct();
                 let variant = adt.non_enum_variant();
                 if adt.did().is_local() || !variant.is_field_list_non_exhaustive();
-                let module_did = cx.tcx.parent_module(stmt.hir_id).to_def_id();
+                let module_did = cx.tcx.parent_module(stmt.hir_id);
                 if variant
                     .fields
                     .iter()
index 64c5de5104206c73ee9eecb29dced83d11cbf658..be02f328e989a67051091196a4d37a2bc8dc673b 100644 (file)
@@ -69,7 +69,10 @@ struct NumericFallbackVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
     fn new(cx: &'a LateContext<'tcx>) -> Self {
-        Self { ty_bounds: vec![TyBound::Nothing], cx }
+        Self {
+            ty_bounds: vec![TyBound::Nothing],
+            cx,
+        }
     }
 
     /// Check whether a passed literal has potential to cause fallback or not.
@@ -126,21 +129,19 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                     }
                     return;
                 }
-            }
+            },
 
             ExprKind::MethodCall(_, receiver, args, _) => {
                 if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
                     let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
-                    for (expr, bound) in
-                        iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs())
-                    {
+                    for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) {
                         self.ty_bounds.push(TyBound::Ty(*bound));
                         self.visit_expr(expr);
                         self.ty_bounds.pop();
                     }
                     return;
                 }
-            }
+            },
 
             ExprKind::Struct(_, fields, base) => {
                 let ty = self.cx.typeck_results().expr_ty(expr);
@@ -175,15 +176,15 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                         return;
                     }
                 }
-            }
+            },
 
             ExprKind::Lit(lit) => {
                 let ty = self.cx.typeck_results().expr_ty(expr);
                 self.check_lit(lit, ty, expr.hir_id);
                 return;
-            }
+            },
 
-            _ => {}
+            _ => {},
         }
 
         walk_expr(self, expr);
@@ -197,7 +198,7 @@ fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
                 } else {
                     self.ty_bounds.push(TyBound::Nothing);
                 }
-            }
+            },
 
             _ => self.ty_bounds.push(TyBound::Nothing),
         }
index ae509aab1525f68d2598e5d903ec3f085789166f..88e28018e5d00529f0f1a63da92e29075aec75cc 100644 (file)
@@ -830,25 +830,22 @@ fn walk_parents<'tcx>(
                             )
                         {
                             return Some(Position::MethodReceiverRefImpl)
-                        } else {
-                            return Some(Position::MethodReceiver)
                         }
+                        return Some(Position::MethodReceiver);
                     }
-                    args.iter()
-                        .position(|arg| arg.hir_id == child_id)
-                        .map(|i| {
-                            let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
-                            if let ty::Param(param_ty) = ty.kind() {
-                                needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv)
-                            } else {
-                                ty_auto_deref_stability(
-                                    cx,
-                                    cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
-                                    precedence,
-                                )
-                                .position_for_arg()
-                            }
-                        })
+                    args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
+                        let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
+                        if let ty::Param(param_ty) = ty.kind() {
+                            needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv)
+                        } else {
+                            ty_auto_deref_stability(
+                                cx,
+                                cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
+                                precedence,
+                            )
+                            .position_for_arg()
+                        }
+                    })
                 },
                 ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
                 ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
@@ -1175,7 +1172,7 @@ fn replace_types<'tcx>(
         if replaced.insert(param_ty.index) {
             for projection_predicate in projection_predicates {
                 if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx)
-                    && let ty::Term::Ty(term_ty) = projection_predicate.term
+                    && let Some(term_ty) = projection_predicate.term.ty()
                     && let ty::Param(term_param_ty) = term_ty.kind()
                 {
                     let item_def_id = projection_predicate.projection_ty.item_def_id;
index 4d7f4076d7b5134b85e08e04b254e420971f964f..ef9eeecc6a934f794859510ef414041e51509164 100644 (file)
@@ -40,7 +40,7 @@
     ///
     /// ### Known problems
     /// Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925)
-    /// in generic types and the user defined `impl` maybe is more generalized or
+    /// in generic types and the user defined `impl` may be more generalized or
     /// specialized than what derive will produce. This lint can't detect the manual `impl`
     /// has exactly equal bounds, and therefore this lint is disabled for types with
     /// generic parameters.
index 9ca443b7dff6cbe67a24c5008dee96d2d09be293..23c86482b46cb1186f9221d7c11f49c51cfea29d 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
     self, Binder, BoundConstness, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, TraitRef,
-    Ty, TyCtxt, Visibility,
+    Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
@@ -464,7 +464,7 @@ fn nested_visit_map(&mut self) -> Self::Map {
 fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
     if_chain! {
         if let ty::Adt(adt, substs) = ty.kind();
-        if cx.tcx.visibility(adt.did()) == Visibility::Public;
+        if cx.tcx.visibility(adt.did()).is_public();
         if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq);
         if let Some(def_id) = trait_ref.trait_def_id();
         if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id);
index 512872cedc1ea04d6f45be24bb378f77fa7372cf..eb158d850fa724b81a8ad83f209bd51697fa8e59 100644 (file)
@@ -236,7 +236,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                         typeck_results: cx.tcx.typeck(item.def_id),
                         panic_span: None,
                     };
-                    fpu.visit_expr(&body.value);
+                    fpu.visit_expr(body.value);
                     lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
                 }
             },
@@ -286,7 +286,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
                 typeck_results: cx.tcx.typeck(item.def_id),
                 panic_span: None,
             };
-            fpu.visit_expr(&body.value);
+            fpu.visit_expr(body.value);
             lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
         }
     }
@@ -348,7 +348,7 @@ fn lint_for_missing_headers<'tcx>(
                 if let Some(future) = cx.tcx.lang_items().future_trait();
                 let typeck = cx.tcx.typeck_body(body_id);
                 let body = cx.tcx.hir().body(body_id);
-                let ret_ty = typeck.expr_ty(&body.value);
+                let ret_ty = typeck.expr_ty(body.value);
                 if implements_trait(cx, ret_ty, future, &[]);
                 if let ty::Opaque(_, subs) = ret_ty.kind();
                 if let Some(gen) = subs.types().next();
@@ -828,7 +828,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-            let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
+            let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
             {
index fdfb821ac7895becb9fa97f56463dad42f0b7632..bce49165e5b18060f96430be8356f5fb979d14ac 100644 (file)
@@ -51,7 +51,9 @@ fn array_rec(pats: &[Pat<'_>]) -> bool {
             false
         },
         PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
-        PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a),
+        PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => {
+            !etc.as_opt_usize().is_some() && array_rec(a)
+        }
         PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),
         PatKind::Path(_) | PatKind::Lit(_) => true,
     }
index 1342a4697b991664122c18fe8071fda8054fa81c..53bc617a4f5b78929510599109619bcb29753018 100644 (file)
@@ -83,7 +83,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         };
         if body.value.span.from_expansion() {
             if body.params.is_empty() {
-                if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, &body.value) {
+                if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) {
                     // replace `|| vec![]` with `Vec::new`
                     span_lint_and_sugg(
                         cx,
@@ -103,7 +103,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let closure_ty = cx.typeck_results().expr_ty(expr);
 
         if_chain!(
-            if !is_adjusted(cx, &body.value);
+            if !is_adjusted(cx, body.value);
             if let ExprKind::Call(callee, args) = body.value.kind;
             if let ExprKind::Path(_) = callee.kind;
             if check_inputs(cx, body.params, None, args);
@@ -145,7 +145,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         );
 
         if_chain!(
-            if !is_adjusted(cx, &body.value);
+            if !is_adjusted(cx, body.value);
             if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind;
             if check_inputs(cx, body.params, Some(receiver), args);
             let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
@@ -206,8 +206,7 @@ fn check_inputs(
             _ => false,
         }
     };
-    std::iter::zip(params, receiver.into_iter().chain(call_args.iter()))
-        .all(|(param, arg)| check_inputs(param, arg))
+    std::iter::zip(params, receiver.into_iter().chain(call_args.iter())).all(|(param, arg)| check_inputs(param, arg))
 }
 
 fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
index 790eea63f58c49e048e58caf039c5e4360765a61..1f69f34a229df4952c4d3b6f5932d6b5b4450703 100644 (file)
@@ -84,7 +84,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 
             // check for `unwrap`
             if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-                let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
+                let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
                 if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                     || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
                 {
@@ -110,7 +110,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                     typeck_results: cx.tcx.typeck(impl_item.id.def_id),
                     result: Vec::new(),
                 };
-                fpu.visit_expr(&body.value);
+                fpu.visit_expr(body.value);
 
                 // if we've found one, lint
                 if !fpu.result.is_empty() {
index 728db41d600438e39803cc21dee554a1e0879820..ba53a9678801ce2fbfa407a5988356a2ef081a4e 100644 (file)
@@ -238,23 +238,23 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
 fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
     // Check receiver
     if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) {
-        let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
-            "exp"
+        if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
+            Some("exp")
         } else if F32(2.0) == value || F64(2.0) == value {
-            "exp2"
+            Some("exp2")
         } else {
-            return;
-        };
-
-        span_lint_and_sugg(
-            cx,
-            SUBOPTIMAL_FLOPS,
-            expr.span,
-            "exponent for bases 2 and e can be computed more accurately",
-            "consider using",
-            format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method),
-            Applicability::MachineApplicable,
-        );
+            None
+        } {
+            span_lint_and_sugg(
+                cx,
+                SUBOPTIMAL_FLOPS,
+                expr.span,
+                "exponent for bases 2 and e can be computed more accurately",
+                "consider using",
+                format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method),
+                Applicability::MachineApplicable,
+            );
+        }
     }
 
     // Check argument
index a17b23f5edc8609074d202d7f85d974be80d84dc..00a4937763eb5ad780c10c278f22531ec2ade832 100644 (file)
@@ -272,6 +272,6 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo
         cx,
         mutates_static: false,
     };
-    intravisit::walk_expr(&mut v, &body.value);
+    intravisit::walk_expr(&mut v, body.value);
     v.mutates_static
 }
index af520a493eda168b649d8bc9de9ce742de1b9169..9591405cb06f7b2d836d55f2c42148faf1ac0947 100644 (file)
@@ -4,7 +4,6 @@
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{sym, Span};
-use rustc_typeck::hir_ty_to_ty;
 
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
 use clippy_utils::trait_ref_of_method;
 fn result_err_ty<'tcx>(
     cx: &LateContext<'tcx>,
     decl: &hir::FnDecl<'tcx>,
+    id: hir::def_id::LocalDefId,
     item_span: Span,
 ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
     if !in_external_macro(cx.sess(), item_span)
         && let hir::FnRetTy::Return(hir_ty) = decl.output
-        && let ty = hir_ty_to_ty(cx.tcx, hir_ty)
+        && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).output())
         && is_type_diagnostic_item(cx, ty, sym::Result)
         && let ty::Adt(_, substs) = ty.kind()
     {
@@ -34,7 +34,7 @@ fn result_err_ty<'tcx>(
 
 pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) {
     if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind
-        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span)
+        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span)
     {
         if cx.access_levels.is_exported(item.def_id) {
             let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@@ -47,7 +47,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, l
 pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) {
     // Don't lint if method is a trait's implementation, we can't do anything about those
     if let hir::ImplItemKind::Fn(ref sig, _) = item.kind
-        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span)
+        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span)
         && trait_ref_of_method(cx, item.def_id).is_none()
     {
         if cx.access_levels.is_exported(item.def_id) {
@@ -61,7 +61,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) {
     if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) {
+        if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) {
             if cx.access_levels.is_exported(item.def_id) {
                 check_result_unit_err(cx, err_ty, fn_header_span);
             }
index a6610ade37e56291400196d6ab02553ba11abe7f..feec8ec2e23f8f802c2b249f0931427eea795162 100644 (file)
@@ -232,7 +232,7 @@ fn check_fn(
             return;
         }
 
-        let res_ty = cx.typeck_results().expr_ty(&body.value);
+        let res_ty = cx.typeck_results().expr_ty(body.value);
         if res_ty.is_unit() || res_ty.is_never() {
             return;
         }
@@ -243,7 +243,7 @@ fn check_fn(
                 None => return,
             }
         } else {
-            &body.value
+            body.value
         };
         lint_implicit_returns(cx, expr, expr.span.ctxt(), None);
     }
index d55a8e1ead17d11eb02f135c361010dca7fb9a2c..8c2c96fa105af251ec8796c5e76d122d89394694 100644 (file)
@@ -59,7 +59,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"),
             Finite => {
                 return;
-            }
+            },
         };
         span_lint(cx, lint, expr.span, msg);
     }
@@ -161,7 +161,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
             if method.ident.name == sym!(flat_map) && args.len() == 1 {
                 if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind {
                     let body = cx.tcx.hir().body(body);
-                    return is_infinite(cx, &body.value);
+                    return is_infinite(cx, body.value);
                 }
             }
             Finite
@@ -230,8 +230,10 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                 }
             }
             if method.ident.name == sym!(last) && args.is_empty() {
-                let not_double_ended =
-                    cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator).map_or(false, |id| {
+                let not_double_ended = cx
+                    .tcx
+                    .get_diagnostic_item(sym::DoubleEndedIterator)
+                    .map_or(false, |id| {
                         !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[])
                     });
                 if not_double_ended {
index c58df126d62442a056d63437518699c3d189012c..eb13d0869c037d522b4b3d34b0a66886c7f324db 100644 (file)
@@ -1,13 +1,12 @@
 //! lint when there is a large size difference between variants on an enum
 
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{diagnostics::span_lint_and_then, ty::is_copy};
+use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size, ty::is_copy};
 use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{Adt, Ty};
+use rustc_middle::ty::{Adt, AdtDef, GenericArg, List, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 
@@ -17,7 +16,7 @@
     /// `enum`s.
     ///
     /// ### Why is this bad?
-    /// Enum size is bounded by the largest variant. Having a
+    /// Enum size is bounded by the largest variant. Having one
     /// large variant can penalize the memory layout of that enum.
     ///
     /// ### Known problems
@@ -33,8 +32,9 @@
     /// use case it may be possible to store the large data in an auxiliary
     /// structure (e.g. Arena or ECS).
     ///
-    /// The lint will ignore generic types if the layout depends on the
-    /// generics, even if the size difference will be large anyway.
+    /// The lint will ignore the impact of generic types to the type layout by
+    /// assuming every type parameter is zero-sized. Depending on your use case,
+    /// this may lead to a false positive.
     ///
     /// ### Example
     /// ```rust
@@ -83,6 +83,38 @@ struct VariantInfo {
     fields_size: Vec<FieldInfo>,
 }
 
+fn variants_size<'tcx>(
+    cx: &LateContext<'tcx>,
+    adt: AdtDef<'tcx>,
+    subst: &'tcx List<GenericArg<'tcx>>,
+) -> Vec<VariantInfo> {
+    let mut variants_size = adt
+        .variants()
+        .iter()
+        .enumerate()
+        .map(|(i, variant)| {
+            let mut fields_size = variant
+                .fields
+                .iter()
+                .enumerate()
+                .map(|(i, f)| FieldInfo {
+                    ind: i,
+                    size: approx_ty_size(cx, f.ty(cx.tcx, subst)),
+                })
+                .collect::<Vec<_>>();
+            fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
+
+            VariantInfo {
+                ind: i,
+                size: fields_size.iter().map(|info| info.size).sum(),
+                fields_size,
+            }
+        })
+        .collect::<Vec<_>>();
+    variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
+    variants_size
+}
+
 impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
@@ -92,36 +124,14 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
             let ty = cx.tcx.type_of(item.def_id);
-            let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
+            let (adt, subst) = match ty.kind() {
+                Adt(adt, subst) => (adt, subst),
+                _ => panic!("already checked whether this is an enum"),
+            };
             if adt.variants().len() <= 1 {
                 return;
             }
-            let mut variants_size: Vec<VariantInfo> = Vec::new();
-            for (i, variant) in adt.variants().iter().enumerate() {
-                let mut fields_size = Vec::new();
-                for (i, f) in variant.fields.iter().enumerate() {
-                    let ty = cx.tcx.type_of(f.did);
-                    // don't lint variants which have a field of generic type.
-                    match cx.layout_of(ty) {
-                        Ok(l) => {
-                            let fsize = l.size.bytes();
-                            fields_size.push(FieldInfo { ind: i, size: fsize });
-                        },
-                        Err(_) => {
-                            return;
-                        },
-                    }
-                }
-                let size: u64 = fields_size.iter().map(|info| info.size).sum();
-
-                variants_size.push(VariantInfo {
-                    ind: i,
-                    size,
-                    fields_size,
-                });
-            }
-
-            variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
+            let variants_size = variants_size(cx, *adt, subst);
 
             let mut difference = variants_size[0].size - variants_size[1].size;
             if difference > self.maximum_size_difference_allowed {
@@ -129,20 +139,30 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
                 span_lint_and_then(
                     cx,
                     LARGE_ENUM_VARIANT,
-                    def.variants[variants_size[0].ind].span,
+                    item.span,
                     "large size difference between variants",
                     |diag| {
+                        diag.span_label(
+                            item.span,
+                            format!("the entire enum is at least {} bytes", approx_ty_size(cx, ty)),
+                        );
                         diag.span_label(
                             def.variants[variants_size[0].ind].span,
-                            &format!("this variant is {} bytes", variants_size[0].size),
+                            format!("the largest variant contains at least {} bytes", variants_size[0].size),
                         );
-                        diag.span_note(
+                        diag.span_label(
                             def.variants[variants_size[1].ind].span,
-                            &format!("and the second-largest variant is {} bytes:", variants_size[1].size),
+                            &if variants_size[1].fields_size.is_empty() {
+                                "the second-largest variant carries no data at all".to_owned()
+                            } else {
+                                format!(
+                                    "the second-largest variant contains at least {} bytes",
+                                    variants_size[1].size
+                                )
+                            },
                         );
 
                         let fields = def.variants[variants_size[0].ind].data.fields();
-                        variants_size[0].fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
                         let mut applicability = Applicability::MaybeIncorrect;
                         if is_copy(cx, ty) || maybe_copy(cx, ty) {
                             diag.span_note(
index 3cbdaff407b04383f07bf24c84dfb71d52bed93d..7ae8ef830faea952e65ef77b77e83dcffcbcc2f1 100644 (file)
@@ -370,7 +370,8 @@ fn check_for_is_empty<'tcx>(
 }
 
 fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
-    if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
+    if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind)
+    {
         // check if we are in an is_empty() method
         if let Some(name) = get_item_name(cx, method) {
             if name.as_str() == "is_empty" {
@@ -378,12 +379,23 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
             }
         }
 
-        check_len(cx, span, method_path.ident.name, receiver, args, &lit.node, op, compare_to);
+        check_len(
+            cx,
+            span,
+            method_path.ident.name,
+            receiver,
+            args,
+            &lit.node,
+            op,
+            compare_to,
+        );
     } else {
         check_empty_expr(cx, span, method, lit, op);
     }
 }
 
+// FIXME(flip1995): Figure out how to reduce the number of arguments
+#[allow(clippy::too_many_arguments)]
 fn check_len(
     cx: &LateContext<'_>,
     span: Span,
index 134cbbf7b5c66ad5f218173022533dc55b19c77b..1f85382347aa1d992ad9ccc526ceb52e818de481 100644 (file)
@@ -17,6 +17,7 @@
     LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
     LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
+    LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
     LintId::of(booleans::NONMINIMAL_BOOL),
     LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
     LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
index fd20e016578a1bad268088cfe5dac73f0182b881..962e67220069a604992b0040cf38afec55d06656 100644 (file)
@@ -56,6 +56,7 @@
     await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
     blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
     bool_assert_comparison::BOOL_ASSERT_COMPARISON,
+    bool_to_int_with_if::BOOL_TO_INT_WITH_IF,
     booleans::NONMINIMAL_BOOL,
     booleans::OVERLY_COMPLEX_BOOL_EXPR,
     borrow_deref_ref::BORROW_DEREF_REF,
     octal_escapes::OCTAL_ESCAPES,
     only_used_in_recursion::ONLY_USED_IN_RECURSION,
     operators::ABSURD_EXTREME_COMPARISONS,
-    operators::ARITHMETIC,
+    operators::ARITHMETIC_SIDE_EFFECTS,
     operators::ASSIGN_OP_PATTERN,
     operators::BAD_BIT_MASK,
     operators::CMP_NAN,
index dd1e1e1a8e33d82088578a75adcaa49cf7db7128..6eb9b3d3b9b7aa61be5ce4de886d42d3c3dabd14 100644 (file)
@@ -50,7 +50,7 @@
     LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION),
     LintId::of(module_style::MOD_MODULE_FILES),
     LintId::of(module_style::SELF_NAMED_MODULE_FILES),
-    LintId::of(operators::ARITHMETIC),
+    LintId::of(operators::ARITHMETIC_SIDE_EFFECTS),
     LintId::of(operators::FLOAT_ARITHMETIC),
     LintId::of(operators::FLOAT_CMP_CONST),
     LintId::of(operators::INTEGER_ARITHMETIC),
index b5cb078e7a3ccce2fc5a8f0b7ed93b68cca24585..05d2ec2e9e1e6002c1d2c3eb2eff1842b49a2da6 100644 (file)
@@ -6,6 +6,7 @@
     LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
     LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
+    LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
     LintId::of(casts::FN_TO_NUMERIC_CAST),
     LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
     LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
index dfdaf90f09f48151eda7964dd3d2a02cba705271..e984254bf2919ae397bc80e990fd9b24ba28108c 100644 (file)
@@ -179,6 +179,7 @@ macro_rules! declare_clippy_lint {
 mod await_holding_invalid;
 mod blocks_in_if_conditions;
 mod bool_assert_comparison;
+mod bool_to_int_with_if;
 mod booleans;
 mod borrow_deref_ref;
 mod cargo;
@@ -533,69 +534,73 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     {
         store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal));
         store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce));
-        store.register_late_pass(|| Box::new(utils::internal_lints::CollapsibleCalls));
-        store.register_late_pass(|| Box::new(utils::internal_lints::CompilerLintFunctions::new()));
-        store.register_late_pass(|| Box::new(utils::internal_lints::IfChainStyle));
-        store.register_late_pass(|| Box::new(utils::internal_lints::InvalidPaths));
-        store.register_late_pass(|| Box::new(utils::internal_lints::InterningDefinedSymbol::default()));
-        store.register_late_pass(|| Box::new(utils::internal_lints::LintWithoutLintPass::default()));
-        store.register_late_pass(|| Box::new(utils::internal_lints::MatchTypeOnDiagItem));
-        store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass));
-        store.register_late_pass(|| Box::new(utils::internal_lints::MsrvAttrImpl));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::CollapsibleCalls));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::CompilerLintFunctions::new()));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::IfChainStyle));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::InvalidPaths));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::InterningDefinedSymbol::default()));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::LintWithoutLintPass::default()));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::MatchTypeOnDiagItem));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::OuterExpnDataPass));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::MsrvAttrImpl));
     }
 
-    let arithmetic_allowed = conf.arithmetic_allowed.clone();
-    store.register_late_pass(move || Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone())));
-    store.register_late_pass(|| Box::new(utils::dump_hir::DumpHir));
-    store.register_late_pass(|| Box::new(utils::author::Author));
+    let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone();
+    store.register_late_pass(move |_| {
+        Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(
+            arithmetic_side_effects_allowed.clone(),
+        ))
+    });
+    store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
+    store.register_late_pass(|_| Box::new(utils::author::Author));
     let await_holding_invalid_types = conf.await_holding_invalid_types.clone();
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(await_holding_invalid::AwaitHolding::new(
             await_holding_invalid_types.clone(),
         ))
     });
-    store.register_late_pass(|| Box::new(serde_api::SerdeApi));
+    store.register_late_pass(|_| Box::new(serde_api::SerdeApi));
     let vec_box_size_threshold = conf.vec_box_size_threshold;
     let type_complexity_threshold = conf.type_complexity_threshold;
     let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(types::Types::new(
             vec_box_size_threshold,
             type_complexity_threshold,
             avoid_breaking_exported_api,
         ))
     });
-    store.register_late_pass(|| Box::new(booleans::NonminimalBool));
-    store.register_late_pass(|| Box::new(enum_clike::UnportableVariant));
-    store.register_late_pass(|| Box::new(float_literal::FloatLiteral));
-    store.register_late_pass(|| Box::new(ptr::Ptr));
-    store.register_late_pass(|| Box::new(needless_bool::NeedlessBool));
-    store.register_late_pass(|| Box::new(needless_bool::BoolComparison));
-    store.register_late_pass(|| Box::new(needless_for_each::NeedlessForEach));
-    store.register_late_pass(|| Box::new(misc::MiscLints));
-    store.register_late_pass(|| Box::new(eta_reduction::EtaReduction));
-    store.register_late_pass(|| Box::new(mut_mut::MutMut));
-    store.register_late_pass(|| Box::new(mut_reference::UnnecessaryMutPassed));
-    store.register_late_pass(|| Box::new(len_zero::LenZero));
-    store.register_late_pass(|| Box::new(attrs::Attributes));
-    store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
-    store.register_late_pass(|| Box::new(unicode::Unicode));
-    store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
-    store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
-    store.register_late_pass(|| Box::new(strings::StringAdd));
-    store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
-    store.register_late_pass(|| Box::new(implicit_saturating_sub::ImplicitSaturatingSub));
-    store.register_late_pass(|| Box::new(default_numeric_fallback::DefaultNumericFallback));
-    store.register_late_pass(|| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
-    store.register_late_pass(|| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
+    store.register_late_pass(|_| Box::new(booleans::NonminimalBool));
+    store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant));
+    store.register_late_pass(|_| Box::new(float_literal::FloatLiteral));
+    store.register_late_pass(|_| Box::new(ptr::Ptr));
+    store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool));
+    store.register_late_pass(|_| Box::new(needless_bool::BoolComparison));
+    store.register_late_pass(|_| Box::new(needless_for_each::NeedlessForEach));
+    store.register_late_pass(|_| Box::new(misc::MiscLints));
+    store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
+    store.register_late_pass(|_| Box::new(mut_mut::MutMut));
+    store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
+    store.register_late_pass(|_| Box::new(len_zero::LenZero));
+    store.register_late_pass(|_| Box::new(attrs::Attributes));
+    store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
+    store.register_late_pass(|_| Box::new(unicode::Unicode));
+    store.register_late_pass(|_| Box::new(uninit_vec::UninitVec));
+    store.register_late_pass(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
+    store.register_late_pass(|_| Box::new(strings::StringAdd));
+    store.register_late_pass(|_| Box::new(implicit_return::ImplicitReturn));
+    store.register_late_pass(|_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub));
+    store.register_late_pass(|_| Box::new(default_numeric_fallback::DefaultNumericFallback));
+    store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
+    store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
     store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
 
     let msrv = read_msrv(conf, sess);
     let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
     let allow_expect_in_tests = conf.allow_expect_in_tests;
     let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
-    store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv)));
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv)));
+    store.register_late_pass(move |_| {
         Box::new(methods::Methods::new(
             avoid_breaking_exported_api,
             msrv,
@@ -603,74 +608,74 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
             allow_unwrap_in_tests,
         ))
     });
-    store.register_late_pass(move || Box::new(matches::Matches::new(msrv)));
+    store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv)));
     store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv)));
-    store.register_late_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));
-    store.register_late_pass(move || Box::new(manual_strip::ManualStrip::new(msrv)));
+    store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));
+    store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv)));
     store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv)));
     store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv)));
-    store.register_late_pass(move || Box::new(checked_conversions::CheckedConversions::new(msrv)));
-    store.register_late_pass(move || Box::new(mem_replace::MemReplace::new(msrv)));
-    store.register_late_pass(move || Box::new(ranges::Ranges::new(msrv)));
-    store.register_late_pass(move || Box::new(from_over_into::FromOverInto::new(msrv)));
-    store.register_late_pass(move || Box::new(use_self::UseSelf::new(msrv)));
-    store.register_late_pass(move || Box::new(missing_const_for_fn::MissingConstForFn::new(msrv)));
-    store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark));
-    store.register_late_pass(move || Box::new(casts::Casts::new(msrv)));
+    store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv)));
+    store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv)));
+    store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv)));
+    store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv)));
+    store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv)));
+    store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv)));
+    store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark));
+    store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv)));
     store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv)));
-    store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount));
-    store.register_late_pass(|| Box::new(same_name_method::SameNameMethod));
+    store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount));
+    store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod));
     let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(index_refutable_slice::IndexRefutableSlice::new(
             max_suggested_slice_pattern_length,
             msrv,
         ))
     });
-    store.register_late_pass(|| Box::new(shadow::Shadow::default()));
-    store.register_late_pass(|| Box::new(unit_types::UnitTypes));
-    store.register_late_pass(|| Box::new(loops::Loops));
-    store.register_late_pass(|| Box::new(main_recursion::MainRecursion::default()));
-    store.register_late_pass(|| Box::new(lifetimes::Lifetimes));
-    store.register_late_pass(|| Box::new(entry::HashMapPass));
-    store.register_late_pass(|| Box::new(minmax::MinMaxPass));
-    store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv));
-    store.register_late_pass(|| Box::new(mutex_atomic::Mutex));
-    store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate));
-    store.register_late_pass(|| Box::new(needless_borrowed_ref::NeedlessBorrowedRef));
-    store.register_late_pass(|| Box::new(borrow_deref_ref::BorrowDerefRef));
-    store.register_late_pass(|| Box::new(no_effect::NoEffect));
-    store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment));
-    store.register_late_pass(move || Box::new(transmute::Transmute::new(msrv)));
+    store.register_late_pass(|_| Box::new(shadow::Shadow::default()));
+    store.register_late_pass(|_| Box::new(unit_types::UnitTypes));
+    store.register_late_pass(|_| Box::new(loops::Loops));
+    store.register_late_pass(|_| Box::new(main_recursion::MainRecursion::default()));
+    store.register_late_pass(|_| Box::new(lifetimes::Lifetimes));
+    store.register_late_pass(|_| Box::new(entry::HashMapPass));
+    store.register_late_pass(|_| Box::new(minmax::MinMaxPass));
+    store.register_late_pass(|_| Box::new(zero_div_zero::ZeroDiv));
+    store.register_late_pass(|_| Box::new(mutex_atomic::Mutex));
+    store.register_late_pass(|_| Box::new(needless_update::NeedlessUpdate));
+    store.register_late_pass(|_| Box::new(needless_borrowed_ref::NeedlessBorrowedRef));
+    store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef));
+    store.register_late_pass(|_| Box::new(no_effect::NoEffect));
+    store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment));
+    store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv)));
     let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(cognitive_complexity::CognitiveComplexity::new(
             cognitive_complexity_threshold,
         ))
     });
     let too_large_for_stack = conf.too_large_for_stack;
-    store.register_late_pass(move || Box::new(escape::BoxedLocal { too_large_for_stack }));
-    store.register_late_pass(move || Box::new(vec::UselessVec { too_large_for_stack }));
-    store.register_late_pass(|| Box::new(panic_unimplemented::PanicUnimplemented));
-    store.register_late_pass(|| Box::new(strings::StringLitAsBytes));
-    store.register_late_pass(|| Box::new(derive::Derive));
-    store.register_late_pass(|| Box::new(derivable_impls::DerivableImpls));
-    store.register_late_pass(|| Box::new(drop_forget_ref::DropForgetRef));
-    store.register_late_pass(|| Box::new(empty_enum::EmptyEnum));
-    store.register_late_pass(|| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
-    store.register_late_pass(|| Box::new(regex::Regex));
-    store.register_late_pass(|| Box::new(copies::CopyAndPaste));
-    store.register_late_pass(|| Box::new(copy_iterator::CopyIterator));
-    store.register_late_pass(|| Box::new(format::UselessFormat));
-    store.register_late_pass(|| Box::new(swap::Swap));
-    store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional));
-    store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default()));
+    store.register_late_pass(move |_| Box::new(escape::BoxedLocal { too_large_for_stack }));
+    store.register_late_pass(move |_| Box::new(vec::UselessVec { too_large_for_stack }));
+    store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented));
+    store.register_late_pass(|_| Box::new(strings::StringLitAsBytes));
+    store.register_late_pass(|_| Box::new(derive::Derive));
+    store.register_late_pass(|_| Box::new(derivable_impls::DerivableImpls));
+    store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef));
+    store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
+    store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
+    store.register_late_pass(|_| Box::new(regex::Regex));
+    store.register_late_pass(|_| Box::new(copies::CopyAndPaste));
+    store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
+    store.register_late_pass(|_| Box::new(format::UselessFormat));
+    store.register_late_pass(|_| Box::new(swap::Swap));
+    store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional));
+    store.register_late_pass(|_| Box::new(new_without_default::NewWithoutDefault::default()));
     let disallowed_names = conf.disallowed_names.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone())));
+    store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone())));
     let too_many_arguments_threshold = conf.too_many_arguments_threshold;
     let too_many_lines_threshold = conf.too_many_lines_threshold;
     let large_error_threshold = conf.large_error_threshold;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(functions::Functions::new(
             too_many_arguments_threshold,
             too_many_lines_threshold,
@@ -678,73 +683,73 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         ))
     });
     let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
-    store.register_late_pass(|| Box::new(neg_multiply::NegMultiply));
-    store.register_late_pass(|| Box::new(mem_forget::MemForget));
-    store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq));
-    store.register_late_pass(|| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
-    store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new()));
-    store.register_late_pass(|| Box::new(missing_inline::MissingInline));
-    store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems));
-    store.register_late_pass(|| Box::new(match_result_ok::MatchResultOk));
-    store.register_late_pass(|| Box::new(partialeq_ne_impl::PartialEqNeImpl));
-    store.register_late_pass(|| Box::new(unused_io_amount::UnusedIoAmount));
+    store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
+    store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply));
+    store.register_late_pass(|_| Box::new(mem_forget::MemForget));
+    store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq));
+    store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
+    store.register_late_pass(|_| Box::new(missing_doc::MissingDoc::new()));
+    store.register_late_pass(|_| Box::new(missing_inline::MissingInline));
+    store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems));
+    store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk));
+    store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl));
+    store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount));
     let enum_variant_size_threshold = conf.enum_variant_size_threshold;
-    store.register_late_pass(move || Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
-    store.register_late_pass(|| Box::new(explicit_write::ExplicitWrite));
-    store.register_late_pass(|| Box::new(needless_pass_by_value::NeedlessPassByValue));
+    store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
+    store.register_late_pass(|_| Box::new(explicit_write::ExplicitWrite));
+    store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue));
     let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
         conf.trivial_copy_size_limit,
         conf.pass_by_value_size_limit,
         conf.avoid_breaking_exported_api,
         &sess.target,
     );
-    store.register_late_pass(move || Box::new(pass_by_ref_or_value));
-    store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef));
-    store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter));
-    store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody));
-    store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default()));
-    store.register_late_pass(|| Box::new(implicit_hasher::ImplicitHasher));
-    store.register_late_pass(|| Box::new(fallible_impl_from::FallibleImplFrom));
-    store.register_late_pass(|| Box::new(question_mark::QuestionMark));
+    store.register_late_pass(move |_| Box::new(pass_by_ref_or_value));
+    store.register_late_pass(|_| Box::new(ref_option_ref::RefOptionRef));
+    store.register_late_pass(|_| Box::new(infinite_iter::InfiniteIter));
+    store.register_late_pass(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody));
+    store.register_late_pass(|_| Box::new(useless_conversion::UselessConversion::default()));
+    store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
+    store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
+    store.register_late_pass(|_| Box::new(question_mark::QuestionMark));
     store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
-    store.register_late_pass(|| Box::new(suspicious_trait_impl::SuspiciousImpl));
-    store.register_late_pass(|| Box::new(map_unit_fn::MapUnit));
-    store.register_late_pass(|| Box::new(inherent_impl::MultipleInherentImpl));
-    store.register_late_pass(|| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
-    store.register_late_pass(|| Box::new(unwrap::Unwrap));
-    store.register_late_pass(|| Box::new(indexing_slicing::IndexingSlicing));
-    store.register_late_pass(|| Box::new(non_copy_const::NonCopyConst));
-    store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
-    store.register_late_pass(|| Box::new(redundant_clone::RedundantClone));
-    store.register_late_pass(|| Box::new(slow_vector_initialization::SlowVectorInit));
-    store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
-    store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants));
-    store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates));
-    store.register_late_pass(|| Box::new(inherent_to_string::InherentToString));
+    store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
+    store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit));
+    store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl));
+    store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
+    store.register_late_pass(|_| Box::new(unwrap::Unwrap));
+    store.register_late_pass(|_| Box::new(indexing_slicing::IndexingSlicing));
+    store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst));
+    store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
+    store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
+    store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit));
+    store.register_late_pass(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
+    store.register_late_pass(|_| Box::new(assertions_on_constants::AssertionsOnConstants));
+    store.register_late_pass(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates));
+    store.register_late_pass(|_| Box::new(inherent_to_string::InherentToString));
     let max_trait_bounds = conf.max_trait_bounds;
-    store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
-    store.register_late_pass(|| Box::new(comparison_chain::ComparisonChain));
-    store.register_late_pass(|| Box::new(mut_key::MutableKeyType));
+    store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
+    store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain));
+    store.register_late_pass(|_| Box::new(mut_key::MutableKeyType));
     store.register_early_pass(|| Box::new(reference::DerefAddrOf));
     store.register_early_pass(|| Box::new(double_parens::DoubleParens));
-    store.register_late_pass(|| Box::new(format_impl::FormatImpl::new()));
+    store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new()));
     store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
     store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
     store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
     store.register_early_pass(|| Box::new(formatting::Formatting));
     store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints));
     store.register_early_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
-    store.register_late_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
+    store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall));
     store.register_early_pass(|| Box::new(unused_unit::UnusedUnit));
-    store.register_late_pass(|| Box::new(returns::Return));
+    store.register_late_pass(|_| Box::new(returns::Return));
     store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf));
     store.register_early_pass(|| Box::new(items_after_statements::ItemsAfterStatements));
     store.register_early_pass(|| Box::new(precedence::Precedence));
-    store.register_late_pass(|| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
+    store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
     store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue));
     store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
-    store.register_late_pass(|| Box::new(create_dir::CreateDir));
+    store.register_late_pass(|_| Box::new(create_dir::CreateDir));
     store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
     let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
     store.register_early_pass(move || {
@@ -759,7 +764,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         ))
     });
     let enum_variant_name_threshold = conf.enum_variant_name_threshold;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(enum_variants::EnumVariantNames::new(
             enum_variant_name_threshold,
             avoid_breaking_exported_api,
@@ -767,23 +772,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
     let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(upper_case_acronyms::UpperCaseAcronyms::new(
             avoid_breaking_exported_api,
             upper_case_acronyms_aggressive,
         ))
     });
-    store.register_late_pass(|| Box::new(default::Default::default()));
-    store.register_late_pass(move || Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api)));
-    store.register_late_pass(|| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
-    store.register_late_pass(|| Box::new(exit::Exit));
-    store.register_late_pass(|| Box::new(to_digit_is_some::ToDigitIsSome));
+    store.register_late_pass(|_| Box::new(default::Default::default()));
+    store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api)));
+    store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
+    store.register_late_pass(|_| Box::new(exit::Exit));
+    store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome));
     let array_size_threshold = conf.array_size_threshold;
-    store.register_late_pass(move || Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold)));
-    store.register_late_pass(move || Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold)));
-    store.register_late_pass(|| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
+    store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold)));
+    store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold)));
+    store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
     store.register_early_pass(|| Box::new(as_conversions::AsConversions));
-    store.register_late_pass(|| Box::new(let_underscore::LetUnderscore));
+    store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore));
     store.register_early_pass(|| Box::new(single_component_path_imports::SingleComponentPathImports));
     let max_fn_params_bools = conf.max_fn_params_bools;
     let max_struct_bools = conf.max_struct_bools;
@@ -795,17 +800,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
     let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
-    store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
-    store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default()));
-    store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress));
-    store.register_late_pass(move || Box::new(dereference::Dereferencing::new(msrv)));
-    store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse));
-    store.register_late_pass(|| Box::new(future_not_send::FutureNotSend));
-    store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex));
-    store.register_late_pass(|| Box::new(if_not_else::IfNotElse));
-    store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
-    store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn));
-    store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn));
+    store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
+    store.register_late_pass(|_| Box::new(redundant_pub_crate::RedundantPubCrate::default()));
+    store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
+    store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv)));
+    store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
+    store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend));
+    store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex));
+    store.register_late_pass(|_| Box::new(if_not_else::IfNotElse));
+    store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality));
+    store.register_late_pass(|_| Box::new(manual_async_fn::ManualAsyncFn));
+    store.register_late_pass(|_| Box::new(panic_in_result_fn::PanicInResultFn));
     let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
     store.register_early_pass(move || {
         Box::new(non_expressive_names::NonExpressiveNames {
@@ -814,93 +819,94 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::<FxHashSet<_>>();
     store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(&macro_matcher)));
-    store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default()));
-    store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch));
-    store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult));
-    store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
-    store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
+    store.register_late_pass(|_| Box::new(macro_use::MacroUseImports::default()));
+    store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch));
+    store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult));
+    store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
+    store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync));
     let disallowed_methods = conf.disallowed_methods.clone();
-    store.register_late_pass(move || Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
+    store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
     store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
     store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
-    store.register_late_pass(|| Box::new(empty_drop::EmptyDrop));
-    store.register_late_pass(|| Box::new(strings::StrToString));
-    store.register_late_pass(|| Box::new(strings::StringToString));
-    store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues));
-    store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default()));
-    store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing));
-    store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10));
-    store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
-    store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison));
+    store.register_late_pass(|_| Box::new(empty_drop::EmptyDrop));
+    store.register_late_pass(|_| Box::new(strings::StrToString));
+    store.register_late_pass(|_| Box::new(strings::StringToString));
+    store.register_late_pass(|_| Box::new(zero_sized_map_values::ZeroSizedMapValues));
+    store.register_late_pass(|_| Box::new(vec_init_then_push::VecInitThenPush::default()));
+    store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing));
+    store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10));
+    store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
+    store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
     store.register_early_pass(move || Box::new(module_style::ModStyle));
-    store.register_late_pass(|| Box::new(unused_async::UnusedAsync));
+    store.register_late_pass(|_| Box::new(unused_async::UnusedAsync));
     let disallowed_types = conf.disallowed_types.clone();
-    store.register_late_pass(move || Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
+    store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
     let import_renames = conf.enforced_import_renames.clone();
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(missing_enforced_import_rename::ImportRename::new(
             import_renames.clone(),
         ))
     });
     let scripts = conf.allowed_scripts.clone();
     store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts)));
-    store.register_late_pass(|| Box::new(strlen_on_c_strings::StrlenOnCStrings));
-    store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors));
-    store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
-    store.register_late_pass(move || Box::new(manual_assert::ManualAssert));
+    store.register_late_pass(|_| Box::new(strlen_on_c_strings::StrlenOnCStrings));
+    store.register_late_pass(move |_| Box::new(self_named_constructors::SelfNamedConstructors));
+    store.register_late_pass(move |_| Box::new(iter_not_returning_iterator::IterNotReturningIterator));
+    store.register_late_pass(move |_| Box::new(manual_assert::ManualAssert));
     let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(
             enable_raw_pointer_heuristic_for_send,
         ))
     });
-    store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
-    store.register_late_pass(move || Box::new(format_args::FormatArgs));
-    store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
+    store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
+    store.register_late_pass(move |_| Box::new(format_args::FormatArgs));
+    store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
     store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
-    store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
-    store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
-    store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields));
+    store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
+    store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
+    store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields));
     store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
-    store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv)));
-    store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation));
+    store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv)));
+    store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
     store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes));
-    store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion::default()));
+    store.register_late_pass(|_| Box::new(only_used_in_recursion::OnlyUsedInRecursion::default()));
     let allow_dbg_in_tests = conf.allow_dbg_in_tests;
-    store.register_late_pass(move || Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
+    store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
     let cargo_ignore_publish = conf.cargo_ignore_publish;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(cargo::Cargo {
             ignore_publish: cargo_ignore_publish,
         })
     });
     store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
     store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
-    store.register_late_pass(|| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
+    store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
     store.register_early_pass(|| Box::new(pub_use::PubUse));
-    store.register_late_pass(|| Box::new(format_push_string::FormatPushString));
+    store.register_late_pass(|_| Box::new(format_push_string::FormatPushString));
     let max_include_file_size = conf.max_include_file_size;
-    store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
-    store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace));
-    store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
+    store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
+    store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace));
+    store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
     store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default()));
     store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
     store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv)));
-    store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef));
-    store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch));
-    store.register_late_pass(|| Box::new(read_zero_byte_vec::ReadZeroByteVec));
-    store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
-    store.register_late_pass(move || Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv)));
-    store.register_late_pass(move || Box::new(manual_retain::ManualRetain::new(msrv)));
+    store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
+    store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch));
+    store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec));
+    store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
+    store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv)));
+    store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv)));
     let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
-    store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
-    store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
-    store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default()));
-    store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed));
-    store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone));
-    store.register_late_pass(|| Box::new(manual_string_new::ManualStringNew));
-    store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable));
+    store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
+    store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
+    store.register_late_pass(|_| Box::new(std_instead_of_core::StdReexports::default()));
+    store.register_late_pass(|_| Box::new(manual_instant_elapsed::ManualInstantElapsed));
+    store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
+    store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
+    store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable));
     store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
+    store.register_late_pass(|_| Box::new(bool_to_int_with_if::BoolToIntWithIf));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
index 573a7c016b8e8c8c6d708fccb3ccd42c0f6f2792..f2b6e0b7ef9ba933b0ec5e1e7cef7f4195fe514a 100644 (file)
@@ -276,7 +276,7 @@ fn could_use_elision<'tcx>(
         let mut checker = BodyLifetimeChecker {
             lifetimes_used_in_body: false,
         };
-        checker.visit_expr(&body.value);
+        checker.visit_expr(body.value);
         if checker.lifetimes_used_in_body {
             return false;
         }
@@ -441,7 +441,7 @@ fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>, tbm: Tra
 
     fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
         match ty.kind {
-            TyKind::OpaqueDef(item, bounds) => {
+            TyKind::OpaqueDef(item, bounds, _) => {
                 let map = self.cx.tcx.hir();
                 let item = map.item(item);
                 let len = self.lts.len();
index ffcf83e4605e2d3cbb84986e80fadbbc7b21a5da..8ab640051b635fb3da6e6122b6e94359f049a64d 100644 (file)
@@ -373,7 +373,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             },
             ExprKind::Closure(&Closure { body, .. }) => {
                 let body = self.cx.tcx.hir().body(body);
-                self.visit_expr(&body.value);
+                self.visit_expr(body.value);
             },
             _ => walk_expr(self, expr),
         }
index 2c54033f8597502c6fb8db8c276f6f91d450377c..deb21894f36a9709cc1cf20815a8c660c9638cd2 100644 (file)
@@ -356,7 +356,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             after_loop: false,
             used_iter: false,
         };
-        v.visit_expr(&cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
+        v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
         v.used_iter
     }
 }
index 2502c8f880ddce76aa1045cfcdc815aaa315209d..754b0e78a148cc989f46f7c7534d4962da0e464d 100644 (file)
@@ -103,7 +103,7 @@ fn future_trait_ref<'tcx>(
     ty: &'tcx Ty<'tcx>,
 ) -> Option<(&'tcx TraitRef<'tcx>, Vec<LifetimeName>)> {
     if_chain! {
-        if let TyKind::OpaqueDef(item_id, bounds) = ty.kind;
+        if let TyKind::OpaqueDef(item_id, bounds, false) = ty.kind;
         let item = cx.tcx.hir().item(item_id);
         if let ItemKind::OpaqueTy(opaque) = &item.kind;
         if let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| {
index e32ef9933afe5c2b16a062fd81aed35b3439b340..93874b103b461d92bb06f73842e441b5e26d41b3 100644 (file)
@@ -248,7 +248,7 @@ fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) ->
                 } else {
                     (None, adt.non_enum_variant())
                 };
-                let (front, back) = match wild_idx {
+                let (front, back) = match wild_idx.as_opt_usize() {
                     Some(i) => pats.split_at(i),
                     None => (pats, [].as_slice()),
                 };
@@ -268,7 +268,7 @@ fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) ->
                     ty::Tuple(subs) => subs.len(),
                     _ => return Self::Wild,
                 };
-                let (front, back) = match wild_idx {
+                let (front, back) = match wild_idx.as_opt_usize() {
                     Some(i) => pats.split_at(i),
                     None => (pats, [].as_slice()),
                 };
index bc16f17b6196e420184860ce3dd731f9eeeebdbe..a3aa2e4b389afe74f1e40f96da6fb5ea4eab66c9 100644 (file)
@@ -40,7 +40,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
                                 arm.pat.span,
                                 &format!("`Err({})` matches all errors", ident_bind_name),
                                 None,
-                                "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
+                                "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable",
                             );
                         }
                     }
index 95478af45b4bf3fa687149fa8f76d5e5587306b4..56bcdc01fe4d61092502ca6cffa46ac5c0b730fb 100644 (file)
@@ -200,13 +200,11 @@ fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>,
             // We don't actually know the position and the presence of the `..` (dotdot) operator
             // in the arms, so we need to evaluate the correct offsets here in order to iterate in
             // both arms at the same time.
+            let left_pos = left_pos.as_opt_usize();
+            let right_pos = right_pos.as_opt_usize();
             let len = max(
-                left_in.len() + {
-                    if left_pos.is_some() { 1 } else { 0 }
-                },
-                right_in.len() + {
-                    if right_pos.is_some() { 1 } else { 0 }
-                },
+                left_in.len() + usize::from(left_pos.is_some()),
+                right_in.len() + usize::from(right_pos.is_some()),
             );
             let mut left_pos = left_pos.unwrap_or(usize::MAX);
             let mut right_pos = right_pos.unwrap_or(usize::MAX);
index 2f117e4dcc3746abd71f918d0e3efa88661a9c0f..22f5635a5bccb803ddad652db33ce738039449ac 100644 (file)
@@ -152,7 +152,7 @@ fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg:
         match arg.kind {
             hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => {
                 let closure_body = cx.tcx.hir().body(body);
-                let closure_expr = peel_blocks(&closure_body.value);
+                let closure_expr = peel_blocks(closure_body.value);
 
                 if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, fn_decl_span) {
                     true
index 51aec21527a7116e8d253911e12611ba829af055..b2bc1ad5c9ed0f33cc1ce5d69af3485e58bc94fd 100644 (file)
@@ -23,7 +23,7 @@ pub(super) fn check(
         if Some(id) == cx.tcx.lang_items().option_some_variant();
         then {
             let mut applicability = Applicability::MachineApplicable;
-            let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0].0).peel_refs();
+            let self_ty = cx.typeck_results().expr_ty_adjusted(args[0].0).peel_refs();
 
             if *self_ty.kind() != ty::Str {
                 return false;
index f5bead387d7bd170b17aec80361b8bb04ffc8560..7ab6b84c2074918f39b8f0d5aa67de94d23a914c 100644 (file)
@@ -21,7 +21,11 @@ pub(super) fn check(
     receiver: &Expr<'_>,
     args: &[Expr<'_>],
 ) {
-    let arg = if method_name == sym::clone && args.is_empty() { receiver } else { return };
+    let arg = if method_name == sym::clone && args.is_empty() {
+        receiver
+    } else {
+        return;
+    };
     if cx
         .typeck_results()
         .type_dependent_def_id(expr.hir_id)
index 9dc839afc6256e8c9b89d8d51d3e8fd1c74f9543..9719b2f1c5125ff78f97934aeed8078405aa8878 100644 (file)
@@ -25,7 +25,7 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
         },
         hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
             let body = cx.tcx.hir().body(body);
-            let closure_expr = peel_blocks(&body.value);
+            let closure_expr = peel_blocks(body.value);
             let arg_id = body.params[0].pat.hir_id;
             match closure_expr.kind {
                 hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
index e8442091fd3067fd3717c397856770c6055d17de..8261ef5e1ce345819266a83a37f3905a5b5f47f8 100644 (file)
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
         if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind;
         then {
             let closure_body = cx.tcx.hir().body(body);
-            let closure_expr = peel_blocks(&closure_body.value);
+            let closure_expr = peel_blocks(closure_body.value);
             match closure_body.params[0].pat.kind {
                 hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
                     hir::BindingAnnotation::NONE, .., name, None
index fc9ba15d82a40e4e00f59c35ef8c378c43e28847..41942b20ea163f34e0e60d47b489b19870b145aa 100644 (file)
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
-    /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
-    /// `unwrap_or_default` instead.
+    /// `.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`,
+    /// `.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()`
+    /// etc. instead.
     ///
     /// ### Why is this bad?
     /// The function will always be called and potentially
@@ -3304,9 +3305,9 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
                 // one of the associated types must be Self
                 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
                     if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
-                        let assoc_ty = match projection_predicate.term {
-                            ty::Term::Ty(ty) => ty,
-                            ty::Term::Const(_c) => continue,
+                        let assoc_ty = match projection_predicate.term.unpack() {
+                            ty::TermKind::Ty(ty) => ty,
+                            ty::TermKind::Const(_c) => continue,
                         };
                         // walk the associated type and check for Self
                         if let Some(self_adt) = self_ty.ty_adt_def() {
index bd8458a222e2922e1d68c3d26e9b37fc0f084d20..b9593b3687d9cf3633d93dc397eda0893dd729c3 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{expr_custom_deref_adjustment, ty::is_type_diagnostic_item};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability};
@@ -11,6 +11,7 @@
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) {
     if_chain! {
+        if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut));
         if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind();
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
index 903fa306f935a8e6b005c7c67e6323b6ad706a27..597af853dc681a57d44f973f8a4fbe83a9d14977 100644 (file)
@@ -40,7 +40,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
         let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
 
         // Only proceed if this is a call on some object of type std::fs::OpenOptions
-        if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 1 {
+        if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() {
             let argument_option = match arguments[0].kind {
                 ExprKind::Lit(ref span) => {
                     if let Spanned {
index 81c67b4ca6a59d0816908e88e600eeff66e13e38..c409268de769d6616a1555071d5a7d1f75a07cdb 100644 (file)
@@ -53,7 +53,7 @@ pub(super) fn check<'tcx>(
             }),
         hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
             let closure_body = cx.tcx.hir().body(body);
-            let closure_expr = peel_blocks(&closure_body.value);
+            let closure_expr = peel_blocks(closure_body.value);
 
             match &closure_expr.kind {
                 hir::ExprKind::MethodCall(_, receiver, [], _) => {
index 5a39b82b027d1643536ec0c4f2fd9237fad57ccf..6657cdccd010c4398a7d0b3dbfd9d8a0e8ca6e91 100644 (file)
@@ -74,7 +74,7 @@ pub(super) fn check<'tcx>(
             if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind;
             let arg_snippet = snippet(cx, fn_decl_span, "..");
             let body = cx.tcx.hir().body(body);
-            if let Some((func, [arg_char])) = reduce_unit_expression(&body.value);
+            if let Some((func, [arg_char])) = reduce_unit_expression(body.value);
             if let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id));
             if Some(id) == cx.tcx.lang_items().option_some_variant();
             then {
index 76876d8662936846bb7766db36547df3903900a5..b43b9258c471da6ec44eae9a9204d0b4c6327a2d 100644 (file)
@@ -23,7 +23,8 @@ pub(super) fn check<'tcx>(
     receiver: &'tcx hir::Expr<'_>,
     args: &'tcx [hir::Expr<'_>],
 ) {
-    /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
+    /// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`,
+    /// `or_insert(T::new())` or `or_insert(T::default())`.
     #[allow(clippy::too_many_arguments)]
     fn check_unwrap_or_default(
         cx: &LateContext<'_>,
@@ -43,7 +44,11 @@ fn check_unwrap_or_default(
 
         if_chain! {
             if !or_has_args;
-            if name == "unwrap_or";
+            if let Some(sugg) = match name {
+                "unwrap_or" => Some("unwrap_or_default"),
+                "or_insert" => Some("or_default"),
+                _ => None,
+            };
             if let hir::ExprKind::Path(ref qpath) = fun.kind;
             if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
             let path = last_path_segment(qpath).ident.name;
@@ -59,7 +64,7 @@ fn check_unwrap_or_default(
                     method_span.with_hi(span.hi()),
                     &format!("use of `{}` followed by a call to `{}`", name, path),
                     "try this",
-                    "unwrap_or_default()".to_string(),
+                    format!("{}()", sugg),
                     Applicability::MachineApplicable,
                 );
 
@@ -83,7 +88,7 @@ fn check_general_case<'tcx>(
         fun_span: Option<Span>,
     ) {
         // (path, fn_has_argument, methods, suffix)
-        static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
+        const KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
             (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
             (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
             (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
index 9c3375bf35e7dc523ce4cd89b4b7435354873a8d..851cdf544550f6caf077890c8c3d9f1293058bbd 100644 (file)
@@ -15,9 +15,9 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hi
         if let Some(def_id) = cx.tcx.hir().opt_local_def_id(closure.hir_id);
         if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id);
         let closure_body = cx.tcx.hir().body(body_id);
-        if !cx.typeck_results().expr_ty(&closure_body.value).is_unit();
+        if !cx.typeck_results().expr_ty(closure_body.value).is_unit();
         then {
-            if let Some(map_mutated_vars) = mutated_variables(&closure_body.value, cx) {
+            if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) {
                 // A variable is used mutably inside of the closure. Suppress the lint.
                 if !map_mutated_vars.is_empty() {
                     return;
index bafa6fc584d48548e595d218fac04d29d129a54b..4e8c201f470bab9b86fbb2b130ca8af2969f03ef 100644 (file)
@@ -21,14 +21,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
     if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
         let body = cx.tcx.hir().body(body);
         let arg_id = body.params[0].pat.hir_id;
-        let mutates_arg =
-            mutated_variables(&body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id));
-        let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, &body.value);
+        let mutates_arg = mutated_variables(body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id));
+        let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, body.value);
 
-        let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, &body.value);
+        let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, body.value);
 
         let mut return_visitor = ReturnVisitor::new(cx, arg_id);
-        return_visitor.visit_expr(&body.value);
+        return_visitor.visit_expr(body.value);
         found_mapping |= return_visitor.found_mapping;
         found_filtering |= return_visitor.found_filtering;
 
@@ -36,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
         let sugg = if !found_filtering {
             if name == "filter_map" { "map" } else { "map(..).next()" }
         } else if !found_mapping && !mutates_arg && (!clone_or_copy_needed || is_copy(cx, in_ty)) {
-            match cx.typeck_results().expr_ty(&body.value).kind() {
+            match cx.typeck_results().expr_ty(body.value).kind() {
                 ty::Adt(adt, subst)
                     if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) =>
                 {
index c3531d4d0511e9e8f730dbc64e35190fc2228f53..c17ef6809f91281aa7ab9490d0092a1f077d8a0f 100644 (file)
@@ -31,7 +31,7 @@ fn check_fold_with_op(
             // Extract the body of the closure passed to fold
             if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind;
             let closure_body = cx.tcx.hir().body(body);
-            let closure_expr = peel_blocks(&closure_body.value);
+            let closure_expr = peel_blocks(closure_body.value);
 
             // Check if the closure body is of the form `acc <op> some_expr(x)`
             if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind;
index 6f25acca1de6123e1a08586d8edd57f17fe192d8..ed5a75b0f3ce574ee50790436ef6704d6323bbe0 100644 (file)
@@ -131,7 +131,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
         ] = &closure_body.params;
         if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind;
         if method_path.ident.name == sym::cmp;
-        if is_trait_method(cx, &closure_body.value, sym::Ord);
+        if is_trait_method(cx, closure_body.value, sym::Ord);
         then {
             let (closure_body, closure_arg, reverse) = if mirrored_exprs(
                 left_expr,
index 9dceb9af2f2234b09673affa472dce6887b57bdf..763bfafecef14916ebbccec2203d4c569eabed9a 100644 (file)
@@ -1,21 +1,25 @@
 use super::implicit_clone::is_clone_like;
 use super::unnecessary_iter_cloned::{self, is_into_iter};
+use crate::rustc_middle::ty::Subst;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{
-    get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, peel_mid_ty_refs,
-};
-use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item};
+use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
+use clippy_utils::visitors::find_all_ret_expressions;
+use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
 use clippy_utils::{meets_msrv, msrvs};
 use rustc_errors::Applicability;
-use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind};
+use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
+use rustc_middle::ty::EarlyBinder;
+use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
 use rustc_semver::RustcVersion;
 use rustc_span::{sym, Symbol};
+use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
+use rustc_typeck::check::{FnCtxt, Inherited};
 use std::cmp::max;
 
 use super::UNNECESSARY_TO_OWNED;
@@ -34,7 +38,7 @@ pub fn check<'tcx>(
         then {
             if is_cloned_or_copied(cx, method_name, method_def_id) {
                 unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
-            } else if is_to_owned_like(cx, method_name, method_def_id) {
+            } else if is_to_owned_like(cx, expr, method_name, method_def_id) {
                 // At this point, we know the call is of a `to_owned`-like function. The functions
                 // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary
                 // based on its context, that is, whether it is a referent in an `AddrOf` expression, an
@@ -246,17 +250,12 @@ fn check_other_call_arg<'tcx>(
 ) -> bool {
     if_chain! {
         if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
-        if let Some((callee_def_id, call_substs, call_receiver, call_args)) = get_callee_substs_and_args(cx, maybe_call);
+        if let Some((callee_def_id, _, recv, call_args)) = get_callee_substs_and_args(cx, maybe_call);
         let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
-        let index = if let Some(call_receiver) = call_receiver {
-            std::iter::once(call_receiver).chain(call_args.iter()).position(|arg| arg.hir_id == maybe_arg.hir_id)
-        } else {
-            call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id)
-        };
-        if let Some(i) = index;
+        if let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id);
         if let Some(input) = fn_sig.inputs().get(i);
         let (input, n_refs) = peel_mid_ty_refs(*input);
-        if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input);
+        if let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input);
         if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait();
         if let [trait_predicate] = trait_predicates
             .iter()
@@ -264,52 +263,13 @@ fn check_other_call_arg<'tcx>(
             .collect::<Vec<_>>()[..];
         if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
         if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef);
+        if trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id;
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
-        // If the callee has type parameters, they could appear in `projection_predicate.ty` or the
-        // types of `trait_predicate.trait_ref.substs`.
-        if if trait_predicate.def_id() == deref_trait_id {
-            if let [projection_predicate] = projection_predicates[..] {
-                let normalized_ty =
-                    cx.tcx
-                        .subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
-                implements_trait(cx, receiver_ty, deref_trait_id, &[])
-                    && get_associated_type(cx, receiver_ty, deref_trait_id, "Target")
-                        .map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
-            } else {
-                false
-            }
-        } else if trait_predicate.def_id() == as_ref_trait_id {
-            let composed_substs = compose_substs(
-                cx,
-                &trait_predicate.trait_ref.substs.iter().skip(1).collect::<Vec<_>>()[..],
-                call_substs,
-            );
-            // if `expr` is a `String` and generic target is [u8], skip
-            // (https://github.com/rust-lang/rust-clippy/issues/9317).
-            if let [subst] = composed_substs[..]
-                && let GenericArgKind::Type(arg_ty) = subst.unpack()
-                && arg_ty.is_slice()
-                && let inner_ty = arg_ty.builtin_index().unwrap()
-                && let ty::Uint(ty::UintTy::U8) = inner_ty.kind()
-                && let self_ty = cx.typeck_results().expr_ty(expr).peel_refs()
-                && is_type_diagnostic_item(cx, self_ty, sym::String) {
-                false
-            } else {
-                implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs)
-            }
-        } else {
-            false
-        };
+        if can_change_type(cx, maybe_arg, receiver_ty);
         // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match
         // `Target = T`.
         if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id;
         let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 });
-        // If the trait is `AsRef` and the input type variable `T` occurs in the output type, then
-        // `T` must not be instantiated with a reference
-        // (https://github.com/rust-lang/rust-clippy/issues/8507).
-        if (n_refs == 0 && !receiver_ty.is_ref())
-            || trait_predicate.def_id() != as_ref_trait_id
-            || !fn_sig.output().contains(input);
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
             span_lint_and_sugg(
@@ -359,11 +319,11 @@ fn get_callee_substs_and_args<'tcx>(
         }
     }
     if_chain! {
-        if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind;
+        if let ExprKind::MethodCall(_, recv, args, _) = expr.kind;
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         then {
             let substs = cx.typeck_results().node_substs(expr.hir_id);
-            return Some((method_def_id, substs, Some(receiver), args));
+            return Some((method_def_id, substs, Some(recv), args));
         }
     }
     None
@@ -395,22 +355,103 @@ fn get_input_traits_and_projections<'tcx>(
     (trait_predicates, projection_predicates)
 }
 
-/// Composes two substitutions by applying the latter to the types of the former.
-fn compose_substs<'tcx>(
-    cx: &LateContext<'tcx>,
-    left: &[GenericArg<'tcx>],
-    right: SubstsRef<'tcx>,
-) -> Vec<GenericArg<'tcx>> {
-    left.iter()
-        .map(|arg| {
-            if let GenericArgKind::Type(arg_ty) = arg.unpack() {
-                let normalized_ty = cx.tcx.subst_and_normalize_erasing_regions(right, cx.param_env, arg_ty);
-                GenericArg::from(normalized_ty)
-            } else {
-                *arg
+fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool {
+    for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
+        match node {
+            Node::Stmt(_) => return true,
+            Node::Block(..) => continue,
+            Node::Item(item) => {
+                if let ItemKind::Fn(_, _, body_id) = &item.kind
+                && let output_ty = return_ty(cx, item.hir_id())
+                && let local_def_id = cx.tcx.hir().local_def_id(item.hir_id())
+                && Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
+                    let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.hir_id());
+                    fn_ctxt.can_coerce(ty, output_ty)
+                }) {
+                    if has_lifetime(output_ty) && has_lifetime(ty) {
+                        return false;
+                    }
+                    let body = cx.tcx.hir().body(*body_id);
+                    let body_expr = &body.value;
+                    let mut count = 0;
+                    return find_all_ret_expressions(cx, body_expr, |_| { count += 1; count <= 1 });
+                }
             }
-        })
-        .collect()
+            Node::Expr(parent_expr) => {
+                if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
+                {
+                    let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+                    if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
+                        && let Some(param_ty) = fn_sig.inputs().get(arg_index)
+                        && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
+                    {
+                        if fn_sig
+                            .inputs()
+                            .iter()
+                            .enumerate()
+                            .filter(|(i, _)| *i != arg_index)
+                            .any(|(_, ty)| ty.contains(*param_ty))
+                        {
+                            return false;
+                        }
+
+                        let mut trait_predicates = cx.tcx.param_env(callee_def_id)
+                            .caller_bounds().iter().filter(|predicate| {
+                            if let PredicateKind::Trait(trait_predicate) =  predicate.kind().skip_binder()
+                                && trait_predicate.trait_ref.self_ty() == *param_ty {
+                                    true
+                                } else {
+                                false
+                            }
+                        });
+
+                        let new_subst = cx.tcx.mk_substs(
+                            call_substs.iter()
+                                .enumerate()
+                                .map(|(i, t)|
+                                     if i == (*param_index as usize) {
+                                         GenericArg::from(ty)
+                                     } else {
+                                         t
+                                     }));
+
+                        if trait_predicates.any(|predicate| {
+                            let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst);
+                            let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
+                            !cx.tcx
+                                .infer_ctxt()
+                                .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
+                        }) {
+                            return false;
+                        }
+
+                        let output_ty = fn_sig.output();
+                        if output_ty.contains(*param_ty) {
+                            if let Ok(new_ty)  = cx.tcx.try_subst_and_normalize_erasing_regions(
+                                new_subst, cx.param_env, output_ty) {
+                                expr = parent_expr;
+                                ty = new_ty;
+                                continue;
+                            }
+                            return false;
+                        }
+
+                        return true;
+                    }
+                } else if let ExprKind::Block(..) = parent_expr.kind {
+                    continue;
+                }
+                return false;
+            },
+            _ => return false,
+        }
+    }
+
+    false
+}
+
+fn has_lifetime(ty: Ty<'_>) -> bool {
+    ty.walk().any(|t| matches!(t.unpack(), GenericArgKind::Lifetime(_)))
 }
 
 /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`.
@@ -421,10 +462,10 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id:
 
 /// Returns true if the named method can be used to convert the receiver to its "owned"
 /// representation.
-fn is_to_owned_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
+fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool {
     is_clone_like(cx, method_name.as_str(), method_def_id)
         || is_cow_into_owned(cx, method_name, method_def_id)
-        || is_to_string(cx, method_name, method_def_id)
+        || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id)
 }
 
 /// Returns true if the named method is `Cow::into_owned`.
@@ -432,7 +473,27 @@ fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: D
     method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow)
 }
 
-/// Returns true if the named method is `ToString::to_string`.
-fn is_to_string(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
-    method_name == sym::to_string && is_diag_trait_item(cx, method_def_id, sym::ToString)
+/// Returns true if the named method is `ToString::to_string` and it's called on a type that
+/// is string-like i.e. implements `AsRef<str>` or `Deref<str>`.
+fn is_to_string_on_string_like<'a>(
+    cx: &LateContext<'_>,
+    call_expr: &'a Expr<'a>,
+    method_name: Symbol,
+    method_def_id: DefId,
+) -> bool {
+    if method_name != sym::to_string || !is_diag_trait_item(cx, method_def_id, sym::ToString) {
+        return false;
+    }
+
+    if let Some(substs) = cx.typeck_results().node_substs_opt(call_expr.hir_id)
+        && let [generic_arg] = substs.as_slice()
+        && let GenericArgKind::Type(ty) = generic_arg.unpack()
+        && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
+        && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
+        && (implements_trait(cx, ty, deref_trait_id, &[cx.tcx.types.str_.into()]) ||
+            implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) {
+            true
+        } else {
+            false
+        }
 }
index f3af281d6cacc289838d278b25d9d3ed144d4494..045f739e64ded7db0b2a352287eb394ca45d8956 100644 (file)
@@ -5,10 +5,11 @@
     diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability,
     ty::is_type_diagnostic_item,
 };
+use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::{sym, symbol};
 
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
@@ -25,7 +26,7 @@ pub(super) fn check<'tcx>(
 
     if_chain! {
         if is_option || is_result;
-        if is_default_equivalent_call(cx, u_arg);
+        if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg);
         then {
             let mut applicability = Applicability::MachineApplicable;
 
@@ -44,3 +45,22 @@ pub(super) fn check<'tcx>(
         }
     }
 }
+
+fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
+    if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
+        let body = cx.tcx.hir().body(body);
+
+        if body.params.is_empty()
+            && let hir::Expr{ kind, .. } = &body.value
+            && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
+            && ident == &symbol::Ident::from_str("to_string")
+            && let hir::Expr{ kind, .. } = self_arg
+            && let hir::ExprKind::Lit(lit) = kind
+            && let LitKind::Str(symbol::kw::Empty, _) = lit.node
+        {
+            return true;
+        }
+    }
+
+    false
+}
index 44b21e7b080d22c6aa8c8654ceb76b226ccba6d2..4d8579135fc061279efa57bdf4b9e83c8adf1568 100644 (file)
@@ -1,7 +1,6 @@
 use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{match_trait_method, paths};
-use if_chain::if_chain;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -84,19 +83,16 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
             }
         },
         ExprKind::MethodCall(path, receiver, args @ [_], _) => {
-            if_chain! {
-                if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
-                then {
-                    if path.ident.name == sym!(max) {
-                        fetch_const(cx, Some(receiver), args, MinMax::Max)
-                    } else if path.ident.name == sym!(min) {
-                        fetch_const(cx, Some(receiver), args, MinMax::Min)
-                    } else {
-                        None
-                    }
+            if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD) {
+                if path.ident.name == sym!(max) {
+                    fetch_const(cx, Some(receiver), args, MinMax::Max)
+                } else if path.ident.name == sym!(min) {
+                    fetch_const(cx, Some(receiver), args, MinMax::Min)
                 } else {
                     None
                 }
+            } else {
+                None
             }
         },
         _ => None,
@@ -109,18 +105,18 @@ fn fetch_const<'a>(
     args: &'a [Expr<'a>],
     m: MinMax,
 ) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
-    let mut args = receiver.into_iter().chain(args.into_iter());
-    let arg0 = args.next()?;
-    let arg1 = args.next()?;
+    let mut args = receiver.into_iter().chain(args);
+    let first_arg = args.next()?;
+    let second_arg = args.next()?;
     if args.next().is_some() {
         return None;
     }
-    constant_simple(cx, cx.typeck_results(), arg0).map_or_else(
-        || constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)),
+    constant_simple(cx, cx.typeck_results(), first_arg).map_or_else(
+        || constant_simple(cx, cx.typeck_results(), second_arg).map(|c| (m, c, first_arg)),
         |c| {
-            if constant_simple(cx, cx.typeck_results(), arg1).is_none() {
+            if constant_simple(cx, cx.typeck_results(), second_arg).is_none() {
                 // otherwise ignore
-                Some((m, c, arg1))
+                Some((m, c, second_arg))
             } else {
                 None
             }
index f8cc3fbb3cdfaeacdcc0332fb432c05586d767eb..3233d87c073193f99a0046745ff49c603f7576a5 100644 (file)
@@ -77,7 +77,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
             if let ExprKind::Block(..) = body.value.kind;
             then {
                 let mut ret_collector = RetCollector::default();
-                ret_collector.visit_expr(&body.value);
+                ret_collector.visit_expr(body.value);
 
                 // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`.
                 if ret_collector.ret_in_loop {
index 17d5fa2152bbffe438f627e0d41103f9c063df95..6217110a1f3aee8253704a06c8894757fd54ed51 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
+use std::iter;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -234,11 +235,7 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
             })) => (
                 def_id.to_def_id(),
                 FnKind::TraitFn,
-                if sig.decl.implicit_self.has_implicit_self() {
-                    1
-                } else {
-                    0
-                },
+                usize::from(sig.decl.implicit_self.has_implicit_self()),
             ),
             Some(Node::ImplItem(&ImplItem {
                 kind: ImplItemKind::Fn(ref sig, _),
@@ -253,11 +250,7 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
                     (
                         trait_item_id,
                         FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const _ as usize),
-                        if sig.decl.implicit_self.has_implicit_self() {
-                            1
-                        } else {
-                            0
-                        },
+                        usize::from(sig.decl.implicit_self.has_implicit_self()),
                     )
                 } else {
                     (def_id.to_def_id(), FnKind::Fn, 0)
@@ -310,7 +303,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) {
                                     && has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id))
                             }) =>
                         {
-                            if let Some(idx) = std::iter::once(receiver).chain(args.iter()).position(|arg| arg.hir_id == child_id) {
+                            if let Some(idx) = iter::once(receiver).chain(args).position(|arg| arg.hir_id == child_id) {
                                 param.uses.push(Usage::new(span, idx));
                             }
                             return;
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic.rs
deleted file mode 100644 (file)
index 800cf24..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-#![allow(
-    // False positive
-    clippy::match_same_arms
-)]
-
-use super::ARITHMETIC;
-use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::impl_lint_pass;
-use rustc_span::source_map::Span;
-
-const HARD_CODED_ALLOWED: &[&str] = &["std::num::Saturating", "std::string::String", "std::num::Wrapping"];
-
-#[derive(Debug)]
-pub struct Arithmetic {
-    allowed: FxHashSet<String>,
-    // Used to check whether expressions are constants, such as in enum discriminants and consts
-    const_span: Option<Span>,
-    expr_span: Option<Span>,
-}
-
-impl_lint_pass!(Arithmetic => [ARITHMETIC]);
-
-impl Arithmetic {
-    #[must_use]
-    pub fn new(mut allowed: FxHashSet<String>) -> Self {
-        allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
-        Self {
-            allowed,
-            const_span: None,
-            expr_span: None,
-        }
-    }
-
-    /// Checks if the given `expr` has any of the inner `allowed` elements.
-    fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
-        self.allowed.contains(
-            cx.typeck_results()
-                .expr_ty(expr)
-                .to_string()
-                .split('<')
-                .next()
-                .unwrap_or_default(),
-        )
-    }
-
-    fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
-        span_lint(cx, ARITHMETIC, expr.span, "arithmetic detected");
-        self.expr_span = Some(expr.span);
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for Arithmetic {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if self.expr_span.is_some() {
-            return;
-        }
-        if let Some(span) = self.const_span && span.contains(expr.span) {
-            return;
-        }
-        match &expr.kind {
-            hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => {
-                let (
-                    hir::BinOpKind::Add
-                    | hir::BinOpKind::Sub
-                    | hir::BinOpKind::Mul
-                    | hir::BinOpKind::Div
-                    | hir::BinOpKind::Rem
-                    | hir::BinOpKind::Shl
-                    | hir::BinOpKind::Shr
-                ) = op.node else {
-                    return;
-                };
-                if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) {
-                    return;
-                }
-                self.issue_lint(cx, expr);
-            },
-            hir::ExprKind::Unary(hir::UnOp::Neg, _) => {
-                // CTFE already takes care of things like `-1` that do not overflow.
-                if constant_simple(cx, cx.typeck_results(), expr).is_none() {
-                    self.issue_lint(cx, expr);
-                }
-            },
-            _ => {},
-        }
-    }
-
-    fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
-        let body_owner = cx.tcx.hir().body_owner_def_id(body.id());
-        match cx.tcx.hir().body_owner_kind(body_owner) {
-            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
-                let body_span = cx.tcx.def_span(body_owner);
-                if let Some(span) = self.const_span && span.contains(body_span) {
-                    return;
-                }
-                self.const_span = Some(body_span);
-            },
-            hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {},
-        }
-    }
-
-    fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
-        let body_owner = cx.tcx.hir().body_owner(body.id());
-        let body_span = cx.tcx.hir().span(body_owner);
-        if let Some(span) = self.const_span && span.contains(body_span) {
-            return;
-        }
-        self.const_span = None;
-    }
-
-    fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if Some(expr.span) == self.expr_span {
-            self.expr_span = None;
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
new file mode 100644 (file)
index 0000000..83b69fb
--- /dev/null
@@ -0,0 +1,173 @@
+#![allow(
+    // False positive
+    clippy::match_same_arms
+)]
+
+use super::ARITHMETIC_SIDE_EFFECTS;
+use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
+use rustc_ast as ast;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty;
+use rustc_session::impl_lint_pass;
+use rustc_span::source_map::{Span, Spanned};
+
+const HARD_CODED_ALLOWED: &[&str] = &[
+    "f32",
+    "f64",
+    "std::num::Saturating",
+    "std::string::String",
+    "std::num::Wrapping",
+];
+
+#[derive(Debug)]
+pub struct ArithmeticSideEffects {
+    allowed: FxHashSet<String>,
+    // Used to check whether expressions are constants, such as in enum discriminants and consts
+    const_span: Option<Span>,
+    expr_span: Option<Span>,
+}
+
+impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]);
+
+impl ArithmeticSideEffects {
+    #[must_use]
+    pub fn new(mut allowed: FxHashSet<String>) -> Self {
+        allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
+        Self {
+            allowed,
+            const_span: None,
+            expr_span: None,
+        }
+    }
+
+    /// Checks assign operators (+=, -=, *=, /=) of integers in a non-constant environment that
+    /// won't overflow.
+    fn has_valid_assign_op(op: &Spanned<hir::BinOpKind>, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool {
+        if !Self::is_literal_integer(rhs, rhs_refs) {
+            return false;
+        }
+        if let hir::BinOpKind::Div | hir::BinOpKind::Mul = op.node
+            && let hir::ExprKind::Lit(ref lit) = rhs.kind
+            && let ast::LitKind::Int(1, _) = lit.node
+        {
+            return true;
+        }
+        false
+    }
+
+    /// Checks "raw" binary operators (+, -, *, /) of integers in a non-constant environment
+    /// already handled by the CTFE.
+    fn has_valid_bin_op(lhs: &hir::Expr<'_>, lhs_refs: Ty<'_>, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool {
+        Self::is_literal_integer(lhs, lhs_refs) && Self::is_literal_integer(rhs, rhs_refs)
+    }
+
+    /// Checks if the given `expr` has any of the inner `allowed` elements.
+    fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+        self.allowed.contains(
+            cx.typeck_results()
+                .expr_ty(expr)
+                .to_string()
+                .split('<')
+                .next()
+                .unwrap_or_default(),
+        )
+    }
+
+    /// Explicit integers like `1` or `i32::MAX`. Does not take into consideration references.
+    fn is_literal_integer(expr: &hir::Expr<'_>, expr_refs: Ty<'_>) -> bool {
+        let is_integral = expr_refs.is_integral();
+        let is_literal = matches!(expr.kind, hir::ExprKind::Lit(_));
+        is_integral && is_literal
+    }
+
+    fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
+        span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, "arithmetic detected");
+        self.expr_span = Some(expr.span);
+    }
+
+    /// Manages when the lint should be triggered. Operations in constant environments, hard coded
+    /// types, custom allowed types and non-constant operations that won't overflow are ignored.
+    fn manage_bin_ops(
+        &mut self,
+        cx: &LateContext<'_>,
+        expr: &hir::Expr<'_>,
+        op: &Spanned<hir::BinOpKind>,
+        lhs: &hir::Expr<'_>,
+        rhs: &hir::Expr<'_>,
+    ) {
+        if constant_simple(cx, cx.typeck_results(), expr).is_some() {
+            return;
+        }
+        if !matches!(
+            op.node,
+            hir::BinOpKind::Add
+                | hir::BinOpKind::Sub
+                | hir::BinOpKind::Mul
+                | hir::BinOpKind::Div
+                | hir::BinOpKind::Rem
+                | hir::BinOpKind::Shl
+                | hir::BinOpKind::Shr
+        ) {
+            return;
+        };
+        if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) {
+            return;
+        }
+        let lhs_refs = cx.typeck_results().expr_ty(lhs).peel_refs();
+        let rhs_refs = cx.typeck_results().expr_ty(rhs).peel_refs();
+        let has_valid_assign_op = Self::has_valid_assign_op(op, rhs, rhs_refs);
+        if has_valid_assign_op || Self::has_valid_bin_op(lhs, lhs_refs, rhs, rhs_refs) {
+            return;
+        }
+        self.issue_lint(cx, expr);
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) {
+            return;
+        }
+        match &expr.kind {
+            hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => {
+                self.manage_bin_ops(cx, expr, op, lhs, rhs);
+            },
+            hir::ExprKind::Unary(hir::UnOp::Neg, _) => {
+                if constant_simple(cx, cx.typeck_results(), expr).is_none() {
+                    self.issue_lint(cx, expr);
+                }
+            },
+            _ => {},
+        }
+    }
+
+    fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
+        let body_owner = cx.tcx.hir().body_owner(body.id());
+        let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner);
+        let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
+        if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind {
+            let body_span = cx.tcx.hir().span_with_body(body_owner);
+            if let Some(span) = self.const_span && span.contains(body_span) {
+                return;
+            }
+            self.const_span = Some(body_span);
+        }
+    }
+
+    fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
+        let body_owner = cx.tcx.hir().body_owner(body.id());
+        let body_span = cx.tcx.hir().span(body_owner);
+        if let Some(span) = self.const_span && span.contains(body_span) {
+            return;
+        }
+        self.const_span = None;
+    }
+
+    fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if Some(expr.span) == self.expr_span {
+            self.expr_span = None;
+        }
+    }
+}
index bb6d99406b49376309e8e40d2f938686bbd0421f..c32b4df4f75c1f3daebf4911ac70332160aa6935 100644 (file)
@@ -21,7 +21,7 @@
 mod self_assignment;
 mod verbose_bit_mask;
 
-pub(crate) mod arithmetic;
+pub(crate) mod arithmetic_side_effects;
 
 use rustc_hir::{Body, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for any kind of arithmetic operation of any type.
+    /// Checks any kind of arithmetic operation of any type.
     ///
     /// Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
     /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
-    /// or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered
-    /// away.
+    /// or can panic (`/`, `%`).
+    ///
+    /// Known safe built-in types like `Wrapping` or `Saturing`, floats, operations in constant
+    /// environments, allowed types and non-constant operations that won't overflow are ignored.
     ///
     /// ### Why is this bad?
-    /// Integer overflow will trigger a panic in debug builds or will wrap in
-    /// release mode. Division by zero will cause a panic in either mode. In some applications one
-    /// wants explicitly checked, wrapping or saturating arithmetic.
+    /// For integers, overflow will trigger a panic in debug builds or wrap the result in
+    /// release mode; division by zero will cause a panic in either mode. As a result, it is
+    /// desirable to explicitly call checked, wrapping or saturating arithmetic methods.
     ///
     /// #### Example
     /// ```rust
-    /// # let a = 0;
-    /// a + 1;
+    /// // `n` can be any number, including `i32::MAX`.
+    /// fn foo(n: i32) -> i32 {
+    ///   n + 1
+    /// }
     /// ```
     ///
-    /// Third-party types also tend to overflow.
+    /// Third-party types can also overflow or present unwanted side-effects.
     ///
     /// #### Example
     /// ```ignore,rust
     /// ```
     ///
     /// ### Allowed types
-    /// Custom allowed types can be specified through the "arithmetic-allowed" filter.
+    /// Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter.
     #[clippy::version = "1.64.0"]
-    pub ARITHMETIC,
+    pub ARITHMETIC_SIDE_EFFECTS,
     restriction,
-    "any arithmetic expression that could overflow or panic"
+    "any arithmetic expression that can cause side effects like overflows or panics"
 }
 
 declare_clippy_lint! {
@@ -785,7 +789,7 @@ pub struct Operators {
 }
 impl_lint_pass!(Operators => [
     ABSURD_EXTREME_COMPARISONS,
-    ARITHMETIC,
+    ARITHMETIC_SIDE_EFFECTS,
     INTEGER_ARITHMETIC,
     FLOAT_ARITHMETIC,
     ASSIGN_OP_PATTERN,
index 21acf003d92b2a775d4068bcbcde535de7e7b531..4aa0d9227abadd80aba8b0811f8f893e0a7965ac 100644 (file)
@@ -69,7 +69,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir
         }
         true
     })
-    .visit_expr(&body.value);
+    .visit_expr(body.value);
     if !panics.is_empty() {
         span_lint_and_then(
             cx,
index 0028e0bc6c517e79e13f3b57452972f013da44c0..41d1baba64f851ffa6409bef6e1c6f3f62575ca4 100644 (file)
@@ -507,7 +507,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
         if let Some(args) = args
             && !args.is_empty()
             && body.map_or(true, |body| {
-                sig.header.unsafety == Unsafety::Unsafe || contains_unsafe_block(cx, &body.value)
+                sig.header.unsafety == Unsafety::Unsafe || contains_unsafe_block(cx, body.value)
             })
         {
             span_lint_and_then(
@@ -664,7 +664,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         results,
         skip_count,
     };
-    v.visit_expr(&body.value);
+    v.visit_expr(body.value);
     v.results
 }
 
index f4f1fd336df7cc81c4a60786da7e95ccb5ed85bb..569870ab2b7f41ae3d4b4b2fd53083ba3b71d9ed 100644 (file)
@@ -122,7 +122,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
     if_chain! {
         if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr);
         if !is_else_clause(cx.tcx, expr);
-        if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind;
+        if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind;
+        if ddpos.as_opt_usize().is_none();
         if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind;
         let caller_ty = cx.typeck_results().expr_ty(let_expr);
         let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else);
index 490f345d2970777634c6554ec54cbb5fd5c040cb..918d624eec6fa852da2d6767b4c2eef29f5cb7ed 100644 (file)
@@ -350,6 +350,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R
 // exclusive range plus one: `x..(y+1)`
 fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
+        if expr.span.can_be_used_for_suggestions();
         if let Some(higher::Range {
             start,
             end: Some(end),
@@ -357,14 +358,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
         }) = higher::Range::hir(expr);
         if let Some(y) = y_plus_one(cx, end);
         then {
-            let span = if expr.span.from_expansion() {
-                expr.span
-                    .ctxt()
-                    .outer_expn_data()
-                    .call_site
-            } else {
-                expr.span
-            };
+            let span = expr.span;
             span_lint_and_then(
                 cx,
                 RANGE_PLUS_ONE,
@@ -399,6 +393,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
 // inclusive range minus one: `x..=(y-1)`
 fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
+        if expr.span.can_be_used_for_suggestions();
         if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::Range::hir(expr);
         if let Some(y) = y_minus_one(cx, end);
         then {
index 1926661c59603a886b5bfe369532d42df86a497e..91553240e3c910fa4a25d4222a9c315a6ca0dad3 100644 (file)
@@ -139,7 +139,7 @@ fn check_fn(
                 } else {
                     RetReplacement::Empty
                 };
-                check_final_expr(cx, &body.value, Some(body.value.span), replacement);
+                check_final_expr(cx, body.value, Some(body.value.span), replacement);
             },
             FnKind::ItemFn(..) | FnKind::Method(..) => {
                 if let ExprKind::Block(block, _) = body.value.kind {
index 4294464dbf61a5fffbda1a1d728a9c3a71608f9d..6add20c1fb712dcad9575e7b2b278bc4125f1412 100644 (file)
@@ -78,7 +78,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             ]
                 .iter()
                 .find(|&(ts, _)| ts.iter().any(|&t| Ok(trait_id) == cx.tcx.lang_items().require(t)));
-            if count_binops(&body.value) == 1;
+            if count_binops(body.value) == 1;
             then {
                 span_lint(
                     cx,
index 851eef7b332417658b090489fa968aa0850923f4..c0a4f3fbacd6487521ae0b9ca0777545176e1e51 100644 (file)
@@ -149,7 +149,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             let args = std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>();
             for (i, trait_name) in arg_indices {
                 if i < args.len() {
-                    match check_arg(cx, &args[i]) {
+                    match check_arg(cx, args[i]) {
                         Some((span, None)) => {
                             span_lint(
                                 cx,
index 35824b03170afb87e139373715ad3b1caca492e5..ce9ebad8c89a85e98687ef486fc410dca262993f 100644 (file)
@@ -19,10 +19,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
         && cx.typeck_results().pat_ty(local.pat).is_unit()
     {
         if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer))
-            || matches!(local.pat.kind, PatKind::Tuple([], None)))
+            || matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()))
             && expr_needs_inferred_result(cx, init)
         {
-            if !matches!(local.pat.kind, PatKind::Wild | PatKind::Tuple([], None)) {
+            if !matches!(local.pat.kind, PatKind::Wild)
+               && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none())
+            {
                 span_lint_and_then(
                     cx,
                     LET_UNIT_VALUE,
index 7ffb53dcf455f371e313cade841426bdeae0fd92..a6f777abc6e942aaf0259f83314b859ba569efb0 100644 (file)
@@ -50,7 +50,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         })
         .collect::<Vec<_>>();
     if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
-        lint_unit_args(cx, expr, &args_to_recover.as_slice());
+        lint_unit_args(cx, expr, args_to_recover.as_slice());
     }
 }
 
index a5afbb8ff9da49272efd9887b20732ed221c0049..2c40827db0e75677800317cf9af9e397028e8b35 100644 (file)
@@ -115,7 +115,7 @@ fn check_fn(
 
         // Check if all return expression respect the following condition and collect them.
         let mut suggs = Vec::new();
-        let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
+        let can_sugg = find_all_ret_expressions(cx, body.value, |ret_expr| {
             if_chain! {
                 if !ret_expr.span.from_expansion();
                 // Check if a function call.
index 9092156be150a30634c382add42dd2fcc6a5e1e1..7e451b7b7a419239c5c136541ab74222e54fce8e 100644 (file)
@@ -160,7 +160,7 @@ fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str)
             let name = method_name.ident.as_str();
             if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name);
             then {
-                assert!(args.len() == 0);
+                assert!(args.is_empty());
                 let unwrappable = match name {
                     "is_some" | "is_ok" => true,
                     "is_err" | "is_none" => false,
index b3ca15f7648bc082bdb8ea71694d65631c9c6200..46020adcaa2caae66e67974e86f0f17f08543c44 100644 (file)
@@ -83,7 +83,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // check for `expect`
         if let Some(arglists) = method_chain_args(expr, &["expect"]) {
-            let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
+            let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
             {
@@ -93,7 +93,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-            let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
+            let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
             {
@@ -114,7 +114,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc
             typeck_results: cx.tcx.typeck(impl_item.def_id),
             result: Vec::new(),
         };
-        fpu.visit_expr(&body.value);
+        fpu.visit_expr(body.value);
 
         // if we've found one, lint
         if !fpu.result.is_empty() {
index 1489c96d9e9b03bcb61a8bb8cd84fb7a0977be97..4003fff27c006a7d5956aa6094406fc4f1f735eb 100644 (file)
@@ -142,7 +142,7 @@ fn check_item(cx: &LateContext<'_>, hir_id: HirId) {
     let hir = cx.tcx.hir();
     if let Some(body_id) = hir.maybe_body_owned_by(hir_id.expect_owner()) {
         check_node(cx, hir_id, |v| {
-            v.expr(&v.bind("expr", &hir.body(body_id).value));
+            v.expr(&v.bind("expr", hir.body(body_id).value));
         });
     }
 }
index 84e65d5fa0b719044d3d43705141e5656aa9f63e..a8500beb25747aa9d95516cd24bbeaffac094e79 100644 (file)
@@ -208,7 +208,7 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
     /// Lint: Arithmetic.
     ///
     /// Suppress checking of the passed type names.
-    (arithmetic_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
+    (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
     /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
index ae1c11ef83c31cab317d5702cdacd8082c4100d2..17d9a041857678adfe81e0d950defc3e6a417431 100644 (file)
@@ -505,7 +505,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                             .hir_id(),
                     ),
                 );
-                collector.visit_expr(&cx.tcx.hir().body(body_id).value);
+                collector.visit_expr(cx.tcx.hir().body(body_id).value);
             }
         }
     }
@@ -653,7 +653,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         }
 
         if_chain! {
-            if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+            if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind;
             let fn_name = path.ident;
             if let Some(sugg) = self.map.get(fn_name.as_str());
             let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
@@ -685,9 +685,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect();
         if_chain! {
             if let ["expn_data", "outer_expn"] = method_names.as_slice();
-            let args = arg_lists[1];
-            if args.len() == 1;
-            let self_arg = &args.0;
+            let (self_arg, args)= arg_lists[1];
+            if args.is_empty();
             let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
             if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
             then {
@@ -734,30 +733,30 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             if and_then_args.len() == 5;
             if let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind;
             let body = cx.tcx.hir().body(body);
-            let only_expr = peel_blocks_with_stmt(&body.value);
-            if let ExprKind::MethodCall(ps, span_call_args, _) = &only_expr.kind;
-            if let ExprKind::Path(..) = span_call_args[0].kind;
+            let only_expr = peel_blocks_with_stmt(body.value);
+            if let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind;
+            if let ExprKind::Path(..) = recv.kind;
             then {
                 let and_then_snippets = get_and_then_snippets(cx, and_then_args);
                 let mut sle = SpanlessEq::new(cx).deny_side_effects();
                 match ps.ident.as_str() {
-                    "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
+                    "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
                         suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args));
                     },
-                    "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
-                        let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
+                    "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+                        let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
                         suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
                     },
-                    "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
-                        let note_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
+                    "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+                        let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
                         suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
                     },
                     "help" => {
-                        let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+                        let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
                         suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
                     }
                     "note" => {
-                        let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+                        let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
                         suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
                     }
                     _  => (),
@@ -798,9 +797,9 @@ fn span_suggestion_snippets<'a, 'hir>(
     cx: &LateContext<'_>,
     span_call_args: &'hir [Expr<'hir>],
 ) -> SpanSuggestionSnippets<'a> {
-    let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
-    let sugg_snippet = snippet(cx, span_call_args[3].span, "..");
-    let applicability_snippet = snippet(cx, span_call_args[4].span, "Applicability::MachineApplicable");
+    let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+    let sugg_snippet = snippet(cx, span_call_args[2].span, "..");
+    let applicability_snippet = snippet(cx, span_call_args[3].span, "Applicability::MachineApplicable");
 
     SpanSuggestionSnippets {
         help: help_snippet,
@@ -954,7 +953,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
                 if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) {
                     if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind {
                         let body = cx.tcx.hir().body(body_id);
-                        return path_to_matched_type(cx, &body.value);
+                        return path_to_matched_type(cx, body.value);
                     }
                 }
             },
@@ -1046,7 +1045,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             if el_ty.is_str();
             let body = cx.tcx.hir().body(body_id);
             let typeck_results = cx.tcx.typeck_body(body_id);
-            if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, &body.value);
+            if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value);
             let path: Vec<&str> = path.iter().map(|x| {
                     if let Constant::Str(s) = x {
                         s.as_str()
@@ -1177,7 +1176,7 @@ fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>)
         };
         if_chain! {
             // is a method call
-            if let ExprKind::MethodCall(_, [item], _) = call.kind;
+            if let ExprKind::MethodCall(_, item, [], _) = call.kind;
             if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id);
             let ty = cx.typeck_results().expr_ty(item);
             // ...on either an Ident or a Symbol
index b1148bccc2a283d025cb530f18197437bfbe9079..342f627e38275ce925c224595542abadfef9b2e3 100644 (file)
@@ -1145,8 +1145,8 @@ fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
                     self.add_single_span_suggestion();
                 }
             },
-            ExprKind::MethodCall(path, arg, _arg_span) => {
-                let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&arg[0]));
+            ExprKind::MethodCall(path, recv, _, _arg_span) => {
+                let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(recv));
                 if match_type(self.cx, self_ty, &paths::DIAGNOSTIC_BUILDER) {
                     let called_method = path.ident.name.as_str().to_string();
                     for (method_name, is_multi_part) in &SUGGESTION_DIAGNOSTIC_BUILDER_METHODS {
index 8425837fd73366277219447d83e196b11c71ffa3..bd5be0c9d7eda70d5db3c9e973c7471c034d47ee 100644 (file)
@@ -86,7 +86,7 @@ fn display_err(&self, cx: &LateContext<'_>) {
                 },
                 ExprKind::Unary(UnOp::Deref, _) | ExprKind::Index(..) if !needs_mut => {
                     let mut last_place = parent;
-                    while let Some(parent) = get_parent_expr(cx, parent) {
+                    while let Some(parent) = get_parent_expr(cx, last_place) {
                         if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..))
                             || matches!(parent.kind, ExprKind::Index(e, _) if e.hir_id == last_place.hir_id)
                         {
index 347165d9704a100717d0e61bffe3cee3ab571269..640a09a7a912347396816d4fec4c0b41c5f09c55 100644 (file)
@@ -805,7 +805,11 @@ fn check_newlines(fmtstr: &StrLit) -> bool {
     let contents = fmtstr.symbol.as_str();
 
     let mut cb = |r: Range<usize>, c: Result<char, EscapeError>| {
-        let c = c.unwrap();
+        let c = match c {
+            Ok(c) => c,
+            Err(e) if !e.is_fatal() => return,
+            Err(e) => panic!("{:?}", e),
+        };
 
         if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline {
             should_lint = true;
index e8d2d579f097e5451a870788145360c3e7510c40..7a8d4e8068ed6dc514031623c55a5d2e47333c07 100644 (file)
@@ -140,7 +140,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
         ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => {
             (expr_search_pat(tcx, e).0, Pat::Str("await"))
         },
-        ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, &tcx.hir().body(body).value).1),
+        ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, tcx.hir().body(body).value).1),
         ExprKind::Block(
             Block {
                 rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
@@ -254,7 +254,7 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI
     let (start_pat, end_pat) = match kind {
         FnKind::ItemFn(.., header) => (fn_header_search_pat(*header), Pat::Str("")),
         FnKind::Method(.., sig) => (fn_header_search_pat(sig.header), Pat::Str("")),
-        FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, &body.value).1),
+        FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, body.value).1),
     };
     let start_pat = match tcx.hir().get(hir_id) {
         Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => {
index 124a00d817847ae7a827a6c8694e0a9e1d888e83..91c9c382c236bcbc87c535976c33944fba629bf8 100644 (file)
@@ -45,7 +45,7 @@ fn bitor_assign(&mut self, rhs: Self) {
 }
 
 /// Determine the eagerness of the given function call.
-fn fn_eagerness<'tcx>(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
+fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
     use EagernessSuggestion::{Eager, Lazy, NoChange};
     let name = name.as_str();
 
index 57448f716d4941e023d2a7112c7e6f919ebcac34..7212d9cd744510fb8ba8763d6a4e9570b7bc4036 100644 (file)
@@ -201,8 +201,8 @@ pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
             self.inner.cx.tcx.typeck_body(right),
         ));
         let res = self.eq_expr(
-            &self.inner.cx.tcx.hir().body(left).value,
-            &self.inner.cx.tcx.hir().body(right).value,
+            self.inner.cx.tcx.hir().body(left).value,
+            self.inner.cx.tcx.hir().body(right).value,
         );
         self.inner.maybe_typeck_results = old_maybe_typeck_results;
         res
@@ -649,7 +649,7 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
             }) => {
                 std::mem::discriminant(&capture_clause).hash(&mut self.s);
                 // closures inherit TypeckResults
-                self.hash_expr(&self.cx.tcx.hir().body(body).value);
+                self.hash_expr(self.cx.tcx.hir().body(body).value);
             },
             ExprKind::Field(e, ref f) => {
                 self.hash_expr(e);
@@ -929,7 +929,7 @@ pub fn hash_guard(&mut self, g: &Guard<'_>) {
         }
     }
 
-    pub fn hash_lifetime(&mut self, lifetime: Lifetime) {
+    pub fn hash_lifetime(&mut self, lifetime: &Lifetime) {
         std::mem::discriminant(&lifetime.name).hash(&mut self.s);
         if let LifetimeName::Param(param_id, ref name) = lifetime.name {
             std::mem::discriminant(name).hash(&mut self.s);
@@ -987,8 +987,9 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
                 }
             },
             TyKind::Path(ref qpath) => self.hash_qpath(qpath),
-            TyKind::OpaqueDef(_, arg_list) => {
+            TyKind::OpaqueDef(_, arg_list, in_trait) => {
                 self.hash_generic_args(arg_list);
+                in_trait.hash(&mut self.s);
             },
             TyKind::TraitObject(_, lifetime, _) => {
                 self.hash_lifetime(*lifetime);
@@ -1010,7 +1011,7 @@ pub fn hash_array_length(&mut self, length: ArrayLen) {
     pub fn hash_body(&mut self, body_id: BodyId) {
         // swap out TypeckResults when hashing a body
         let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id));
-        self.hash_expr(&self.cx.tcx.hir().body(body_id).value);
+        self.hash_expr(self.cx.tcx.hir().body(body_id).value);
         self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
@@ -1018,7 +1019,7 @@ fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) {
         for arg in arg_list {
             match *arg {
                 GenericArg::Lifetime(l) => self.hash_lifetime(l),
-                GenericArg::Type(ref ty) => self.hash_ty(ty),
+                GenericArg::Type(ty) => self.hash_ty(ty),
                 GenericArg::Const(ref ca) => self.hash_body(ca.value.body),
                 GenericArg::Infer(ref inf) => self.hash_ty(&inf.to_ty()),
             }
index b27439cbec278bec5bafb3fd46e47b7d0deb0422..bdb858e1f9384b307172f2802f92d7ce4001b0ff 100644 (file)
@@ -1031,12 +1031,12 @@ fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) {
     v.allow_closure.then_some(v.captures)
 }
 
+/// Arguments of a method: the receiver and all the additional arguments.
+pub type MethodArguments<'tcx> = Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>;
+
 /// Returns the method names and argument list of nested method call expressions that make up
 /// `expr`. method/span lists are sorted with the most recent call first.
-pub fn method_calls<'tcx>(
-    expr: &'tcx Expr<'tcx>,
-    max_depth: usize,
-) -> (Vec<Symbol>, Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>, Vec<Span>) {
+pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec<Symbol>, MethodArguments<'tcx>, Vec<Span>) {
     let mut method_names = Vec::with_capacity(max_depth);
     let mut arg_lists = Vec::with_capacity(max_depth);
     let mut spans = Vec::with_capacity(max_depth);
@@ -1552,7 +1552,8 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It
 pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
         if_chain! {
-            if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
+            if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind;
+            if ddpos.as_opt_usize().is_none();
             if is_lang_ctor(cx, path, ResultOk);
             if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
             if path_to_local_id(arm.body, hir_id);
index 43e53f3feebd31429644fca6943951a93720019c..bd89ff977f87791dd6deacaf193b34e7781ffd62 100644 (file)
@@ -389,8 +389,10 @@ fn new(cx: &LateContext<'_>, pieces: &Expr<'_>) -> Option<Self> {
         };
 
         let mut unescaped = String::with_capacity(inner.len());
-        unescape_literal(inner, mode, &mut |_, ch| {
-            unescaped.push(ch.unwrap());
+        unescape_literal(inner, mode, &mut |_, ch| match ch {
+            Ok(ch) => unescaped.push(ch),
+            Err(e) if !e.is_fatal() => (),
+            Err(e) => panic!("{:?}", e),
         });
 
         let mut parts = Vec::new();
index 74c222bbcbeb99e6bda141ed4af1033c47915b3a..d5f64e5118f563b97cc2c497b1d1fa2dd7429d78 100644 (file)
@@ -6,8 +6,8 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{
-    Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
-    TerminatorKind,
+    Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind,
+    Terminator, TerminatorKind,
 };
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
@@ -212,11 +212,16 @@ fn check_statement<'tcx>(
             check_place(tcx, **place, span, body)
         },
 
-        StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
+        StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body),
+
+        StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+            rustc_middle::mir::CopyNonOverlapping { dst, src, count },
+        )) => {
             check_operand(tcx, dst, span, body)?;
             check_operand(tcx, src, span, body)?;
             check_operand(tcx, count, span, body)
         },
+
         // These are all NOPs
         StatementKind::StorageLive(_)
         | StatementKind::StorageDead(_)
index 6a62002a4d12e3274f14773f79c9ac41b3524aec..232d571902b6c20a8f84684e7ca1ca5e88206f47 100644 (file)
@@ -274,7 +274,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
         }
         !found
     })
-    .visit_expr(&cx.tcx.hir().body(body).value);
+    .visit_expr(cx.tcx.hir().body(body).value);
     found
 }
 
@@ -568,6 +568,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
 // Calls the given function for every unconsumed temporary created by the expression. Note the
 // function is only guaranteed to be called for types which need to be dropped, but it may be called
 // for other types.
+#[allow(clippy::too_many_lines)]
 pub fn for_each_unconsumed_temporary<'tcx, B>(
     cx: &LateContext<'tcx>,
     e: &'tcx Expr<'tcx>,
index 4fbae8614ca3daa060945a2862d65432bba921d5..ebbe9c9ae675f0039510d8e736cc2a79fbadf59c 100644 (file)
@@ -1,6 +1,6 @@
 [crates]
 # some of these are from cargotest
-cargo = {name = "cargo", versions = ['0.49.0']}
+cargo = {name = "cargo", versions = ['0.64.0']}
 iron = {name = "iron", versions = ['0.6.1']}
 ripgrep = {name = "ripgrep", versions = ['12.1.1']}
 xsv = {name = "xsv", versions = ['0.13.0']}
index 85b60fefd60fc4ab84a271c50ebc510bd7449221..b6976366dafc9c66287a30ac986407e9865998eb 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-08-27"
+channel = "nightly-2022-09-08"
 components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/docs.rs b/src/tools/clippy/src/docs.rs
new file mode 100644 (file)
index 0000000..f3a5048
--- /dev/null
@@ -0,0 +1,596 @@
+// autogenerated. Please look at /clippy_dev/src/update_lints.rs
+
+macro_rules! include_lint {
+    ($file_name: expr) => {
+        include_str!($file_name)
+    };
+}
+
+macro_rules! docs {
+    ($($lint_name: expr,)*) => {
+        pub fn explain(lint: &str) {
+            println!("{}", match lint {
+                $(
+                    $lint_name => include_lint!(concat!("docs/", concat!($lint_name, ".txt"))),
+                )*
+                _ => "unknown lint",
+            })
+        }
+    }
+}
+
+docs! {
+    "absurd_extreme_comparisons",
+    "alloc_instead_of_core",
+    "allow_attributes_without_reason",
+    "almost_complete_letter_range",
+    "almost_swapped",
+    "approx_constant",
+    "arithmetic_side_effects",
+    "as_conversions",
+    "as_underscore",
+    "assertions_on_constants",
+    "assertions_on_result_states",
+    "assign_op_pattern",
+    "async_yields_async",
+    "await_holding_invalid_type",
+    "await_holding_lock",
+    "await_holding_refcell_ref",
+    "bad_bit_mask",
+    "bind_instead_of_map",
+    "blanket_clippy_restriction_lints",
+    "blocks_in_if_conditions",
+    "bool_assert_comparison",
+    "bool_comparison",
+    "bool_to_int_with_if",
+    "borrow_as_ptr",
+    "borrow_deref_ref",
+    "borrow_interior_mutable_const",
+    "borrowed_box",
+    "box_collection",
+    "boxed_local",
+    "branches_sharing_code",
+    "builtin_type_shadow",
+    "bytes_count_to_len",
+    "bytes_nth",
+    "cargo_common_metadata",
+    "case_sensitive_file_extension_comparisons",
+    "cast_abs_to_unsigned",
+    "cast_enum_constructor",
+    "cast_enum_truncation",
+    "cast_lossless",
+    "cast_possible_truncation",
+    "cast_possible_wrap",
+    "cast_precision_loss",
+    "cast_ptr_alignment",
+    "cast_ref_to_mut",
+    "cast_sign_loss",
+    "cast_slice_different_sizes",
+    "cast_slice_from_raw_parts",
+    "char_lit_as_u8",
+    "chars_last_cmp",
+    "chars_next_cmp",
+    "checked_conversions",
+    "clone_double_ref",
+    "clone_on_copy",
+    "clone_on_ref_ptr",
+    "cloned_instead_of_copied",
+    "cmp_nan",
+    "cmp_null",
+    "cmp_owned",
+    "cognitive_complexity",
+    "collapsible_else_if",
+    "collapsible_if",
+    "collapsible_match",
+    "collapsible_str_replace",
+    "comparison_chain",
+    "comparison_to_empty",
+    "copy_iterator",
+    "crate_in_macro_def",
+    "create_dir",
+    "crosspointer_transmute",
+    "dbg_macro",
+    "debug_assert_with_mut_call",
+    "decimal_literal_representation",
+    "declare_interior_mutable_const",
+    "default_instead_of_iter_empty",
+    "default_numeric_fallback",
+    "default_trait_access",
+    "default_union_representation",
+    "deprecated_cfg_attr",
+    "deprecated_semver",
+    "deref_addrof",
+    "deref_by_slicing",
+    "derivable_impls",
+    "derive_hash_xor_eq",
+    "derive_ord_xor_partial_ord",
+    "derive_partial_eq_without_eq",
+    "disallowed_methods",
+    "disallowed_names",
+    "disallowed_script_idents",
+    "disallowed_types",
+    "diverging_sub_expression",
+    "doc_link_with_quotes",
+    "doc_markdown",
+    "double_comparisons",
+    "double_must_use",
+    "double_neg",
+    "double_parens",
+    "drop_copy",
+    "drop_non_drop",
+    "drop_ref",
+    "duplicate_mod",
+    "duplicate_underscore_argument",
+    "duration_subsec",
+    "else_if_without_else",
+    "empty_drop",
+    "empty_enum",
+    "empty_line_after_outer_attr",
+    "empty_loop",
+    "empty_structs_with_brackets",
+    "enum_clike_unportable_variant",
+    "enum_glob_use",
+    "enum_variant_names",
+    "eq_op",
+    "equatable_if_let",
+    "erasing_op",
+    "err_expect",
+    "excessive_precision",
+    "exhaustive_enums",
+    "exhaustive_structs",
+    "exit",
+    "expect_fun_call",
+    "expect_used",
+    "expl_impl_clone_on_copy",
+    "explicit_auto_deref",
+    "explicit_counter_loop",
+    "explicit_deref_methods",
+    "explicit_into_iter_loop",
+    "explicit_iter_loop",
+    "explicit_write",
+    "extend_with_drain",
+    "extra_unused_lifetimes",
+    "fallible_impl_from",
+    "field_reassign_with_default",
+    "filetype_is_file",
+    "filter_map_identity",
+    "filter_map_next",
+    "filter_next",
+    "flat_map_identity",
+    "flat_map_option",
+    "float_arithmetic",
+    "float_cmp",
+    "float_cmp_const",
+    "float_equality_without_abs",
+    "fn_address_comparisons",
+    "fn_params_excessive_bools",
+    "fn_to_numeric_cast",
+    "fn_to_numeric_cast_any",
+    "fn_to_numeric_cast_with_truncation",
+    "for_kv_map",
+    "for_loops_over_fallibles",
+    "forget_copy",
+    "forget_non_drop",
+    "forget_ref",
+    "format_in_format_args",
+    "format_push_string",
+    "from_iter_instead_of_collect",
+    "from_over_into",
+    "from_str_radix_10",
+    "future_not_send",
+    "get_first",
+    "get_last_with_len",
+    "get_unwrap",
+    "identity_op",
+    "if_let_mutex",
+    "if_not_else",
+    "if_same_then_else",
+    "if_then_some_else_none",
+    "ifs_same_cond",
+    "implicit_clone",
+    "implicit_hasher",
+    "implicit_return",
+    "implicit_saturating_sub",
+    "imprecise_flops",
+    "inconsistent_digit_grouping",
+    "inconsistent_struct_constructor",
+    "index_refutable_slice",
+    "indexing_slicing",
+    "ineffective_bit_mask",
+    "inefficient_to_string",
+    "infallible_destructuring_match",
+    "infinite_iter",
+    "inherent_to_string",
+    "inherent_to_string_shadow_display",
+    "init_numbered_fields",
+    "inline_always",
+    "inline_asm_x86_att_syntax",
+    "inline_asm_x86_intel_syntax",
+    "inline_fn_without_body",
+    "inspect_for_each",
+    "int_plus_one",
+    "integer_arithmetic",
+    "integer_division",
+    "into_iter_on_ref",
+    "invalid_null_ptr_usage",
+    "invalid_regex",
+    "invalid_upcast_comparisons",
+    "invalid_utf8_in_unchecked",
+    "invisible_characters",
+    "is_digit_ascii_radix",
+    "items_after_statements",
+    "iter_cloned_collect",
+    "iter_count",
+    "iter_next_loop",
+    "iter_next_slice",
+    "iter_not_returning_iterator",
+    "iter_nth",
+    "iter_nth_zero",
+    "iter_on_empty_collections",
+    "iter_on_single_items",
+    "iter_overeager_cloned",
+    "iter_skip_next",
+    "iter_with_drain",
+    "iterator_step_by_zero",
+    "just_underscores_and_digits",
+    "large_const_arrays",
+    "large_digit_groups",
+    "large_enum_variant",
+    "large_include_file",
+    "large_stack_arrays",
+    "large_types_passed_by_value",
+    "len_without_is_empty",
+    "len_zero",
+    "let_and_return",
+    "let_underscore_drop",
+    "let_underscore_lock",
+    "let_underscore_must_use",
+    "let_unit_value",
+    "linkedlist",
+    "lossy_float_literal",
+    "macro_use_imports",
+    "main_recursion",
+    "manual_assert",
+    "manual_async_fn",
+    "manual_bits",
+    "manual_filter_map",
+    "manual_find",
+    "manual_find_map",
+    "manual_flatten",
+    "manual_instant_elapsed",
+    "manual_map",
+    "manual_memcpy",
+    "manual_non_exhaustive",
+    "manual_ok_or",
+    "manual_range_contains",
+    "manual_rem_euclid",
+    "manual_retain",
+    "manual_saturating_arithmetic",
+    "manual_split_once",
+    "manual_str_repeat",
+    "manual_string_new",
+    "manual_strip",
+    "manual_swap",
+    "manual_unwrap_or",
+    "many_single_char_names",
+    "map_clone",
+    "map_collect_result_unit",
+    "map_entry",
+    "map_err_ignore",
+    "map_flatten",
+    "map_identity",
+    "map_unwrap_or",
+    "match_as_ref",
+    "match_bool",
+    "match_like_matches_macro",
+    "match_on_vec_items",
+    "match_overlapping_arm",
+    "match_ref_pats",
+    "match_result_ok",
+    "match_same_arms",
+    "match_single_binding",
+    "match_str_case_mismatch",
+    "match_wild_err_arm",
+    "match_wildcard_for_single_variants",
+    "maybe_infinite_iter",
+    "mem_forget",
+    "mem_replace_option_with_none",
+    "mem_replace_with_default",
+    "mem_replace_with_uninit",
+    "min_max",
+    "mismatched_target_os",
+    "mismatching_type_param_order",
+    "misrefactored_assign_op",
+    "missing_const_for_fn",
+    "missing_docs_in_private_items",
+    "missing_enforced_import_renames",
+    "missing_errors_doc",
+    "missing_inline_in_public_items",
+    "missing_panics_doc",
+    "missing_safety_doc",
+    "missing_spin_loop",
+    "mistyped_literal_suffixes",
+    "mixed_case_hex_literals",
+    "mixed_read_write_in_expression",
+    "mod_module_files",
+    "module_inception",
+    "module_name_repetitions",
+    "modulo_arithmetic",
+    "modulo_one",
+    "multi_assignments",
+    "multiple_crate_versions",
+    "multiple_inherent_impl",
+    "must_use_candidate",
+    "must_use_unit",
+    "mut_from_ref",
+    "mut_mut",
+    "mut_mutex_lock",
+    "mut_range_bound",
+    "mutable_key_type",
+    "mutex_atomic",
+    "mutex_integer",
+    "naive_bytecount",
+    "needless_arbitrary_self_type",
+    "needless_bitwise_bool",
+    "needless_bool",
+    "needless_borrow",
+    "needless_borrowed_reference",
+    "needless_collect",
+    "needless_continue",
+    "needless_doctest_main",
+    "needless_for_each",
+    "needless_late_init",
+    "needless_lifetimes",
+    "needless_match",
+    "needless_option_as_deref",
+    "needless_option_take",
+    "needless_parens_on_range_literals",
+    "needless_pass_by_value",
+    "needless_question_mark",
+    "needless_range_loop",
+    "needless_return",
+    "needless_splitn",
+    "needless_update",
+    "neg_cmp_op_on_partial_ord",
+    "neg_multiply",
+    "negative_feature_names",
+    "never_loop",
+    "new_ret_no_self",
+    "new_without_default",
+    "no_effect",
+    "no_effect_replace",
+    "no_effect_underscore_binding",
+    "non_ascii_literal",
+    "non_octal_unix_permissions",
+    "non_send_fields_in_send_ty",
+    "nonminimal_bool",
+    "nonsensical_open_options",
+    "nonstandard_macro_braces",
+    "not_unsafe_ptr_arg_deref",
+    "obfuscated_if_else",
+    "octal_escapes",
+    "ok_expect",
+    "only_used_in_recursion",
+    "op_ref",
+    "option_as_ref_deref",
+    "option_env_unwrap",
+    "option_filter_map",
+    "option_if_let_else",
+    "option_map_or_none",
+    "option_map_unit_fn",
+    "option_option",
+    "or_fun_call",
+    "or_then_unwrap",
+    "out_of_bounds_indexing",
+    "overflow_check_conditional",
+    "overly_complex_bool_expr",
+    "panic",
+    "panic_in_result_fn",
+    "panicking_unwrap",
+    "partialeq_ne_impl",
+    "partialeq_to_none",
+    "path_buf_push_overwrite",
+    "pattern_type_mismatch",
+    "positional_named_format_parameters",
+    "possible_missing_comma",
+    "precedence",
+    "print_in_format_impl",
+    "print_literal",
+    "print_stderr",
+    "print_stdout",
+    "print_with_newline",
+    "println_empty_string",
+    "ptr_arg",
+    "ptr_as_ptr",
+    "ptr_eq",
+    "ptr_offset_with_cast",
+    "pub_use",
+    "question_mark",
+    "range_minus_one",
+    "range_plus_one",
+    "range_zip_with_len",
+    "rc_buffer",
+    "rc_clone_in_vec_init",
+    "rc_mutex",
+    "read_zero_byte_vec",
+    "recursive_format_impl",
+    "redundant_allocation",
+    "redundant_clone",
+    "redundant_closure",
+    "redundant_closure_call",
+    "redundant_closure_for_method_calls",
+    "redundant_else",
+    "redundant_feature_names",
+    "redundant_field_names",
+    "redundant_pattern",
+    "redundant_pattern_matching",
+    "redundant_pub_crate",
+    "redundant_slicing",
+    "redundant_static_lifetimes",
+    "ref_binding_to_reference",
+    "ref_option_ref",
+    "repeat_once",
+    "rest_pat_in_fully_bound_structs",
+    "result_large_err",
+    "result_map_or_into_option",
+    "result_map_unit_fn",
+    "result_unit_err",
+    "return_self_not_must_use",
+    "reversed_empty_ranges",
+    "same_functions_in_if_condition",
+    "same_item_push",
+    "same_name_method",
+    "search_is_some",
+    "self_assignment",
+    "self_named_constructors",
+    "self_named_module_files",
+    "semicolon_if_nothing_returned",
+    "separated_literal_suffix",
+    "serde_api_misuse",
+    "shadow_reuse",
+    "shadow_same",
+    "shadow_unrelated",
+    "short_circuit_statement",
+    "should_implement_trait",
+    "significant_drop_in_scrutinee",
+    "similar_names",
+    "single_char_add_str",
+    "single_char_lifetime_names",
+    "single_char_pattern",
+    "single_component_path_imports",
+    "single_element_loop",
+    "single_match",
+    "single_match_else",
+    "size_of_in_element_count",
+    "skip_while_next",
+    "slow_vector_initialization",
+    "stable_sort_primitive",
+    "std_instead_of_alloc",
+    "std_instead_of_core",
+    "str_to_string",
+    "string_add",
+    "string_add_assign",
+    "string_extend_chars",
+    "string_from_utf8_as_bytes",
+    "string_lit_as_bytes",
+    "string_slice",
+    "string_to_string",
+    "strlen_on_c_strings",
+    "struct_excessive_bools",
+    "suboptimal_flops",
+    "suspicious_arithmetic_impl",
+    "suspicious_assignment_formatting",
+    "suspicious_else_formatting",
+    "suspicious_map",
+    "suspicious_op_assign_impl",
+    "suspicious_operation_groupings",
+    "suspicious_splitn",
+    "suspicious_to_owned",
+    "suspicious_unary_op_formatting",
+    "swap_ptr_to_ref",
+    "tabs_in_doc_comments",
+    "temporary_assignment",
+    "to_digit_is_some",
+    "to_string_in_format_args",
+    "todo",
+    "too_many_arguments",
+    "too_many_lines",
+    "toplevel_ref_arg",
+    "trailing_empty_array",
+    "trait_duplication_in_bounds",
+    "transmute_bytes_to_str",
+    "transmute_float_to_int",
+    "transmute_int_to_bool",
+    "transmute_int_to_char",
+    "transmute_int_to_float",
+    "transmute_num_to_bytes",
+    "transmute_ptr_to_ptr",
+    "transmute_ptr_to_ref",
+    "transmute_undefined_repr",
+    "transmutes_expressible_as_ptr_casts",
+    "transmuting_null",
+    "trim_split_whitespace",
+    "trivial_regex",
+    "trivially_copy_pass_by_ref",
+    "try_err",
+    "type_complexity",
+    "type_repetition_in_bounds",
+    "undocumented_unsafe_blocks",
+    "undropped_manually_drops",
+    "unicode_not_nfc",
+    "unimplemented",
+    "uninit_assumed_init",
+    "uninit_vec",
+    "unit_arg",
+    "unit_cmp",
+    "unit_hash",
+    "unit_return_expecting_ord",
+    "unnecessary_cast",
+    "unnecessary_filter_map",
+    "unnecessary_find_map",
+    "unnecessary_fold",
+    "unnecessary_join",
+    "unnecessary_lazy_evaluations",
+    "unnecessary_mut_passed",
+    "unnecessary_operation",
+    "unnecessary_owned_empty_strings",
+    "unnecessary_self_imports",
+    "unnecessary_sort_by",
+    "unnecessary_to_owned",
+    "unnecessary_unwrap",
+    "unnecessary_wraps",
+    "unneeded_field_pattern",
+    "unneeded_wildcard_pattern",
+    "unnested_or_patterns",
+    "unreachable",
+    "unreadable_literal",
+    "unsafe_derive_deserialize",
+    "unsafe_removed_from_name",
+    "unseparated_literal_suffix",
+    "unsound_collection_transmute",
+    "unused_async",
+    "unused_io_amount",
+    "unused_peekable",
+    "unused_rounding",
+    "unused_self",
+    "unused_unit",
+    "unusual_byte_groupings",
+    "unwrap_in_result",
+    "unwrap_or_else_default",
+    "unwrap_used",
+    "upper_case_acronyms",
+    "use_debug",
+    "use_self",
+    "used_underscore_binding",
+    "useless_asref",
+    "useless_attribute",
+    "useless_conversion",
+    "useless_format",
+    "useless_let_if_seq",
+    "useless_transmute",
+    "useless_vec",
+    "vec_box",
+    "vec_init_then_push",
+    "vec_resize_to_zero",
+    "verbose_bit_mask",
+    "verbose_file_reads",
+    "vtable_address_comparisons",
+    "while_immutable_condition",
+    "while_let_loop",
+    "while_let_on_iterator",
+    "wildcard_dependencies",
+    "wildcard_enum_match_arm",
+    "wildcard_imports",
+    "wildcard_in_or_patterns",
+    "write_literal",
+    "write_with_newline",
+    "writeln_empty_string",
+    "wrong_self_convention",
+    "wrong_transmute",
+    "zero_divided_by_zero",
+    "zero_prefixed_literal",
+    "zero_ptr",
+    "zero_sized_map_values",
+    "zst_offset",
+
+}
diff --git a/src/tools/clippy/src/docs/absurd_extreme_comparisons.txt b/src/tools/clippy/src/docs/absurd_extreme_comparisons.txt
new file mode 100644 (file)
index 0000000..590bee2
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for comparisons where one side of the relation is
+either the minimum or maximum value for its type and warns if it involves a
+case that is always true or always false. Only integer and boolean types are
+checked.
+
+### Why is this bad?
+An expression like `min <= x` may misleadingly imply
+that it is possible for `x` to be less than the minimum. Expressions like
+`max < x` are probably mistakes.
+
+### Known problems
+For `usize` the size of the current compile target will
+be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
+a comparison to detect target pointer width will trigger this lint. One can
+use `mem::sizeof` and compare its value or conditional compilation
+attributes
+like `#[cfg(target_pointer_width = "64")] ..` instead.
+
+### Example
+```
+let vec: Vec<isize> = Vec::new();
+if vec.len() <= 0 {}
+if 100 > i32::MAX {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/alloc_instead_of_core.txt b/src/tools/clippy/src/docs/alloc_instead_of_core.txt
new file mode 100644 (file)
index 0000000..488a36e
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+
+Finds items imported through `alloc` when available through `core`.
+
+### Why is this bad?
+
+Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are
+imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint
+is also useful for crates migrating to become `no_std` compatible.
+
+### Example
+```
+use alloc::slice::from_ref;
+```
+Use instead:
+```
+use core::slice::from_ref;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/allow_attributes_without_reason.txt b/src/tools/clippy/src/docs/allow_attributes_without_reason.txt
new file mode 100644 (file)
index 0000000..fcc4f49
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for attributes that allow lints without a reason.
+
+(This requires the `lint_reasons` feature)
+
+### Why is this bad?
+Allowing a lint should always have a reason. This reason should be documented to
+ensure that others understand the reasoning
+
+### Example
+```
+#![feature(lint_reasons)]
+
+#![allow(clippy::some_lint)]
+```
+
+Use instead:
+```
+#![feature(lint_reasons)]
+
+#![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")]
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/almost_complete_letter_range.txt b/src/tools/clippy/src/docs/almost_complete_letter_range.txt
new file mode 100644 (file)
index 0000000..01cbaf9
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for ranges which almost include the entire range of letters from 'a' to 'z', but
+don't because they're a half open range.
+
+### Why is this bad?
+This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
+
+### Example
+```
+let _ = 'a'..'z';
+```
+Use instead:
+```
+let _ = 'a'..='z';
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/almost_swapped.txt b/src/tools/clippy/src/docs/almost_swapped.txt
new file mode 100644 (file)
index 0000000..cd10a8d
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for `foo = bar; bar = foo` sequences.
+
+### Why is this bad?
+This looks like a failed attempt to swap.
+
+### Example
+```
+a = b;
+b = a;
+```
+If swapping is intended, use `swap()` instead:
+```
+std::mem::swap(&mut a, &mut b);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/approx_constant.txt b/src/tools/clippy/src/docs/approx_constant.txt
new file mode 100644 (file)
index 0000000..393fa4b
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for floating point literals that approximate
+constants which are defined in
+[`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants)
+or
+[`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants),
+respectively, suggesting to use the predefined constant.
+
+### Why is this bad?
+Usually, the definition in the standard library is more
+precise than what people come up with. If you find that your definition is
+actually more precise, please [file a Rust
+issue](https://github.com/rust-lang/rust/issues).
+
+### Example
+```
+let x = 3.14;
+let y = 1_f64 / x;
+```
+Use instead:
+```
+let x = std::f32::consts::PI;
+let y = std::f64::consts::FRAC_1_PI;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/arithmetic_side_effects.txt b/src/tools/clippy/src/docs/arithmetic_side_effects.txt
new file mode 100644 (file)
index 0000000..6c7d51a
--- /dev/null
@@ -0,0 +1,33 @@
+### What it does
+Checks any kind of arithmetic operation of any type.
+
+Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
+Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
+or can panic (`/`, `%`).
+
+Known safe built-in types like `Wrapping` or `Saturing`, floats, operations in constant
+environments, allowed types and non-constant operations that won't overflow are ignored.
+
+### Why is this bad?
+For integers, overflow will trigger a panic in debug builds or wrap the result in
+release mode; division by zero will cause a panic in either mode. As a result, it is
+desirable to explicitly call checked, wrapping or saturating arithmetic methods.
+
+#### Example
+```
+// `n` can be any number, including `i32::MAX`.
+fn foo(n: i32) -> i32 {
+  n + 1
+}
+```
+
+Third-party types can also overflow or present unwanted side-effects.
+
+#### Example
+```
+use rust_decimal::Decimal;
+let _n = Decimal::MAX + Decimal::MAX;
+```
+
+### Allowed types
+Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter.
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/as_conversions.txt b/src/tools/clippy/src/docs/as_conversions.txt
new file mode 100644 (file)
index 0000000..4af479b
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Checks for usage of `as` conversions.
+
+Note that this lint is specialized in linting *every single* use of `as`
+regardless of whether good alternatives exist or not.
+If you want more precise lints for `as`, please consider using these separate lints:
+`unnecessary_cast`, `cast_lossless/cast_possible_truncation/cast_possible_wrap/cast_precision_loss/cast_sign_loss`,
+`fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`.
+There is a good explanation the reason why this lint should work in this way and how it is useful
+[in this issue](https://github.com/rust-lang/rust-clippy/issues/5122).
+
+### Why is this bad?
+`as` conversions will perform many kinds of
+conversions, including silently lossy conversions and dangerous coercions.
+There are cases when it makes sense to use `as`, so the lint is
+Allow by default.
+
+### Example
+```
+let a: u32;
+...
+f(a as u16);
+```
+
+Use instead:
+```
+f(a.try_into()?);
+
+// or
+
+f(a.try_into().expect("Unexpected u16 overflow in f"));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/as_underscore.txt b/src/tools/clippy/src/docs/as_underscore.txt
new file mode 100644 (file)
index 0000000..2d9b0c3
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Check for the usage of `as _` conversion using inferred type.
+
+### Why is this bad?
+The conversion might include lossy conversion and dangerous cast that might go
+undetected due to the type being inferred.
+
+The lint is allowed by default as using `_` is less wordy than always specifying the type.
+
+### Example
+```
+fn foo(n: usize) {}
+let n: u16 = 256;
+foo(n as _);
+```
+Use instead:
+```
+fn foo(n: usize) {}
+let n: u16 = 256;
+foo(n as usize);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/assertions_on_constants.txt b/src/tools/clippy/src/docs/assertions_on_constants.txt
new file mode 100644 (file)
index 0000000..270c1e3
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for `assert!(true)` and `assert!(false)` calls.
+
+### Why is this bad?
+Will be optimized out by the compiler or should probably be replaced by a
+`panic!()` or `unreachable!()`
+
+### Example
+```
+assert!(false)
+assert!(true)
+const B: bool = false;
+assert!(B)
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/assertions_on_result_states.txt b/src/tools/clippy/src/docs/assertions_on_result_states.txt
new file mode 100644 (file)
index 0000000..0889084
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls.
+
+### Why is this bad?
+An assertion failure cannot output an useful message of the error.
+
+### Known problems
+The suggested replacement decreases the readability of code and log output.
+
+### Example
+```
+assert!(r.is_ok());
+assert!(r.is_err());
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/assign_op_pattern.txt b/src/tools/clippy/src/docs/assign_op_pattern.txt
new file mode 100644 (file)
index 0000000..f355c0c
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+Checks for `a = a op b` or `a = b commutative_op a`
+patterns.
+
+### Why is this bad?
+These can be written as the shorter `a op= b`.
+
+### Known problems
+While forbidden by the spec, `OpAssign` traits may have
+implementations that differ from the regular `Op` impl.
+
+### Example
+```
+let mut a = 5;
+let b = 0;
+// ...
+
+a = a + b;
+```
+
+Use instead:
+```
+let mut a = 5;
+let b = 0;
+// ...
+
+a += b;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/async_yields_async.txt b/src/tools/clippy/src/docs/async_yields_async.txt
new file mode 100644 (file)
index 0000000..a40de6d
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+Checks for async blocks that yield values of types
+that can themselves be awaited.
+
+### Why is this bad?
+An await is likely missing.
+
+### Example
+```
+async fn foo() {}
+
+fn bar() {
+  let x = async {
+    foo()
+  };
+}
+```
+
+Use instead:
+```
+async fn foo() {}
+
+fn bar() {
+  let x = async {
+    foo().await
+  };
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/await_holding_invalid_type.txt b/src/tools/clippy/src/docs/await_holding_invalid_type.txt
new file mode 100644 (file)
index 0000000..e9c7687
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Allows users to configure types which should not be held across `await`
+suspension points.
+
+### Why is this bad?
+There are some types which are perfectly "safe" to be used concurrently
+from a memory access perspective but will cause bugs at runtime if they
+are held in such a way.
+
+### Example
+
+```
+await-holding-invalid-types = [
+  # You can specify a type name
+  "CustomLockType",
+  # You can (optionally) specify a reason
+  { path = "OtherCustomLockType", reason = "Relies on a thread local" }
+]
+```
+
+```
+struct CustomLockType;
+struct OtherCustomLockType;
+async fn foo() {
+  let _x = CustomLockType;
+  let _y = OtherCustomLockType;
+  baz().await; // Lint violation
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/await_holding_lock.txt b/src/tools/clippy/src/docs/await_holding_lock.txt
new file mode 100644 (file)
index 0000000..0f450a1
--- /dev/null
@@ -0,0 +1,51 @@
+### What it does
+Checks for calls to await while holding a non-async-aware MutexGuard.
+
+### Why is this bad?
+The Mutex types found in std::sync and parking_lot
+are not designed to operate in an async context across await points.
+
+There are two potential solutions. One is to use an async-aware Mutex
+type. Many asynchronous foundation crates provide such a Mutex type. The
+other solution is to ensure the mutex is unlocked before calling await,
+either by introducing a scope or an explicit call to Drop::drop.
+
+### Known problems
+Will report false positive for explicitly dropped guards
+([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is
+to wrap the `.lock()` call in a block instead of explicitly dropping the guard.
+
+### Example
+```
+async fn foo(x: &Mutex<u32>) {
+  let mut guard = x.lock().unwrap();
+  *guard += 1;
+  baz().await;
+}
+
+async fn bar(x: &Mutex<u32>) {
+  let mut guard = x.lock().unwrap();
+  *guard += 1;
+  drop(guard); // explicit drop
+  baz().await;
+}
+```
+
+Use instead:
+```
+async fn foo(x: &Mutex<u32>) {
+  {
+    let mut guard = x.lock().unwrap();
+    *guard += 1;
+  }
+  baz().await;
+}
+
+async fn bar(x: &Mutex<u32>) {
+  {
+    let mut guard = x.lock().unwrap();
+    *guard += 1;
+  } // guard dropped here at end of scope
+  baz().await;
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/await_holding_refcell_ref.txt b/src/tools/clippy/src/docs/await_holding_refcell_ref.txt
new file mode 100644 (file)
index 0000000..226a261
--- /dev/null
@@ -0,0 +1,47 @@
+### What it does
+Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`.
+
+### Why is this bad?
+`RefCell` refs only check for exclusive mutable access
+at runtime. Holding onto a `RefCell` ref across an `await` suspension point
+risks panics from a mutable ref shared while other refs are outstanding.
+
+### Known problems
+Will report false positive for explicitly dropped refs
+([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)). A workaround for this is
+to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref.
+
+### Example
+```
+async fn foo(x: &RefCell<u32>) {
+  let mut y = x.borrow_mut();
+  *y += 1;
+  baz().await;
+}
+
+async fn bar(x: &RefCell<u32>) {
+  let mut y = x.borrow_mut();
+  *y += 1;
+  drop(y); // explicit drop
+  baz().await;
+}
+```
+
+Use instead:
+```
+async fn foo(x: &RefCell<u32>) {
+  {
+     let mut y = x.borrow_mut();
+     *y += 1;
+  }
+  baz().await;
+}
+
+async fn bar(x: &RefCell<u32>) {
+  {
+    let mut y = x.borrow_mut();
+    *y += 1;
+  } // y dropped here at end of scope
+  baz().await;
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bad_bit_mask.txt b/src/tools/clippy/src/docs/bad_bit_mask.txt
new file mode 100644 (file)
index 0000000..d40024e
--- /dev/null
@@ -0,0 +1,30 @@
+### What it does
+Checks for incompatible bit masks in comparisons.
+
+The formula for detecting if an expression of the type `_ <bit_op> m
+<cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
+{`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
+table:
+
+|Comparison  |Bit Op|Example      |is always|Formula               |
+|------------|------|-------------|---------|----------------------|
+|`==` or `!=`| `&`  |`x & 2 == 3` |`false`  |`c & m != c`          |
+|`<`  or `>=`| `&`  |`x & 2 < 3`  |`true`   |`m < c`               |
+|`>`  or `<=`| `&`  |`x & 1 > 1`  |`false`  |`m <= c`              |
+|`==` or `!=`| `\|` |`x \| 1 == 0`|`false`  |`c \| m != c`         |
+|`<`  or `>=`| `\|` |`x \| 1 < 1` |`false`  |`m >= c`              |
+|`<=` or `>` | `\|` |`x \| 1 > 0` |`true`   |`m > c`               |
+
+### Why is this bad?
+If the bits that the comparison cares about are always
+set to zero or one by the bit mask, the comparison is constant `true` or
+`false` (depending on mask, compared value, and operators).
+
+So the code is actively misleading, and the only reason someone would write
+this intentionally is to win an underhanded Rust contest or create a
+test-case for this lint.
+
+### Example
+```
+if (x & 1 == 2) { }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bind_instead_of_map.txt b/src/tools/clippy/src/docs/bind_instead_of_map.txt
new file mode 100644 (file)
index 0000000..1485758
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
+`_.or_else(|x| Err(y))`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.map(|x| y)` or `_.map_err(|x| y)`.
+
+### Example
+```
+let _ = opt().and_then(|s| Some(s.len()));
+let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) });
+let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) });
+```
+
+The correct use would be:
+
+```
+let _ = opt().map(|s| s.len());
+let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 });
+let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 });
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/blanket_clippy_restriction_lints.txt b/src/tools/clippy/src/docs/blanket_clippy_restriction_lints.txt
new file mode 100644 (file)
index 0000000..28a4ebf
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
+
+### Why is this bad?
+Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust.
+These lints should only be enabled on a lint-by-lint basis and with careful consideration.
+
+### Example
+```
+#![deny(clippy::restriction)]
+```
+
+Use instead:
+```
+#![deny(clippy::as_conversions)]
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/blocks_in_if_conditions.txt b/src/tools/clippy/src/docs/blocks_in_if_conditions.txt
new file mode 100644 (file)
index 0000000..3afa148
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for `if` conditions that use blocks containing an
+expression, statements or conditions that use closures with blocks.
+
+### Why is this bad?
+Style, using blocks in the condition makes it hard to read.
+
+### Examples
+```
+if { true } { /* ... */ }
+
+if { let x = somefunc(); x } { /* ... */ }
+```
+
+Use instead:
+```
+if true { /* ... */ }
+
+let res = { let x = somefunc(); x };
+if res { /* ... */ }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bool_assert_comparison.txt b/src/tools/clippy/src/docs/bool_assert_comparison.txt
new file mode 100644 (file)
index 0000000..df7ca00
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+This lint warns about boolean comparisons in assert-like macros.
+
+### Why is this bad?
+It is shorter to use the equivalent.
+
+### Example
+```
+assert_eq!("a".is_empty(), false);
+assert_ne!("a".is_empty(), true);
+```
+
+Use instead:
+```
+assert!(!"a".is_empty());
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bool_comparison.txt b/src/tools/clippy/src/docs/bool_comparison.txt
new file mode 100644 (file)
index 0000000..0996f60
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for expressions of the form `x == true`,
+`x != true` and order comparisons such as `x < true` (or vice versa) and
+suggest using the variable directly.
+
+### Why is this bad?
+Unnecessary code.
+
+### Example
+```
+if x == true {}
+if y == false {}
+```
+use `x` directly:
+```
+if x {}
+if !y {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bool_to_int_with_if.txt b/src/tools/clippy/src/docs/bool_to_int_with_if.txt
new file mode 100644 (file)
index 0000000..63535b4
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Instead of using an if statement to convert a bool to an int,
+this lint suggests using a `from()` function or an `as` coercion.
+
+### Why is this bad?
+Coercion or `from()` is idiomatic way to convert bool to a number.
+Both methods are guaranteed to return 1 for true, and 0 for false.
+
+See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
+
+### Example
+```
+if condition {
+    1_i64
+} else {
+    0
+};
+```
+Use instead:
+```
+i64::from(condition);
+```
+or
+```
+condition as i64;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/borrow_as_ptr.txt b/src/tools/clippy/src/docs/borrow_as_ptr.txt
new file mode 100644 (file)
index 0000000..0be865a
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for the usage of `&expr as *const T` or
+`&mut expr as *mut T`, and suggest using `ptr::addr_of` or
+`ptr::addr_of_mut` instead.
+
+### Why is this bad?
+This would improve readability and avoid creating a reference
+that points to an uninitialized value or unaligned place.
+Read the `ptr::addr_of` docs for more information.
+
+### Example
+```
+let val = 1;
+let p = &val as *const i32;
+
+let mut val_mut = 1;
+let p_mut = &mut val_mut as *mut i32;
+```
+Use instead:
+```
+let val = 1;
+let p = std::ptr::addr_of!(val);
+
+let mut val_mut = 1;
+let p_mut = std::ptr::addr_of_mut!(val_mut);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/borrow_deref_ref.txt b/src/tools/clippy/src/docs/borrow_deref_ref.txt
new file mode 100644 (file)
index 0000000..352480d
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for `&*(&T)`.
+
+### Why is this bad?
+Dereferencing and then borrowing a reference value has no effect in most cases.
+
+### Known problems
+False negative on such code:
+```
+let x = &12;
+let addr_x = &x as *const _ as usize;
+let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggered.
+                                        // But if we fix it, assert will fail.
+assert_ne!(addr_x, addr_y);
+```
+
+### Example
+```
+let s = &String::new();
+
+let a: &String = &* s;
+```
+
+Use instead:
+```
+let a: &String = s;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/borrow_interior_mutable_const.txt b/src/tools/clippy/src/docs/borrow_interior_mutable_const.txt
new file mode 100644 (file)
index 0000000..e55b6a7
--- /dev/null
@@ -0,0 +1,40 @@
+### What it does
+Checks if `const` items which is interior mutable (e.g.,
+contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
+
+### Why is this bad?
+Consts are copied everywhere they are referenced, i.e.,
+every time you refer to the const a fresh instance of the `Cell` or `Mutex`
+or `AtomicXxxx` will be created, which defeats the whole purpose of using
+these types in the first place.
+
+The `const` value should be stored inside a `static` item.
+
+### Known problems
+When an enum has variants with interior mutability, use of its non
+interior mutable variants can generate false positives. See issue
+[#3962](https://github.com/rust-lang/rust-clippy/issues/3962)
+
+Types that have underlying or potential interior mutability trigger the lint whether
+the interior mutable field is used or not. See issues
+[#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
+[#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
+
+### Example
+```
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
+
+CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
+assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
+```
+
+Use instead:
+```
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
+
+static STATIC_ATOM: AtomicUsize = CONST_ATOM;
+STATIC_ATOM.store(9, SeqCst);
+assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/borrowed_box.txt b/src/tools/clippy/src/docs/borrowed_box.txt
new file mode 100644 (file)
index 0000000..d7089be
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for use of `&Box<T>` anywhere in the code.
+Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
+
+### Why is this bad?
+A `&Box<T>` parameter requires the function caller to box `T` first before passing it to a function.
+Using `&T` defines a concrete type for the parameter and generalizes the function, this would also
+auto-deref to `&T` at the function call site if passed a `&Box<T>`.
+
+### Example
+```
+fn foo(bar: &Box<T>) { ... }
+```
+
+Better:
+
+```
+fn foo(bar: &T) { ... }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/box_collection.txt b/src/tools/clippy/src/docs/box_collection.txt
new file mode 100644 (file)
index 0000000..053f24c
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for use of `Box<T>` where T is a collection such as Vec anywhere in the code.
+Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
+
+### Why is this bad?
+Collections already keeps their contents in a separate area on
+the heap. So if you `Box` them, you just add another level of indirection
+without any benefit whatsoever.
+
+### Example
+```
+struct X {
+    values: Box<Vec<Foo>>,
+}
+```
+
+Better:
+
+```
+struct X {
+    values: Vec<Foo>,
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/boxed_local.txt b/src/tools/clippy/src/docs/boxed_local.txt
new file mode 100644 (file)
index 0000000..8b1febf
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for usage of `Box<T>` where an unboxed `T` would
+work fine.
+
+### Why is this bad?
+This is an unnecessary allocation, and bad for
+performance. It is only necessary to allocate if you wish to move the box
+into something.
+
+### Example
+```
+fn foo(x: Box<u32>) {}
+```
+
+Use instead:
+```
+fn foo(x: u32) {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/branches_sharing_code.txt b/src/tools/clippy/src/docs/branches_sharing_code.txt
new file mode 100644 (file)
index 0000000..79be612
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Checks if the `if` and `else` block contain shared code that can be
+moved out of the blocks.
+
+### Why is this bad?
+Duplicate code is less maintainable.
+
+### Known problems
+* The lint doesn't check if the moved expressions modify values that are being used in
+  the if condition. The suggestion can in that case modify the behavior of the program.
+  See [rust-clippy#7452](https://github.com/rust-lang/rust-clippy/issues/7452)
+
+### Example
+```
+let foo = if … {
+    println!("Hello World");
+    13
+} else {
+    println!("Hello World");
+    42
+};
+```
+
+Use instead:
+```
+println!("Hello World");
+let foo = if … {
+    13
+} else {
+    42
+};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/builtin_type_shadow.txt b/src/tools/clippy/src/docs/builtin_type_shadow.txt
new file mode 100644 (file)
index 0000000..15b1c9d
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Warns if a generic shadows a built-in type.
+
+### Why is this bad?
+This gives surprising type errors.
+
+### Example
+
+```
+impl<u32> Foo<u32> {
+    fn impl_func(&self) -> u32 {
+        42
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bytes_count_to_len.txt b/src/tools/clippy/src/docs/bytes_count_to_len.txt
new file mode 100644 (file)
index 0000000..ca7bf9a
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+It checks for `str::bytes().count()` and suggests replacing it with
+`str::len()`.
+
+### Why is this bad?
+`str::bytes().count()` is longer and may not be as performant as using
+`str::len()`.
+
+### Example
+```
+"hello".bytes().count();
+String::from("hello").bytes().count();
+```
+Use instead:
+```
+"hello".len();
+String::from("hello").len();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bytes_nth.txt b/src/tools/clippy/src/docs/bytes_nth.txt
new file mode 100644 (file)
index 0000000..260de34
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for the use of `.bytes().nth()`.
+
+### Why is this bad?
+`.as_bytes().get()` is more efficient and more
+readable.
+
+### Example
+```
+"Hello".bytes().nth(3);
+```
+
+Use instead:
+```
+"Hello".as_bytes().get(3);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cargo_common_metadata.txt b/src/tools/clippy/src/docs/cargo_common_metadata.txt
new file mode 100644 (file)
index 0000000..1998647
--- /dev/null
@@ -0,0 +1,33 @@
+### What it does
+Checks to see if all common metadata is defined in
+`Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata
+
+### Why is this bad?
+It will be more difficult for users to discover the
+purpose of the crate, and key information related to it.
+
+### Example
+```
+[package]
+name = "clippy"
+version = "0.0.212"
+repository = "https://github.com/rust-lang/rust-clippy"
+readme = "README.md"
+license = "MIT OR Apache-2.0"
+keywords = ["clippy", "lint", "plugin"]
+categories = ["development-tools", "development-tools::cargo-plugins"]
+```
+
+Should include a description field like:
+
+```
+[package]
+name = "clippy"
+version = "0.0.212"
+description = "A bunch of helpful lints to avoid common pitfalls in Rust"
+repository = "https://github.com/rust-lang/rust-clippy"
+readme = "README.md"
+license = "MIT OR Apache-2.0"
+keywords = ["clippy", "lint", "plugin"]
+categories = ["development-tools", "development-tools::cargo-plugins"]
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/case_sensitive_file_extension_comparisons.txt b/src/tools/clippy/src/docs/case_sensitive_file_extension_comparisons.txt
new file mode 100644 (file)
index 0000000..8e6e18e
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for calls to `ends_with` with possible file extensions
+and suggests to use a case-insensitive approach instead.
+
+### Why is this bad?
+`ends_with` is case-sensitive and may not detect files with a valid extension.
+
+### Example
+```
+fn is_rust_file(filename: &str) -> bool {
+    filename.ends_with(".rs")
+}
+```
+Use instead:
+```
+fn is_rust_file(filename: &str) -> bool {
+    let filename = std::path::Path::new(filename);
+    filename.extension()
+        .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_abs_to_unsigned.txt b/src/tools/clippy/src/docs/cast_abs_to_unsigned.txt
new file mode 100644 (file)
index 0000000..c5d8ee0
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for uses of the `abs()` method that cast the result to unsigned.
+
+### Why is this bad?
+The `unsigned_abs()` method avoids panic when called on the MIN value.
+
+### Example
+```
+let x: i32 = -42;
+let y: u32 = x.abs() as u32;
+```
+Use instead:
+```
+let x: i32 = -42;
+let y: u32 = x.unsigned_abs();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_enum_constructor.txt b/src/tools/clippy/src/docs/cast_enum_constructor.txt
new file mode 100644 (file)
index 0000000..675c03a
--- /dev/null
@@ -0,0 +1,11 @@
+### What it does
+Checks for casts from an enum tuple constructor to an integer.
+
+### Why is this bad?
+The cast is easily confused with casting a c-like enum value to an integer.
+
+### Example
+```
+enum E { X(i32) };
+let _ = E::X as usize;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_enum_truncation.txt b/src/tools/clippy/src/docs/cast_enum_truncation.txt
new file mode 100644 (file)
index 0000000..abe32a8
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for casts from an enum type to an integral type which will definitely truncate the
+value.
+
+### Why is this bad?
+The resulting integral value will not match the value of the variant it came from.
+
+### Example
+```
+enum E { X = 256 };
+let _ = E::X as u8;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_lossless.txt b/src/tools/clippy/src/docs/cast_lossless.txt
new file mode 100644 (file)
index 0000000..c3a61dd
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for casts between numerical types that may
+be replaced by safe conversion functions.
+
+### Why is this bad?
+Rust's `as` keyword will perform many kinds of
+conversions, including silently lossy conversions. Conversion functions such
+as `i32::from` will only perform lossless conversions. Using the conversion
+functions prevents conversions from turning into silent lossy conversions if
+the types of the input expressions ever change, and make it easier for
+people reading the code to know that the conversion is lossless.
+
+### Example
+```
+fn as_u64(x: u8) -> u64 {
+    x as u64
+}
+```
+
+Using `::from` would look like this:
+
+```
+fn as_u64(x: u8) -> u64 {
+    u64::from(x)
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_possible_truncation.txt b/src/tools/clippy/src/docs/cast_possible_truncation.txt
new file mode 100644 (file)
index 0000000..0b16484
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for casts between numerical types that may
+truncate large values. This is expected behavior, so the cast is `Allow` by
+default.
+
+### Why is this bad?
+In some problem domains, it is good practice to avoid
+truncation. This lint can be activated to help assess where additional
+checks could be beneficial.
+
+### Example
+```
+fn as_u8(x: u64) -> u8 {
+    x as u8
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_possible_wrap.txt b/src/tools/clippy/src/docs/cast_possible_wrap.txt
new file mode 100644 (file)
index 0000000..f883fc9
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for casts from an unsigned type to a signed type of
+the same size. Performing such a cast is a 'no-op' for the compiler,
+i.e., nothing is changed at the bit level, and the binary representation of
+the value is reinterpreted. This can cause wrapping if the value is too big
+for the target signed type. However, the cast works as defined, so this lint
+is `Allow` by default.
+
+### Why is this bad?
+While such a cast is not bad in itself, the results can
+be surprising when this is not the intended behavior, as demonstrated by the
+example below.
+
+### Example
+```
+u32::MAX as i32; // will yield a value of `-1`
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_precision_loss.txt b/src/tools/clippy/src/docs/cast_precision_loss.txt
new file mode 100644 (file)
index 0000000..f915d9f
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for casts from any numerical to a float type where
+the receiving type cannot store all values from the original type without
+rounding errors. This possible rounding is to be expected, so this lint is
+`Allow` by default.
+
+Basically, this warns on casting any integer with 32 or more bits to `f32`
+or any 64-bit integer to `f64`.
+
+### Why is this bad?
+It's not bad at all. But in some applications it can be
+helpful to know where precision loss can take place. This lint can help find
+those places in the code.
+
+### Example
+```
+let x = u64::MAX;
+x as f64;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_ptr_alignment.txt b/src/tools/clippy/src/docs/cast_ptr_alignment.txt
new file mode 100644 (file)
index 0000000..6a6d4dc
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for casts, using `as` or `pointer::cast`,
+from a less-strictly-aligned pointer to a more-strictly-aligned pointer
+
+### Why is this bad?
+Dereferencing the resulting pointer may be undefined
+behavior.
+
+### Known problems
+Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
+on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
+u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
+
+### Example
+```
+let _ = (&1u8 as *const u8) as *const u16;
+let _ = (&mut 1u8 as *mut u8) as *mut u16;
+
+(&1u8 as *const u8).cast::<u16>();
+(&mut 1u8 as *mut u8).cast::<u16>();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_ref_to_mut.txt b/src/tools/clippy/src/docs/cast_ref_to_mut.txt
new file mode 100644 (file)
index 0000000..fb5b4db
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+Checks for casts of `&T` to `&mut T` anywhere in the code.
+
+### Why is this bad?
+It’s basically guaranteed to be undefined behavior.
+`UnsafeCell` is the only way to obtain aliasable data that is considered
+mutable.
+
+### Example
+```
+fn x(r: &i32) {
+    unsafe {
+        *(r as *const _ as *mut _) += 1;
+    }
+}
+```
+
+Instead consider using interior mutability types.
+
+```
+use std::cell::UnsafeCell;
+
+fn x(r: &UnsafeCell<i32>) {
+    unsafe {
+        *r.get() += 1;
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_sign_loss.txt b/src/tools/clippy/src/docs/cast_sign_loss.txt
new file mode 100644 (file)
index 0000000..d64fe1b
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for casts from a signed to an unsigned numerical
+type. In this case, negative values wrap around to large positive values,
+which can be quite surprising in practice. However, as the cast works as
+defined, this lint is `Allow` by default.
+
+### Why is this bad?
+Possibly surprising results. You can activate this lint
+as a one-time check to see where numerical wrapping can arise.
+
+### Example
+```
+let y: i8 = -1;
+y as u128; // will return 18446744073709551615
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_slice_different_sizes.txt b/src/tools/clippy/src/docs/cast_slice_different_sizes.txt
new file mode 100644 (file)
index 0000000..c01ef0b
--- /dev/null
@@ -0,0 +1,38 @@
+### What it does
+Checks for `as` casts between raw pointers to slices with differently sized elements.
+
+### Why is this bad?
+The produced raw pointer to a slice does not update its length metadata. The produced
+pointer will point to a different number of bytes than the original pointer because the
+length metadata of a raw slice pointer is in elements rather than bytes.
+Producing a slice reference from the raw pointer will either create a slice with
+less data (which can be surprising) or create a slice with more data and cause Undefined Behavior.
+
+### Example
+// Missing data
+```
+let a = [1_i32, 2, 3, 4];
+let p = &a as *const [i32] as *const [u8];
+unsafe {
+    println!("{:?}", &*p);
+}
+```
+// Undefined Behavior (note: also potential alignment issues)
+```
+let a = [1_u8, 2, 3, 4];
+let p = &a as *const [u8] as *const [u32];
+unsafe {
+    println!("{:?}", &*p);
+}
+```
+Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length
+```
+let a = [1_i32, 2, 3, 4];
+let old_ptr = &a as *const [i32];
+// The data pointer is cast to a pointer to the target `u8` not `[u8]`
+// The length comes from the known length of 4 i32s times the 4 bytes per i32
+let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16);
+unsafe {
+    println!("{:?}", &*new_ptr);
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_slice_from_raw_parts.txt b/src/tools/clippy/src/docs/cast_slice_from_raw_parts.txt
new file mode 100644 (file)
index 0000000..b58c739
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for a raw slice being cast to a slice pointer
+
+### Why is this bad?
+This can result in multiple `&mut` references to the same location when only a pointer is
+required.
+`ptr::slice_from_raw_parts` is a safe alternative that doesn't require
+the same [safety requirements] to be upheld.
+
+### Example
+```
+let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _;
+let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _;
+```
+Use instead:
+```
+let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len);
+let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
+```
+[safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/char_lit_as_u8.txt b/src/tools/clippy/src/docs/char_lit_as_u8.txt
new file mode 100644 (file)
index 0000000..00d60b9
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for expressions where a character literal is cast
+to `u8` and suggests using a byte literal instead.
+
+### Why is this bad?
+In general, casting values to smaller types is
+error-prone and should be avoided where possible. In the particular case of
+converting a character literal to u8, it is easy to avoid by just using a
+byte literal instead. As an added bonus, `b'a'` is even slightly shorter
+than `'a' as u8`.
+
+### Example
+```
+'x' as u8
+```
+
+A better version, using the byte literal:
+
+```
+b'x'
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/chars_last_cmp.txt b/src/tools/clippy/src/docs/chars_last_cmp.txt
new file mode 100644 (file)
index 0000000..4c1d883
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for usage of `_.chars().last()` or
+`_.chars().next_back()` on a `str` to check if it ends with a given char.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.ends_with(_)`.
+
+### Example
+```
+name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
+```
+
+Use instead:
+```
+name.ends_with('_') || name.ends_with('-');
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/chars_next_cmp.txt b/src/tools/clippy/src/docs/chars_next_cmp.txt
new file mode 100644 (file)
index 0000000..77cbce2
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `.chars().next()` on a `str` to check
+if it starts with a given char.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.starts_with(_)`.
+
+### Example
+```
+let name = "foo";
+if name.chars().next() == Some('_') {};
+```
+
+Use instead:
+```
+let name = "foo";
+if name.starts_with('_') {};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/checked_conversions.txt b/src/tools/clippy/src/docs/checked_conversions.txt
new file mode 100644 (file)
index 0000000..536b012
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for explicit bounds checking when casting.
+
+### Why is this bad?
+Reduces the readability of statements & is error prone.
+
+### Example
+```
+foo <= i32::MAX as u32;
+```
+
+Use instead:
+```
+i32::try_from(foo).is_ok();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/clone_double_ref.txt b/src/tools/clippy/src/docs/clone_double_ref.txt
new file mode 100644 (file)
index 0000000..2729635
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `.clone()` on an `&&T`.
+
+### Why is this bad?
+Cloning an `&&T` copies the inner `&T`, instead of
+cloning the underlying `T`.
+
+### Example
+```
+fn main() {
+    let x = vec![1];
+    let y = &&x;
+    let z = y.clone();
+    println!("{:p} {:p}", *y, z); // prints out the same pointer
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/clone_on_copy.txt b/src/tools/clippy/src/docs/clone_on_copy.txt
new file mode 100644 (file)
index 0000000..99a0bdb
--- /dev/null
@@ -0,0 +1,11 @@
+### What it does
+Checks for usage of `.clone()` on a `Copy` type.
+
+### Why is this bad?
+The only reason `Copy` types implement `Clone` is for
+generics, not for using the `clone` method on a concrete type.
+
+### Example
+```
+42u64.clone();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/clone_on_ref_ptr.txt b/src/tools/clippy/src/docs/clone_on_ref_ptr.txt
new file mode 100644 (file)
index 0000000..2d83f8f
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for usage of `.clone()` on a ref-counted pointer,
+(`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
+function syntax instead (e.g., `Rc::clone(foo)`).
+
+### Why is this bad?
+Calling '.clone()' on an Rc, Arc, or Weak
+can obscure the fact that only the pointer is being cloned, not the underlying
+data.
+
+### Example
+```
+let x = Rc::new(1);
+
+x.clone();
+```
+
+Use instead:
+```
+Rc::clone(&x);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cloned_instead_of_copied.txt b/src/tools/clippy/src/docs/cloned_instead_of_copied.txt
new file mode 100644 (file)
index 0000000..2f2014d
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for usages of `cloned()` on an `Iterator` or `Option` where
+`copied()` could be used instead.
+
+### Why is this bad?
+`copied()` is better because it guarantees that the type being cloned
+implements `Copy`.
+
+### Example
+```
+[1, 2, 3].iter().cloned();
+```
+Use instead:
+```
+[1, 2, 3].iter().copied();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cmp_nan.txt b/src/tools/clippy/src/docs/cmp_nan.txt
new file mode 100644 (file)
index 0000000..e2ad04d
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for comparisons to NaN.
+
+### Why is this bad?
+NaN does not compare meaningfully to anything – not
+even itself – so those comparisons are simply wrong.
+
+### Example
+```
+if x == f32::NAN { }
+```
+
+Use instead:
+```
+if x.is_nan() { }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cmp_null.txt b/src/tools/clippy/src/docs/cmp_null.txt
new file mode 100644 (file)
index 0000000..02fd151
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+This lint checks for equality comparisons with `ptr::null`
+
+### Why is this bad?
+It's easier and more readable to use the inherent
+`.is_null()`
+method instead
+
+### Example
+```
+use std::ptr;
+
+if x == ptr::null {
+    // ..
+}
+```
+
+Use instead:
+```
+if x.is_null() {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cmp_owned.txt b/src/tools/clippy/src/docs/cmp_owned.txt
new file mode 100644 (file)
index 0000000..f8d4956
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for conversions to owned values just for the sake
+of a comparison.
+
+### Why is this bad?
+The comparison can operate on a reference, so creating
+an owned value effectively throws it away directly afterwards, which is
+needlessly consuming code and heap space.
+
+### Example
+```
+if x.to_owned() == y {}
+```
+
+Use instead:
+```
+if x == y {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cognitive_complexity.txt b/src/tools/clippy/src/docs/cognitive_complexity.txt
new file mode 100644 (file)
index 0000000..fdd75f6
--- /dev/null
@@ -0,0 +1,13 @@
+### What it does
+Checks for methods with high cognitive complexity.
+
+### Why is this bad?
+Methods of high cognitive complexity tend to be hard to
+both read and maintain. Also LLVM will tend to optimize small methods better.
+
+### Known problems
+Sometimes it's hard to find a way to reduce the
+complexity.
+
+### Example
+You'll see it when you get the warning.
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/collapsible_else_if.txt b/src/tools/clippy/src/docs/collapsible_else_if.txt
new file mode 100644 (file)
index 0000000..4ddfca1
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for collapsible `else { if ... }` expressions
+that can be collapsed to `else if ...`.
+
+### Why is this bad?
+Each `if`-statement adds one level of nesting, which
+makes code look more complex than it really is.
+
+### Example
+```
+
+if x {
+    …
+} else {
+    if y {
+        …
+    }
+}
+```
+
+Should be written:
+
+```
+if x {
+    …
+} else if y {
+    …
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/collapsible_if.txt b/src/tools/clippy/src/docs/collapsible_if.txt
new file mode 100644 (file)
index 0000000..e1264ee
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for nested `if` statements which can be collapsed
+by `&&`-combining their conditions.
+
+### Why is this bad?
+Each `if`-statement adds one level of nesting, which
+makes code look more complex than it really is.
+
+### Example
+```
+if x {
+    if y {
+        // …
+    }
+}
+```
+
+Use instead:
+```
+if x && y {
+    // …
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/collapsible_match.txt b/src/tools/clippy/src/docs/collapsible_match.txt
new file mode 100644 (file)
index 0000000..0d59594
--- /dev/null
@@ -0,0 +1,31 @@
+### What it does
+Finds nested `match` or `if let` expressions where the patterns may be "collapsed" together
+without adding any branches.
+
+Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only
+cases where merging would most likely make the code more readable.
+
+### Why is this bad?
+It is unnecessarily verbose and complex.
+
+### Example
+```
+fn func(opt: Option<Result<u64, String>>) {
+    let n = match opt {
+        Some(n) => match n {
+            Ok(n) => n,
+            _ => return,
+        }
+        None => return,
+    };
+}
+```
+Use instead:
+```
+fn func(opt: Option<Result<u64, String>>) {
+    let n = match opt {
+        Some(Ok(n)) => n,
+        _ => return,
+    };
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/collapsible_str_replace.txt b/src/tools/clippy/src/docs/collapsible_str_replace.txt
new file mode 100644 (file)
index 0000000..c24c25a
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for consecutive calls to `str::replace` (2 or more)
+that can be collapsed into a single call.
+
+### Why is this bad?
+Consecutive `str::replace` calls scan the string multiple times
+with repetitive code.
+
+### Example
+```
+let hello = "hesuo worpd"
+    .replace('s', "l")
+    .replace("u", "l")
+    .replace('p', "l");
+```
+Use instead:
+```
+let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/comparison_chain.txt b/src/tools/clippy/src/docs/comparison_chain.txt
new file mode 100644 (file)
index 0000000..43b09f3
--- /dev/null
@@ -0,0 +1,36 @@
+### What it does
+Checks comparison chains written with `if` that can be
+rewritten with `match` and `cmp`.
+
+### Why is this bad?
+`if` is not guaranteed to be exhaustive and conditionals can get
+repetitive
+
+### Known problems
+The match statement may be slower due to the compiler
+not inlining the call to cmp. See issue [#5354](https://github.com/rust-lang/rust-clippy/issues/5354)
+
+### Example
+```
+fn f(x: u8, y: u8) {
+    if x > y {
+        a()
+    } else if x < y {
+        b()
+    } else {
+        c()
+    }
+}
+```
+
+Use instead:
+```
+use std::cmp::Ordering;
+fn f(x: u8, y: u8) {
+     match x.cmp(&y) {
+         Ordering::Greater => a(),
+         Ordering::Less => b(),
+         Ordering::Equal => c()
+     }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/comparison_to_empty.txt b/src/tools/clippy/src/docs/comparison_to_empty.txt
new file mode 100644 (file)
index 0000000..db6f74f
--- /dev/null
@@ -0,0 +1,31 @@
+### What it does
+Checks for comparing to an empty slice such as `""` or `[]`,
+and suggests using `.is_empty()` where applicable.
+
+### Why is this bad?
+Some structures can answer `.is_empty()` much faster
+than checking for equality. So it is good to get into the habit of using
+`.is_empty()`, and having it is cheap.
+Besides, it makes the intent clearer than a manual comparison in some contexts.
+
+### Example
+
+```
+if s == "" {
+    ..
+}
+
+if arr == [] {
+    ..
+}
+```
+Use instead:
+```
+if s.is_empty() {
+    ..
+}
+
+if arr.is_empty() {
+    ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/copy_iterator.txt b/src/tools/clippy/src/docs/copy_iterator.txt
new file mode 100644 (file)
index 0000000..5f9a2a0
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for types that implement `Copy` as well as
+`Iterator`.
+
+### Why is this bad?
+Implicit copies can be confusing when working with
+iterator combinators.
+
+### Example
+```
+#[derive(Copy, Clone)]
+struct Countdown(u8);
+
+impl Iterator for Countdown {
+    // ...
+}
+
+let a: Vec<_> = my_iterator.take(1).collect();
+let b: Vec<_> = my_iterator.collect();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/crate_in_macro_def.txt b/src/tools/clippy/src/docs/crate_in_macro_def.txt
new file mode 100644 (file)
index 0000000..047e986
--- /dev/null
@@ -0,0 +1,35 @@
+### What it does
+Checks for use of `crate` as opposed to `$crate` in a macro definition.
+
+### Why is this bad?
+`crate` refers to the macro call's crate, whereas `$crate` refers to the macro definition's
+crate. Rarely is the former intended. See:
+https://doc.rust-lang.org/reference/macros-by-example.html#hygiene
+
+### Example
+```
+#[macro_export]
+macro_rules! print_message {
+    () => {
+        println!("{}", crate::MESSAGE);
+    };
+}
+pub const MESSAGE: &str = "Hello!";
+```
+Use instead:
+```
+#[macro_export]
+macro_rules! print_message {
+    () => {
+        println!("{}", $crate::MESSAGE);
+    };
+}
+pub const MESSAGE: &str = "Hello!";
+```
+
+Note that if the use of `crate` is intentional, an `allow` attribute can be applied to the
+macro definition, e.g.:
+```
+#[allow(clippy::crate_in_macro_def)]
+macro_rules! ok { ... crate::foo ... }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/create_dir.txt b/src/tools/clippy/src/docs/create_dir.txt
new file mode 100644 (file)
index 0000000..e4e7937
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead.
+
+### Why is this bad?
+Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`.
+
+### Example
+```
+std::fs::create_dir("foo");
+```
+
+Use instead:
+```
+std::fs::create_dir_all("foo");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/crosspointer_transmute.txt b/src/tools/clippy/src/docs/crosspointer_transmute.txt
new file mode 100644 (file)
index 0000000..49dea15
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for transmutes between a type `T` and `*T`.
+
+### Why is this bad?
+It's easy to mistakenly transmute between a type and a
+pointer to that type.
+
+### Example
+```
+core::intrinsics::transmute(t) // where the result type is the same as
+                               // `*t` or `&t`'s
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/dbg_macro.txt b/src/tools/clippy/src/docs/dbg_macro.txt
new file mode 100644 (file)
index 0000000..3e1a9a0
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of dbg!() macro.
+
+### Why is this bad?
+`dbg!` macro is intended as a debugging tool. It
+should not be in version control.
+
+### Example
+```
+dbg!(true)
+```
+
+Use instead:
+```
+true
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/debug_assert_with_mut_call.txt b/src/tools/clippy/src/docs/debug_assert_with_mut_call.txt
new file mode 100644 (file)
index 0000000..2c44abe
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for function/method calls with a mutable
+parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros.
+
+### Why is this bad?
+In release builds `debug_assert!` macros are optimized out by the
+compiler.
+Therefore mutating something in a `debug_assert!` macro results in different behavior
+between a release and debug build.
+
+### Example
+```
+debug_assert_eq!(vec![3].pop(), Some(3));
+
+// or
+
+debug_assert!(takes_a_mut_parameter(&mut x));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/decimal_literal_representation.txt b/src/tools/clippy/src/docs/decimal_literal_representation.txt
new file mode 100644 (file)
index 0000000..daca9bb
--- /dev/null
@@ -0,0 +1,13 @@
+### What it does
+Warns if there is a better representation for a numeric literal.
+
+### Why is this bad?
+Especially for big powers of 2 a hexadecimal representation is more
+readable than a decimal representation.
+
+### Example
+```
+`255` => `0xFF`
+`65_535` => `0xFFFF`
+`4_042_322_160` => `0xF0F0_F0F0`
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/declare_interior_mutable_const.txt b/src/tools/clippy/src/docs/declare_interior_mutable_const.txt
new file mode 100644 (file)
index 0000000..2801b5c
--- /dev/null
@@ -0,0 +1,46 @@
+### What it does
+Checks for declaration of `const` items which is interior
+mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
+
+### Why is this bad?
+Consts are copied everywhere they are referenced, i.e.,
+every time you refer to the const a fresh instance of the `Cell` or `Mutex`
+or `AtomicXxxx` will be created, which defeats the whole purpose of using
+these types in the first place.
+
+The `const` should better be replaced by a `static` item if a global
+variable is wanted, or replaced by a `const fn` if a constructor is wanted.
+
+### Known problems
+A "non-constant" const item is a legacy way to supply an
+initialized value to downstream `static` items (e.g., the
+`std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
+and this lint should be suppressed.
+
+Even though the lint avoids triggering on a constant whose type has enums that have variants
+with interior mutability, and its value uses non interior mutable variants (see
+[#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and
+[#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples);
+it complains about associated constants without default values only based on its types;
+which might not be preferable.
+There're other enums plus associated constants cases that the lint cannot handle.
+
+Types that have underlying or potential interior mutability trigger the lint whether
+the interior mutable field is used or not. See issues
+[#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
+
+### Example
+```
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+
+const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
+CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
+assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
+```
+
+Use instead:
+```
+static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15);
+STATIC_ATOM.store(9, SeqCst);
+assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/default_instead_of_iter_empty.txt b/src/tools/clippy/src/docs/default_instead_of_iter_empty.txt
new file mode 100644 (file)
index 0000000..b63ef3d
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+It checks for `std::iter::Empty::default()` and suggests replacing it with
+`std::iter::empty()`.
+### Why is this bad?
+`std::iter::empty()` is the more idiomatic way.
+### Example
+```
+let _ = std::iter::Empty::<usize>::default();
+let iter: std::iter::Empty<usize> = std::iter::Empty::default();
+```
+Use instead:
+```
+let _ = std::iter::empty::<usize>();
+let iter: std::iter::Empty<usize> = std::iter::empty();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/default_numeric_fallback.txt b/src/tools/clippy/src/docs/default_numeric_fallback.txt
new file mode 100644 (file)
index 0000000..15076a0
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type
+inference.
+
+Default numeric fallback means that if numeric types have not yet been bound to concrete
+types at the end of type inference, then integer type is bound to `i32`, and similarly
+floating type is bound to `f64`.
+
+See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback.
+
+### Why is this bad?
+For those who are very careful about types, default numeric fallback
+can be a pitfall that cause unexpected runtime behavior.
+
+### Known problems
+This lint can only be allowed at the function level or above.
+
+### Example
+```
+let i = 10;
+let f = 1.23;
+```
+
+Use instead:
+```
+let i = 10i32;
+let f = 1.23f64;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/default_trait_access.txt b/src/tools/clippy/src/docs/default_trait_access.txt
new file mode 100644 (file)
index 0000000..e692989
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for literal calls to `Default::default()`.
+
+### Why is this bad?
+It's easier for the reader if the name of the type is used, rather than the
+generic `Default`.
+
+### Example
+```
+let s: String = Default::default();
+```
+
+Use instead:
+```
+let s = String::default();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/default_union_representation.txt b/src/tools/clippy/src/docs/default_union_representation.txt
new file mode 100644 (file)
index 0000000..f79ff97
--- /dev/null
@@ -0,0 +1,36 @@
+### What it does
+Displays a warning when a union is declared with the default representation (without a `#[repr(C)]` attribute).
+
+### Why is this bad?
+Unions in Rust have unspecified layout by default, despite many people thinking that they
+lay out each field at the start of the union (like C does). That is, there are no guarantees
+about the offset of the fields for unions with multiple non-ZST fields without an explicitly
+specified layout. These cases may lead to undefined behavior in unsafe blocks.
+
+### Example
+```
+union Foo {
+    a: i32,
+    b: u32,
+}
+
+fn main() {
+    let _x: u32 = unsafe {
+        Foo { a: 0_i32 }.b // Undefined behavior: `b` is allowed to be padding
+    };
+}
+```
+Use instead:
+```
+#[repr(C)]
+union Foo {
+    a: i32,
+    b: u32,
+}
+
+fn main() {
+    let _x: u32 = unsafe {
+        Foo { a: 0_i32 }.b // Now defined behavior, this is just an i32 -> u32 transmute
+    };
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/deprecated_cfg_attr.txt b/src/tools/clippy/src/docs/deprecated_cfg_attr.txt
new file mode 100644 (file)
index 0000000..9f26488
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it
+with `#[rustfmt::skip]`.
+
+### Why is this bad?
+Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690))
+are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes.
+
+### Known problems
+This lint doesn't detect crate level inner attributes, because they get
+processed before the PreExpansionPass lints get executed. See
+[#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765)
+
+### Example
+```
+#[cfg_attr(rustfmt, rustfmt_skip)]
+fn main() { }
+```
+
+Use instead:
+```
+#[rustfmt::skip]
+fn main() { }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/deprecated_semver.txt b/src/tools/clippy/src/docs/deprecated_semver.txt
new file mode 100644 (file)
index 0000000..c9574a9
--- /dev/null
@@ -0,0 +1,13 @@
+### What it does
+Checks for `#[deprecated]` annotations with a `since`
+field that is not a valid semantic version.
+
+### Why is this bad?
+For checking the version of the deprecation, it must be
+a valid semver. Failing that, the contained information is useless.
+
+### Example
+```
+#[deprecated(since = "forever")]
+fn something_else() { /* ... */ }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/deref_addrof.txt b/src/tools/clippy/src/docs/deref_addrof.txt
new file mode 100644 (file)
index 0000000..fa711b9
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `*&` and `*&mut` in expressions.
+
+### Why is this bad?
+Immediately dereferencing a reference is no-op and
+makes the code less clear.
+
+### Known problems
+Multiple dereference/addrof pairs are not handled so
+the suggested fix for `x = **&&y` is `x = *&y`, which is still incorrect.
+
+### Example
+```
+let a = f(*&mut b);
+let c = *&d;
+```
+
+Use instead:
+```
+let a = f(b);
+let c = d;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/deref_by_slicing.txt b/src/tools/clippy/src/docs/deref_by_slicing.txt
new file mode 100644 (file)
index 0000000..4dad24a
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for slicing expressions which are equivalent to dereferencing the
+value.
+
+### Why is this bad?
+Some people may prefer to dereference rather than slice.
+
+### Example
+```
+let vec = vec![1, 2, 3];
+let slice = &vec[..];
+```
+Use instead:
+```
+let vec = vec![1, 2, 3];
+let slice = &*vec;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/derivable_impls.txt b/src/tools/clippy/src/docs/derivable_impls.txt
new file mode 100644 (file)
index 0000000..5cee439
--- /dev/null
@@ -0,0 +1,35 @@
+### What it does
+Detects manual `std::default::Default` implementations that are identical to a derived implementation.
+
+### Why is this bad?
+It is less concise.
+
+### Example
+```
+struct Foo {
+    bar: bool
+}
+
+impl Default for Foo {
+    fn default() -> Self {
+        Self {
+            bar: false
+        }
+    }
+}
+```
+
+Use instead:
+```
+#[derive(Default)]
+struct Foo {
+    bar: bool
+}
+```
+
+### Known problems
+Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925)
+in generic types and the user defined `impl` may be more generalized or
+specialized than what derive will produce. This lint can't detect the manual `impl`
+has exactly equal bounds, and therefore this lint is disabled for types with
+generic parameters.
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/derive_hash_xor_eq.txt b/src/tools/clippy/src/docs/derive_hash_xor_eq.txt
new file mode 100644 (file)
index 0000000..fbf623d
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for deriving `Hash` but implementing `PartialEq`
+explicitly or vice versa.
+
+### Why is this bad?
+The implementation of these traits must agree (for
+example for use with `HashMap`) so it’s probably a bad idea to use a
+default-generated `Hash` implementation with an explicitly defined
+`PartialEq`. In particular, the following must hold for any type:
+
+```
+k1 == k2 ⇒ hash(k1) == hash(k2)
+```
+
+### Example
+```
+#[derive(Hash)]
+struct Foo;
+
+impl PartialEq for Foo {
+    ...
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/derive_ord_xor_partial_ord.txt b/src/tools/clippy/src/docs/derive_ord_xor_partial_ord.txt
new file mode 100644 (file)
index 0000000..f2107a5
--- /dev/null
@@ -0,0 +1,44 @@
+### What it does
+Checks for deriving `Ord` but implementing `PartialOrd`
+explicitly or vice versa.
+
+### Why is this bad?
+The implementation of these traits must agree (for
+example for use with `sort`) so it’s probably a bad idea to use a
+default-generated `Ord` implementation with an explicitly defined
+`PartialOrd`. In particular, the following must hold for any type
+implementing `Ord`:
+
+```
+k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
+```
+
+### Example
+```
+#[derive(Ord, PartialEq, Eq)]
+struct Foo;
+
+impl PartialOrd for Foo {
+    ...
+}
+```
+Use instead:
+```
+#[derive(PartialEq, Eq)]
+struct Foo;
+
+impl PartialOrd for Foo {
+    fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
+       Some(self.cmp(other))
+    }
+}
+
+impl Ord for Foo {
+    ...
+}
+```
+or, if you don't need a custom ordering:
+```
+#[derive(Ord, PartialOrd, PartialEq, Eq)]
+struct Foo;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/derive_partial_eq_without_eq.txt b/src/tools/clippy/src/docs/derive_partial_eq_without_eq.txt
new file mode 100644 (file)
index 0000000..932faba
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for types that derive `PartialEq` and could implement `Eq`.
+
+### Why is this bad?
+If a type `T` derives `PartialEq` and all of its members implement `Eq`,
+then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used
+in APIs that require `Eq` types. It also allows structs containing `T` to derive
+`Eq` themselves.
+
+### Example
+```
+#[derive(PartialEq)]
+struct Foo {
+    i_am_eq: i32,
+    i_am_eq_too: Vec<String>,
+}
+```
+Use instead:
+```
+#[derive(PartialEq, Eq)]
+struct Foo {
+    i_am_eq: i32,
+    i_am_eq_too: Vec<String>,
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/disallowed_methods.txt b/src/tools/clippy/src/docs/disallowed_methods.txt
new file mode 100644 (file)
index 0000000..d8ad5b6
--- /dev/null
@@ -0,0 +1,41 @@
+### What it does
+Denies the configured methods and functions in clippy.toml
+
+Note: Even though this lint is warn-by-default, it will only trigger if
+methods are defined in the clippy.toml file.
+
+### Why is this bad?
+Some methods are undesirable in certain contexts, and it's beneficial to
+lint for them as needed.
+
+### Example
+An example clippy.toml configuration:
+```
+disallowed-methods = [
+    # Can use a string as the path of the disallowed method.
+    "std::boxed::Box::new",
+    # Can also use an inline table with a `path` key.
+    { path = "std::time::Instant::now" },
+    # When using an inline table, can add a `reason` for why the method
+    # is disallowed.
+    { path = "std::vec::Vec::leak", reason = "no leaking memory" },
+]
+```
+
+```
+// Example code where clippy issues a warning
+let xs = vec![1, 2, 3, 4];
+xs.leak(); // Vec::leak is disallowed in the config.
+// The diagnostic contains the message "no leaking memory".
+
+let _now = Instant::now(); // Instant::now is disallowed in the config.
+
+let _box = Box::new(3); // Box::new is disallowed in the config.
+```
+
+Use instead:
+```
+// Example code which does not raise clippy warning
+let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config.
+xs.push(123); // Vec::push is _not_ disallowed in the config.
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/disallowed_names.txt b/src/tools/clippy/src/docs/disallowed_names.txt
new file mode 100644 (file)
index 0000000..f4aaee9
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for usage of disallowed names for variables, such
+as `foo`.
+
+### Why is this bad?
+These names are usually placeholder names and should be
+avoided.
+
+### Example
+```
+let foo = 3.14;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/disallowed_script_idents.txt b/src/tools/clippy/src/docs/disallowed_script_idents.txt
new file mode 100644 (file)
index 0000000..2151b7a
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Checks for usage of unicode scripts other than those explicitly allowed
+by the lint config.
+
+This lint doesn't take into account non-text scripts such as `Unknown` and `Linear_A`.
+It also ignores the `Common` script type.
+While configuring, be sure to use official script name [aliases] from
+[the list of supported scripts][supported_scripts].
+
+See also: [`non_ascii_idents`].
+
+[aliases]: http://www.unicode.org/reports/tr24/tr24-31.html#Script_Value_Aliases
+[supported_scripts]: https://www.unicode.org/iso15924/iso15924-codes.html
+
+### Why is this bad?
+It may be not desired to have many different scripts for
+identifiers in the codebase.
+
+Note that if you only want to allow plain English, you might want to use
+built-in [`non_ascii_idents`] lint instead.
+
+[`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents
+
+### Example
+```
+// Assuming that `clippy.toml` contains the following line:
+// allowed-locales = ["Latin", "Cyrillic"]
+let counter = 10; // OK, latin is allowed.
+let счётчик = 10; // OK, cyrillic is allowed.
+let zähler = 10; // OK, it's still latin.
+let カウンタ = 10; // Will spawn the lint.
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/disallowed_types.txt b/src/tools/clippy/src/docs/disallowed_types.txt
new file mode 100644 (file)
index 0000000..2bcbcdd
--- /dev/null
@@ -0,0 +1,33 @@
+### What it does
+Denies the configured types in clippy.toml.
+
+Note: Even though this lint is warn-by-default, it will only trigger if
+types are defined in the clippy.toml file.
+
+### Why is this bad?
+Some types are undesirable in certain contexts.
+
+### Example:
+An example clippy.toml configuration:
+```
+disallowed-types = [
+    # Can use a string as the path of the disallowed type.
+    "std::collections::BTreeMap",
+    # Can also use an inline table with a `path` key.
+    { path = "std::net::TcpListener" },
+    # When using an inline table, can add a `reason` for why the type
+    # is disallowed.
+    { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
+]
+```
+
+```
+use std::collections::BTreeMap;
+// or its use
+let x = std::collections::BTreeMap::new();
+```
+Use instead:
+```
+// A similar type that is allowed by the config
+use std::collections::HashMap;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/diverging_sub_expression.txt b/src/tools/clippy/src/docs/diverging_sub_expression.txt
new file mode 100644 (file)
index 0000000..1943622
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for diverging calls that are not match arms or
+statements.
+
+### Why is this bad?
+It is often confusing to read. In addition, the
+sub-expression evaluation order for Rust is not well documented.
+
+### Known problems
+Someone might want to use `some_bool || panic!()` as a
+shorthand.
+
+### Example
+```
+let a = b() || panic!() || c();
+// `c()` is dead, `panic!()` is only called if `b()` returns `false`
+let x = (a, b, c, panic!());
+// can simply be replaced by `panic!()`
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/doc_link_with_quotes.txt b/src/tools/clippy/src/docs/doc_link_with_quotes.txt
new file mode 100644 (file)
index 0000000..107c8ac
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks)
+outside of code blocks
+### Why is this bad?
+It is likely a typo when defining an intra-doc link
+
+### Example
+```
+/// See also: ['foo']
+fn bar() {}
+```
+Use instead:
+```
+/// See also: [`foo`]
+fn bar() {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/doc_markdown.txt b/src/tools/clippy/src/docs/doc_markdown.txt
new file mode 100644 (file)
index 0000000..94f54c5
--- /dev/null
@@ -0,0 +1,35 @@
+### What it does
+Checks for the presence of `_`, `::` or camel-case words
+outside ticks in documentation.
+
+### Why is this bad?
+*Rustdoc* supports markdown formatting, `_`, `::` and
+camel-case probably indicates some code which should be included between
+ticks. `_` can also be used for emphasis in markdown, this lint tries to
+consider that.
+
+### Known problems
+Lots of bad docs won’t be fixed, what the lint checks
+for is limited, and there are still false positives. HTML elements and their
+content are not linted.
+
+In addition, when writing documentation comments, including `[]` brackets
+inside a link text would trip the parser. Therefore, documenting link with
+`[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec
+would fail.
+
+### Examples
+```
+/// Do something with the foo_bar parameter. See also
+/// that::other::module::foo.
+// ^ `foo_bar` and `that::other::module::foo` should be ticked.
+fn doit(foo_bar: usize) {}
+```
+
+```
+// Link text with `[]` brackets should be written as following:
+/// Consume the array and return the inner
+/// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec].
+/// [SmallVec]: SmallVec
+fn main() {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/double_comparisons.txt b/src/tools/clippy/src/docs/double_comparisons.txt
new file mode 100644 (file)
index 0000000..7dc6818
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for double comparisons that could be simplified to a single expression.
+
+
+### Why is this bad?
+Readability.
+
+### Example
+```
+if x == y || x < y {}
+```
+
+Use instead:
+
+```
+if x <= y {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/double_must_use.txt b/src/tools/clippy/src/docs/double_must_use.txt
new file mode 100644 (file)
index 0000000..0017d10
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for a `#[must_use]` attribute without
+further information on functions and methods that return a type already
+marked as `#[must_use]`.
+
+### Why is this bad?
+The attribute isn't needed. Not using the result
+will already be reported. Alternatively, one can add some text to the
+attribute to improve the lint message.
+
+### Examples
+```
+#[must_use]
+fn double_must_use() -> Result<(), ()> {
+    unimplemented!();
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/double_neg.txt b/src/tools/clippy/src/docs/double_neg.txt
new file mode 100644 (file)
index 0000000..a07f674
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Detects expressions of the form `--x`.
+
+### Why is this bad?
+It can mislead C/C++ programmers to think `x` was
+decremented.
+
+### Example
+```
+let mut x = 3;
+--x;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/double_parens.txt b/src/tools/clippy/src/docs/double_parens.txt
new file mode 100644 (file)
index 0000000..260d7dd
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for unnecessary double parentheses.
+
+### Why is this bad?
+This makes code harder to read and might indicate a
+mistake.
+
+### Example
+```
+fn simple_double_parens() -> i32 {
+    ((0))
+}
+
+foo((0));
+```
+
+Use instead:
+```
+fn simple_no_parens() -> i32 {
+    0
+}
+
+foo(0);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/drop_copy.txt b/src/tools/clippy/src/docs/drop_copy.txt
new file mode 100644 (file)
index 0000000..f917ca8
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for calls to `std::mem::drop` with a value
+that derives the Copy trait
+
+### Why is this bad?
+Calling `std::mem::drop` [does nothing for types that
+implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the
+value will be copied and moved into the function on invocation.
+
+### Example
+```
+let x: i32 = 42; // i32 implements Copy
+std::mem::drop(x) // A copy of x is passed to the function, leaving the
+                  // original unaffected
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/drop_non_drop.txt b/src/tools/clippy/src/docs/drop_non_drop.txt
new file mode 100644 (file)
index 0000000..ee1e3a6
--- /dev/null
@@ -0,0 +1,13 @@
+### What it does
+Checks for calls to `std::mem::drop` with a value that does not implement `Drop`.
+
+### Why is this bad?
+Calling `std::mem::drop` is no different than dropping such a type. A different value may
+have been intended.
+
+### Example
+```
+struct Foo;
+let x = Foo;
+std::mem::drop(x);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/drop_ref.txt b/src/tools/clippy/src/docs/drop_ref.txt
new file mode 100644 (file)
index 0000000..c4f7adf
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for calls to `std::mem::drop` with a reference
+instead of an owned value.
+
+### Why is this bad?
+Calling `drop` on a reference will only drop the
+reference itself, which is a no-op. It will not call the `drop` method (from
+the `Drop` trait implementation) on the underlying referenced value, which
+is likely what was intended.
+
+### Example
+```
+let mut lock_guard = mutex.lock();
+std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex
+// still locked
+operation_that_requires_mutex_to_be_unlocked();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/duplicate_mod.txt b/src/tools/clippy/src/docs/duplicate_mod.txt
new file mode 100644 (file)
index 0000000..709a9ab
--- /dev/null
@@ -0,0 +1,31 @@
+### What it does
+Checks for files that are included as modules multiple times.
+
+### Why is this bad?
+Loading a file as a module more than once causes it to be compiled
+multiple times, taking longer and putting duplicate content into the
+module tree.
+
+### Example
+```
+// lib.rs
+mod a;
+mod b;
+```
+```
+// a.rs
+#[path = "./b.rs"]
+mod b;
+```
+
+Use instead:
+
+```
+// lib.rs
+mod a;
+mod b;
+```
+```
+// a.rs
+use crate::b;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/duplicate_underscore_argument.txt b/src/tools/clippy/src/docs/duplicate_underscore_argument.txt
new file mode 100644 (file)
index 0000000..a8fcd6a
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for function arguments having the similar names
+differing by an underscore.
+
+### Why is this bad?
+It affects code readability.
+
+### Example
+```
+fn foo(a: i32, _a: i32) {}
+```
+
+Use instead:
+```
+fn bar(a: i32, _b: i32) {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/duration_subsec.txt b/src/tools/clippy/src/docs/duration_subsec.txt
new file mode 100644 (file)
index 0000000..e7e0ca8
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for calculation of subsecond microseconds or milliseconds
+from other `Duration` methods.
+
+### Why is this bad?
+It's more concise to call `Duration::subsec_micros()` or
+`Duration::subsec_millis()` than to calculate them.
+
+### Example
+```
+let micros = duration.subsec_nanos() / 1_000;
+let millis = duration.subsec_nanos() / 1_000_000;
+```
+
+Use instead:
+```
+let micros = duration.subsec_micros();
+let millis = duration.subsec_millis();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/else_if_without_else.txt b/src/tools/clippy/src/docs/else_if_without_else.txt
new file mode 100644 (file)
index 0000000..33f5d0f
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for usage of if expressions with an `else if` branch,
+but without a final `else` branch.
+
+### Why is this bad?
+Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10).
+
+### Example
+```
+if x.is_positive() {
+    a();
+} else if x.is_negative() {
+    b();
+}
+```
+
+Use instead:
+
+```
+if x.is_positive() {
+    a();
+} else if x.is_negative() {
+    b();
+} else {
+    // We don't care about zero.
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/empty_drop.txt b/src/tools/clippy/src/docs/empty_drop.txt
new file mode 100644 (file)
index 0000000..d0c0c24
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for empty `Drop` implementations.
+
+### Why is this bad?
+Empty `Drop` implementations have no effect when dropping an instance of the type. They are
+most likely useless. However, an empty `Drop` implementation prevents a type from being
+destructured, which might be the intention behind adding the implementation as a marker.
+
+### Example
+```
+struct S;
+
+impl Drop for S {
+    fn drop(&mut self) {}
+}
+```
+Use instead:
+```
+struct S;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/empty_enum.txt b/src/tools/clippy/src/docs/empty_enum.txt
new file mode 100644 (file)
index 0000000..f7b41c4
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for `enum`s with no variants.
+
+As of this writing, the `never_type` is still a
+nightly-only experimental API. Therefore, this lint is only triggered
+if the `never_type` is enabled.
+
+### Why is this bad?
+If you want to introduce a type which
+can't be instantiated, you should use `!` (the primitive type "never"),
+or a wrapper around it, because `!` has more extensive
+compiler support (type inference, etc...) and wrappers
+around it are the conventional way to define an uninhabited type.
+For further information visit [never type documentation](https://doc.rust-lang.org/std/primitive.never.html)
+
+
+### Example
+```
+enum Test {}
+```
+
+Use instead:
+```
+#![feature(never_type)]
+
+struct Test(!);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/empty_line_after_outer_attr.txt b/src/tools/clippy/src/docs/empty_line_after_outer_attr.txt
new file mode 100644 (file)
index 0000000..c85242b
--- /dev/null
@@ -0,0 +1,35 @@
+### What it does
+Checks for empty lines after outer attributes
+
+### Why is this bad?
+Most likely the attribute was meant to be an inner attribute using a '!'.
+If it was meant to be an outer attribute, then the following item
+should not be separated by empty lines.
+
+### Known problems
+Can cause false positives.
+
+From the clippy side it's difficult to detect empty lines between an attributes and the
+following item because empty lines and comments are not part of the AST. The parsing
+currently works for basic cases but is not perfect.
+
+### Example
+```
+#[allow(dead_code)]
+
+fn not_quite_good_code() { }
+```
+
+Use instead:
+```
+// Good (as inner attribute)
+#![allow(dead_code)]
+
+fn this_is_fine() { }
+
+// or
+
+// Good (as outer attribute)
+#[allow(dead_code)]
+fn this_is_fine_too() { }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/empty_loop.txt b/src/tools/clippy/src/docs/empty_loop.txt
new file mode 100644 (file)
index 0000000..fea49a7
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for empty `loop` expressions.
+
+### Why is this bad?
+These busy loops burn CPU cycles without doing
+anything. It is _almost always_ a better idea to `panic!` than to have
+a busy loop.
+
+If panicking isn't possible, think of the environment and either:
+  - block on something
+  - sleep the thread for some microseconds
+  - yield or pause the thread
+
+For `std` targets, this can be done with
+[`std::thread::sleep`](https://doc.rust-lang.org/std/thread/fn.sleep.html)
+or [`std::thread::yield_now`](https://doc.rust-lang.org/std/thread/fn.yield_now.html).
+
+For `no_std` targets, doing this is more complicated, especially because
+`#[panic_handler]`s can't panic. To stop/pause the thread, you will
+probably need to invoke some target-specific intrinsic. Examples include:
+  - [`x86_64::instructions::hlt`](https://docs.rs/x86_64/0.12.2/x86_64/instructions/fn.hlt.html)
+  - [`cortex_m::asm::wfi`](https://docs.rs/cortex-m/0.6.3/cortex_m/asm/fn.wfi.html)
+
+### Example
+```
+loop {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/empty_structs_with_brackets.txt b/src/tools/clippy/src/docs/empty_structs_with_brackets.txt
new file mode 100644 (file)
index 0000000..ab5e35a
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Finds structs without fields (a so-called "empty struct") that are declared with brackets.
+
+### Why is this bad?
+Empty brackets after a struct declaration can be omitted.
+
+### Example
+```
+struct Cookie {}
+```
+Use instead:
+```
+struct Cookie;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/enum_clike_unportable_variant.txt b/src/tools/clippy/src/docs/enum_clike_unportable_variant.txt
new file mode 100644 (file)
index 0000000..d30a973
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for C-like enumerations that are
+`repr(isize/usize)` and have values that don't fit into an `i32`.
+
+### Why is this bad?
+This will truncate the variant value on 32 bit
+architectures, but works fine on 64 bit.
+
+### Example
+```
+#[repr(usize)]
+enum NonPortable {
+    X = 0x1_0000_0000,
+    Y = 0,
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/enum_glob_use.txt b/src/tools/clippy/src/docs/enum_glob_use.txt
new file mode 100644 (file)
index 0000000..3776822
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for `use Enum::*`.
+
+### Why is this bad?
+It is usually better style to use the prefixed name of
+an enumeration variant, rather than importing variants.
+
+### Known problems
+Old-style enumerations that prefix the variants are
+still around.
+
+### Example
+```
+use std::cmp::Ordering::*;
+
+foo(Less);
+```
+
+Use instead:
+```
+use std::cmp::Ordering;
+
+foo(Ordering::Less)
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/enum_variant_names.txt b/src/tools/clippy/src/docs/enum_variant_names.txt
new file mode 100644 (file)
index 0000000..e726925
--- /dev/null
@@ -0,0 +1,30 @@
+### What it does
+Detects enumeration variants that are prefixed or suffixed
+by the same characters.
+
+### Why is this bad?
+Enumeration variant names should specify their variant,
+not repeat the enumeration name.
+
+### Limitations
+Characters with no casing will be considered when comparing prefixes/suffixes
+This applies to numbers and non-ascii characters without casing
+e.g. `Foo1` and `Foo2` is considered to have different prefixes
+(the prefixes are `Foo1` and `Foo2` respectively), as also `Bar螃`, `Bar蟹`
+
+### Example
+```
+enum Cake {
+    BlackForestCake,
+    HummingbirdCake,
+    BattenbergCake,
+}
+```
+Use instead:
+```
+enum Cake {
+    BlackForest,
+    Hummingbird,
+    Battenberg,
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/eq_op.txt b/src/tools/clippy/src/docs/eq_op.txt
new file mode 100644 (file)
index 0000000..2d75a0e
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for equal operands to comparison, logical and
+bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
+`||`, `&`, `|`, `^`, `-` and `/`).
+
+### Why is this bad?
+This is usually just a typo or a copy and paste error.
+
+### Known problems
+False negatives: We had some false positives regarding
+calls (notably [racer](https://github.com/phildawes/racer) had one instance
+of `x.pop() && x.pop()`), so we removed matching any function or method
+calls. We may introduce a list of known pure functions in the future.
+
+### Example
+```
+if x + 1 == x + 1 {}
+
+// or
+
+assert_eq!(a, a);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/equatable_if_let.txt b/src/tools/clippy/src/docs/equatable_if_let.txt
new file mode 100644 (file)
index 0000000..9997046
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for pattern matchings that can be expressed using equality.
+
+### Why is this bad?
+
+* It reads better and has less cognitive load because equality won't cause binding.
+* It is a [Yoda condition](https://en.wikipedia.org/wiki/Yoda_conditions). Yoda conditions are widely
+criticized for increasing the cognitive load of reading the code.
+* Equality is a simple bool expression and can be merged with `&&` and `||` and
+reuse if blocks
+
+### Example
+```
+if let Some(2) = x {
+    do_thing();
+}
+```
+Use instead:
+```
+if x == Some(2) {
+    do_thing();
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/erasing_op.txt b/src/tools/clippy/src/docs/erasing_op.txt
new file mode 100644 (file)
index 0000000..3d285a6
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for erasing operations, e.g., `x * 0`.
+
+### Why is this bad?
+The whole expression can be replaced by zero.
+This is most likely not the intended outcome and should probably be
+corrected
+
+### Example
+```
+let x = 1;
+0 / x;
+0 * x;
+x & 0;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/err_expect.txt b/src/tools/clippy/src/docs/err_expect.txt
new file mode 100644 (file)
index 0000000..1dc83c5
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for `.err().expect()` calls on the `Result` type.
+
+### Why is this bad?
+`.expect_err()` can be called directly to avoid the extra type conversion from `err()`.
+
+### Example
+```
+let x: Result<u32, &str> = Ok(10);
+x.err().expect("Testing err().expect()");
+```
+Use instead:
+```
+let x: Result<u32, &str> = Ok(10);
+x.expect_err("Testing expect_err");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/excessive_precision.txt b/src/tools/clippy/src/docs/excessive_precision.txt
new file mode 100644 (file)
index 0000000..517879c
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for float literals with a precision greater
+than that supported by the underlying type.
+
+### Why is this bad?
+Rust will truncate the literal silently.
+
+### Example
+```
+let v: f32 = 0.123_456_789_9;
+println!("{}", v); //  0.123_456_789
+```
+
+Use instead:
+```
+let v: f64 = 0.123_456_789_9;
+println!("{}", v); //  0.123_456_789_9
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/exhaustive_enums.txt b/src/tools/clippy/src/docs/exhaustive_enums.txt
new file mode 100644 (file)
index 0000000..d1032a7
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Warns on any exported `enum`s that are not tagged `#[non_exhaustive]`
+
+### Why is this bad?
+Exhaustive enums are typically fine, but a project which does
+not wish to make a stability commitment around exported enums may wish to
+disable them by default.
+
+### Example
+```
+enum Foo {
+    Bar,
+    Baz
+}
+```
+Use instead:
+```
+#[non_exhaustive]
+enum Foo {
+    Bar,
+    Baz
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/exhaustive_structs.txt b/src/tools/clippy/src/docs/exhaustive_structs.txt
new file mode 100644 (file)
index 0000000..fd6e4f5
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`
+
+### Why is this bad?
+Exhaustive structs are typically fine, but a project which does
+not wish to make a stability commitment around exported structs may wish to
+disable them by default.
+
+### Example
+```
+struct Foo {
+    bar: u8,
+    baz: String,
+}
+```
+Use instead:
+```
+#[non_exhaustive]
+struct Foo {
+    bar: u8,
+    baz: String,
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/exit.txt b/src/tools/clippy/src/docs/exit.txt
new file mode 100644 (file)
index 0000000..1e6154d
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+`exit()`  terminates the program and doesn't provide a
+stack trace.
+
+### Why is this bad?
+Ideally a program is terminated by finishing
+the main function.
+
+### Example
+```
+std::process::exit(0)
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/expect_fun_call.txt b/src/tools/clippy/src/docs/expect_fun_call.txt
new file mode 100644 (file)
index 0000000..d82d9aa
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,
+etc., and suggests to use `unwrap_or_else` instead
+
+### Why is this bad?
+The function will always be called.
+
+### Known problems
+If the function has side-effects, not calling it will
+change the semantics of the program, but you shouldn't rely on that anyway.
+
+### Example
+```
+foo.expect(&format!("Err {}: {}", err_code, err_msg));
+
+// or
+
+foo.expect(format!("Err {}: {}", err_code, err_msg).as_str());
+```
+
+Use instead:
+```
+foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/expect_used.txt b/src/tools/clippy/src/docs/expect_used.txt
new file mode 100644 (file)
index 0000000..4a6981e
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s.
+
+### Why is this bad?
+Usually it is better to handle the `None` or `Err` case.
+Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why
+this lint is `Allow` by default.
+
+`result.expect()` will let the thread panic on `Err`
+values. Normally, you want to implement more sophisticated error handling,
+and propagate errors upwards with `?` operator.
+
+### Examples
+```
+option.expect("one");
+result.expect("one");
+```
+
+Use instead:
+```
+option?;
+
+// or
+
+result?;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/expl_impl_clone_on_copy.txt b/src/tools/clippy/src/docs/expl_impl_clone_on_copy.txt
new file mode 100644 (file)
index 0000000..391d93b
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for explicit `Clone` implementations for `Copy`
+types.
+
+### Why is this bad?
+To avoid surprising behavior, these traits should
+agree and the behavior of `Copy` cannot be overridden. In almost all
+situations a `Copy` type should have a `Clone` implementation that does
+nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
+gets you.
+
+### Example
+```
+#[derive(Copy)]
+struct Foo;
+
+impl Clone for Foo {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/explicit_auto_deref.txt b/src/tools/clippy/src/docs/explicit_auto_deref.txt
new file mode 100644 (file)
index 0000000..65b2563
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for dereferencing expressions which would be covered by auto-deref.
+
+### Why is this bad?
+This unnecessarily complicates the code.
+
+### Example
+```
+let x = String::new();
+let y: &str = &*x;
+```
+Use instead:
+```
+let x = String::new();
+let y: &str = &x;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/explicit_counter_loop.txt b/src/tools/clippy/src/docs/explicit_counter_loop.txt
new file mode 100644 (file)
index 0000000..2661a43
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks `for` loops over slices with an explicit counter
+and suggests the use of `.enumerate()`.
+
+### Why is this bad?
+Using `.enumerate()` makes the intent more clear,
+declutters the code and may be faster in some instances.
+
+### Example
+```
+let mut i = 0;
+for item in &v {
+    bar(i, *item);
+    i += 1;
+}
+```
+
+Use instead:
+```
+for (i, item) in v.iter().enumerate() { bar(i, *item); }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/explicit_deref_methods.txt b/src/tools/clippy/src/docs/explicit_deref_methods.txt
new file mode 100644 (file)
index 0000000..e14e981
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for explicit `deref()` or `deref_mut()` method calls.
+
+### Why is this bad?
+Dereferencing by `&*x` or `&mut *x` is clearer and more concise,
+when not part of a method chain.
+
+### Example
+```
+use std::ops::Deref;
+let a: &mut String = &mut String::from("foo");
+let b: &str = a.deref();
+```
+
+Use instead:
+```
+let a: &mut String = &mut String::from("foo");
+let b = &*a;
+```
+
+This lint excludes:
+```
+let _ = d.unwrap().deref();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/explicit_into_iter_loop.txt b/src/tools/clippy/src/docs/explicit_into_iter_loop.txt
new file mode 100644 (file)
index 0000000..3931dfd
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for loops on `y.into_iter()` where `y` will do, and
+suggests the latter.
+
+### Why is this bad?
+Readability.
+
+### Example
+```
+// with `y` a `Vec` or slice:
+for x in y.into_iter() {
+    // ..
+}
+```
+can be rewritten to
+```
+for x in y {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/explicit_iter_loop.txt b/src/tools/clippy/src/docs/explicit_iter_loop.txt
new file mode 100644 (file)
index 0000000..cabe72e
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for loops on `x.iter()` where `&x` will do, and
+suggests the latter.
+
+### Why is this bad?
+Readability.
+
+### Known problems
+False negatives. We currently only warn on some known
+types.
+
+### Example
+```
+// with `y` a `Vec` or slice:
+for x in y.iter() {
+    // ..
+}
+```
+
+Use instead:
+```
+for x in &y {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/explicit_write.txt b/src/tools/clippy/src/docs/explicit_write.txt
new file mode 100644 (file)
index 0000000..eafed5d
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for usage of `write!()` / `writeln()!` which can be
+replaced with `(e)print!()` / `(e)println!()`
+
+### Why is this bad?
+Using `(e)println! is clearer and more concise
+
+### Example
+```
+writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap();
+writeln!(&mut std::io::stdout(), "foo: {:?}", bar).unwrap();
+```
+
+Use instead:
+```
+eprintln!("foo: {:?}", bar);
+println!("foo: {:?}", bar);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/extend_with_drain.txt b/src/tools/clippy/src/docs/extend_with_drain.txt
new file mode 100644 (file)
index 0000000..2f31dcf
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for occurrences where one vector gets extended instead of append
+
+### Why is this bad?
+Using `append` instead of `extend` is more concise and faster
+
+### Example
+```
+let mut a = vec![1, 2, 3];
+let mut b = vec![4, 5, 6];
+
+a.extend(b.drain(..));
+```
+
+Use instead:
+```
+let mut a = vec![1, 2, 3];
+let mut b = vec![4, 5, 6];
+
+a.append(&mut b);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/extra_unused_lifetimes.txt b/src/tools/clippy/src/docs/extra_unused_lifetimes.txt
new file mode 100644 (file)
index 0000000..bc1814a
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for lifetimes in generics that are never used
+anywhere else.
+
+### Why is this bad?
+The additional lifetimes make the code look more
+complicated, while there is nothing out of the ordinary going on. Removing
+them leads to more readable code.
+
+### Example
+```
+// unnecessary lifetimes
+fn unused_lifetime<'a>(x: u8) {
+    // ..
+}
+```
+
+Use instead:
+```
+fn no_lifetime(x: u8) {
+    // ...
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/fallible_impl_from.txt b/src/tools/clippy/src/docs/fallible_impl_from.txt
new file mode 100644 (file)
index 0000000..588a5bb
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
+
+### Why is this bad?
+`TryFrom` should be used if there's a possibility of failure.
+
+### Example
+```
+struct Foo(i32);
+
+impl From<String> for Foo {
+    fn from(s: String) -> Self {
+        Foo(s.parse().unwrap())
+    }
+}
+```
+
+Use instead:
+```
+struct Foo(i32);
+
+impl TryFrom<String> for Foo {
+    type Error = ();
+    fn try_from(s: String) -> Result<Self, Self::Error> {
+        if let Ok(parsed) = s.parse() {
+            Ok(Foo(parsed))
+        } else {
+            Err(())
+        }
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/field_reassign_with_default.txt b/src/tools/clippy/src/docs/field_reassign_with_default.txt
new file mode 100644 (file)
index 0000000..e58b723
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for immediate reassignment of fields initialized
+with Default::default().
+
+### Why is this bad?
+It's more idiomatic to use the [functional update syntax](https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax).
+
+### Known problems
+Assignments to patterns that are of tuple type are not linted.
+
+### Example
+```
+let mut a: A = Default::default();
+a.i = 42;
+```
+
+Use instead:
+```
+let a = A {
+    i: 42,
+    .. Default::default()
+};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/filetype_is_file.txt b/src/tools/clippy/src/docs/filetype_is_file.txt
new file mode 100644 (file)
index 0000000..ad14bd6
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for `FileType::is_file()`.
+
+### Why is this bad?
+When people testing a file type with `FileType::is_file`
+they are testing whether a path is something they can get bytes from. But
+`is_file` doesn't cover special file types in unix-like systems, and doesn't cover
+symlink in windows. Using `!FileType::is_dir()` is a better way to that intention.
+
+### Example
+```
+let metadata = std::fs::metadata("foo.txt")?;
+let filetype = metadata.file_type();
+
+if filetype.is_file() {
+    // read file
+}
+```
+
+should be written as:
+
+```
+let metadata = std::fs::metadata("foo.txt")?;
+let filetype = metadata.file_type();
+
+if !filetype.is_dir() {
+    // read file
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/filter_map_identity.txt b/src/tools/clippy/src/docs/filter_map_identity.txt
new file mode 100644 (file)
index 0000000..83b666f
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for usage of `filter_map(|x| x)`.
+
+### Why is this bad?
+Readability, this can be written more concisely by using `flatten`.
+
+### Example
+```
+iter.filter_map(|x| x);
+```
+Use instead:
+```
+iter.flatten();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/filter_map_next.txt b/src/tools/clippy/src/docs/filter_map_next.txt
new file mode 100644 (file)
index 0000000..b38620b
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `_.filter_map(_).next()`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.find_map(_)`.
+
+### Example
+```
+ (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();
+```
+Can be written as
+
+```
+ (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/filter_next.txt b/src/tools/clippy/src/docs/filter_next.txt
new file mode 100644 (file)
index 0000000..898a741
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `_.filter(_).next()`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.find(_)`.
+
+### Example
+```
+vec.iter().filter(|x| **x == 0).next();
+```
+
+Use instead:
+```
+vec.iter().find(|x| **x == 0);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/flat_map_identity.txt b/src/tools/clippy/src/docs/flat_map_identity.txt
new file mode 100644 (file)
index 0000000..a5ee79b
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for usage of `flat_map(|x| x)`.
+
+### Why is this bad?
+Readability, this can be written more concisely by using `flatten`.
+
+### Example
+```
+iter.flat_map(|x| x);
+```
+Can be written as
+```
+iter.flatten();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/flat_map_option.txt b/src/tools/clippy/src/docs/flat_map_option.txt
new file mode 100644 (file)
index 0000000..d50b915
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for usages of `Iterator::flat_map()` where `filter_map()` could be
+used instead.
+
+### Why is this bad?
+When applicable, `filter_map()` is more clear since it shows that
+`Option` is used to produce 0 or 1 items.
+
+### Example
+```
+let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect();
+```
+Use instead:
+```
+let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/float_arithmetic.txt b/src/tools/clippy/src/docs/float_arithmetic.txt
new file mode 100644 (file)
index 0000000..1f9bce5
--- /dev/null
@@ -0,0 +1,11 @@
+### What it does
+Checks for float arithmetic.
+
+### Why is this bad?
+For some embedded systems or kernel development, it
+can be useful to rule out floating-point numbers.
+
+### Example
+```
+a + 1.0;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/float_cmp.txt b/src/tools/clippy/src/docs/float_cmp.txt
new file mode 100644 (file)
index 0000000..c19907c
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+Checks for (in-)equality comparisons on floating-point
+values (apart from zero), except in functions called `*eq*` (which probably
+implement equality for a type involving floats).
+
+### Why is this bad?
+Floating point calculations are usually imprecise, so
+asking if two values are *exactly* equal is asking for trouble. For a good
+guide on what to do, see [the floating point
+guide](http://www.floating-point-gui.de/errors/comparison).
+
+### Example
+```
+let x = 1.2331f64;
+let y = 1.2332f64;
+
+if y == 1.23f64 { }
+if y != x {} // where both are floats
+```
+
+Use instead:
+```
+let error_margin = f64::EPSILON; // Use an epsilon for comparison
+// Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
+// let error_margin = std::f64::EPSILON;
+if (y - 1.23f64).abs() < error_margin { }
+if (y - x).abs() > error_margin { }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/float_cmp_const.txt b/src/tools/clippy/src/docs/float_cmp_const.txt
new file mode 100644 (file)
index 0000000..9208fea
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for (in-)equality comparisons on floating-point
+value and constant, except in functions called `*eq*` (which probably
+implement equality for a type involving floats).
+
+### Why is this bad?
+Floating point calculations are usually imprecise, so
+asking if two values are *exactly* equal is asking for trouble. For a good
+guide on what to do, see [the floating point
+guide](http://www.floating-point-gui.de/errors/comparison).
+
+### Example
+```
+let x: f64 = 1.0;
+const ONE: f64 = 1.00;
+
+if x == ONE { } // where both are floats
+```
+
+Use instead:
+```
+let error_margin = f64::EPSILON; // Use an epsilon for comparison
+// Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
+// let error_margin = std::f64::EPSILON;
+if (x - ONE).abs() < error_margin { }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/float_equality_without_abs.txt b/src/tools/clippy/src/docs/float_equality_without_abs.txt
new file mode 100644 (file)
index 0000000..556b574
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for statements of the form `(a - b) < f32::EPSILON` or
+`(a - b) < f64::EPSILON`. Notes the missing `.abs()`.
+
+### Why is this bad?
+The code without `.abs()` is more likely to have a bug.
+
+### Known problems
+If the user can ensure that b is larger than a, the `.abs()` is
+technically unnecessary. However, it will make the code more robust and doesn't have any
+large performance implications. If the abs call was deliberately left out for performance
+reasons, it is probably better to state this explicitly in the code, which then can be done
+with an allow.
+
+### Example
+```
+pub fn is_roughly_equal(a: f32, b: f32) -> bool {
+    (a - b) < f32::EPSILON
+}
+```
+Use instead:
+```
+pub fn is_roughly_equal(a: f32, b: f32) -> bool {
+    (a - b).abs() < f32::EPSILON
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/fn_address_comparisons.txt b/src/tools/clippy/src/docs/fn_address_comparisons.txt
new file mode 100644 (file)
index 0000000..7d2b7b6
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for comparisons with an address of a function item.
+
+### Why is this bad?
+Function item address is not guaranteed to be unique and could vary
+between different code generation units. Furthermore different function items could have
+the same address after being merged together.
+
+### Example
+```
+type F = fn();
+fn a() {}
+let f: F = a;
+if f == a {
+    // ...
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/fn_params_excessive_bools.txt b/src/tools/clippy/src/docs/fn_params_excessive_bools.txt
new file mode 100644 (file)
index 0000000..2eae056
--- /dev/null
@@ -0,0 +1,31 @@
+### What it does
+Checks for excessive use of
+bools in function definitions.
+
+### Why is this bad?
+Calls to such functions
+are confusing and error prone, because it's
+hard to remember argument order and you have
+no type system support to back you up. Using
+two-variant enums instead of bools often makes
+API easier to use.
+
+### Example
+```
+fn f(is_round: bool, is_hot: bool) { ... }
+```
+
+Use instead:
+```
+enum Shape {
+    Round,
+    Spiky,
+}
+
+enum Temperature {
+    Hot,
+    IceCold,
+}
+
+fn f(shape: Shape, temperature: Temperature) { ... }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/fn_to_numeric_cast.txt b/src/tools/clippy/src/docs/fn_to_numeric_cast.txt
new file mode 100644 (file)
index 0000000..1f587f6
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for casts of function pointers to something other than usize
+
+### Why is this bad?
+Casting a function pointer to anything other than usize/isize is not portable across
+architectures, because you end up losing bits if the target type is too small or end up with a
+bunch of extra bits that waste space and add more instructions to the final binary than
+strictly necessary for the problem
+
+Casting to isize also doesn't make sense since there are no signed addresses.
+
+### Example
+```
+fn fun() -> i32 { 1 }
+let _ = fun as i64;
+```
+
+Use instead:
+```
+let _ = fun as usize;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/fn_to_numeric_cast_any.txt b/src/tools/clippy/src/docs/fn_to_numeric_cast_any.txt
new file mode 100644 (file)
index 0000000..ee3c33d
--- /dev/null
@@ -0,0 +1,35 @@
+### What it does
+Checks for casts of a function pointer to any integer type.
+
+### Why is this bad?
+Casting a function pointer to an integer can have surprising results and can occur
+accidentally if parentheses are omitted from a function call. If you aren't doing anything
+low-level with function pointers then you can opt-out of casting functions to integers in
+order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
+pointer casts in your code.
+
+### Example
+```
+// fn1 is cast as `usize`
+fn fn1() -> u16 {
+    1
+};
+let _ = fn1 as usize;
+```
+
+Use instead:
+```
+// maybe you intended to call the function?
+fn fn2() -> u16 {
+    1
+};
+let _ = fn2() as usize;
+
+// or
+
+// maybe you intended to cast it to a function type?
+fn fn3() -> u16 {
+    1
+}
+let _ = fn3 as fn() -> u16;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/fn_to_numeric_cast_with_truncation.txt b/src/tools/clippy/src/docs/fn_to_numeric_cast_with_truncation.txt
new file mode 100644 (file)
index 0000000..69f12fa
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for casts of a function pointer to a numeric type not wide enough to
+store address.
+
+### Why is this bad?
+Such a cast discards some bits of the function's address. If this is intended, it would be more
+clearly expressed by casting to usize first, then casting the usize to the intended type (with
+a comment) to perform the truncation.
+
+### Example
+```
+fn fn1() -> i16 {
+    1
+};
+let _ = fn1 as i32;
+```
+
+Use instead:
+```
+// Cast to usize first, then comment with the reason for the truncation
+fn fn1() -> i16 {
+    1
+};
+let fn_ptr = fn1 as usize;
+let fn_ptr_truncated = fn_ptr as i32;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/for_kv_map.txt b/src/tools/clippy/src/docs/for_kv_map.txt
new file mode 100644 (file)
index 0000000..a9a2ffe
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for iterating a map (`HashMap` or `BTreeMap`) and
+ignoring either the keys or values.
+
+### Why is this bad?
+Readability. There are `keys` and `values` methods that
+can be used to express that don't need the values or keys.
+
+### Example
+```
+for (k, _) in &map {
+    ..
+}
+```
+
+could be replaced by
+
+```
+for k in map.keys() {
+    ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/for_loops_over_fallibles.txt b/src/tools/clippy/src/docs/for_loops_over_fallibles.txt
new file mode 100644 (file)
index 0000000..c5a7508
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Checks for `for` loops over `Option` or `Result` values.
+
+### Why is this bad?
+Readability. This is more clearly expressed as an `if
+let`.
+
+### Example
+```
+for x in opt {
+    // ..
+}
+
+for x in &res {
+    // ..
+}
+
+for x in res.iter() {
+    // ..
+}
+```
+
+Use instead:
+```
+if let Some(x) = opt {
+    // ..
+}
+
+if let Ok(x) = res {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/forget_copy.txt b/src/tools/clippy/src/docs/forget_copy.txt
new file mode 100644 (file)
index 0000000..1d10091
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for calls to `std::mem::forget` with a value that
+derives the Copy trait
+
+### Why is this bad?
+Calling `std::mem::forget` [does nothing for types that
+implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the
+value will be copied and moved into the function on invocation.
+
+An alternative, but also valid, explanation is that Copy types do not
+implement
+the Drop trait, which means they have no destructors. Without a destructor,
+there
+is nothing for `std::mem::forget` to ignore.
+
+### Example
+```
+let x: i32 = 42; // i32 implements Copy
+std::mem::forget(x) // A copy of x is passed to the function, leaving the
+                    // original unaffected
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/forget_non_drop.txt b/src/tools/clippy/src/docs/forget_non_drop.txt
new file mode 100644 (file)
index 0000000..3307d65
--- /dev/null
@@ -0,0 +1,13 @@
+### What it does
+Checks for calls to `std::mem::forget` with a value that does not implement `Drop`.
+
+### Why is this bad?
+Calling `std::mem::forget` is no different than dropping such a type. A different value may
+have been intended.
+
+### Example
+```
+struct Foo;
+let x = Foo;
+std::mem::forget(x);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/forget_ref.txt b/src/tools/clippy/src/docs/forget_ref.txt
new file mode 100644 (file)
index 0000000..874fb87
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for calls to `std::mem::forget` with a reference
+instead of an owned value.
+
+### Why is this bad?
+Calling `forget` on a reference will only forget the
+reference itself, which is a no-op. It will not forget the underlying
+referenced
+value, which is likely what was intended.
+
+### Example
+```
+let x = Box::new(1);
+std::mem::forget(&x) // Should have been forget(x), x will still be dropped
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/format_in_format_args.txt b/src/tools/clippy/src/docs/format_in_format_args.txt
new file mode 100644 (file)
index 0000000..ac49847
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Detects `format!` within the arguments of another macro that does
+formatting such as `format!` itself, `write!` or `println!`. Suggests
+inlining the `format!` call.
+
+### Why is this bad?
+The recommended code is both shorter and avoids a temporary allocation.
+
+### Example
+```
+println!("error: {}", format!("something failed at {}", Location::caller()));
+```
+Use instead:
+```
+println!("error: something failed at {}", Location::caller());
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/format_push_string.txt b/src/tools/clippy/src/docs/format_push_string.txt
new file mode 100644 (file)
index 0000000..ca409eb
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Detects cases where the result of a `format!` call is
+appended to an existing `String`.
+
+### Why is this bad?
+Introduces an extra, avoidable heap allocation.
+
+### Known problems
+`format!` returns a `String` but `write!` returns a `Result`.
+Thus you are forced to ignore the `Err` variant to achieve the same API.
+
+While using `write!` in the suggested way should never fail, this isn't necessarily clear to the programmer.
+
+### Example
+```
+let mut s = String::new();
+s += &format!("0x{:X}", 1024);
+s.push_str(&format!("0x{:X}", 1024));
+```
+Use instead:
+```
+use std::fmt::Write as _; // import without risk of name clashing
+
+let mut s = String::new();
+let _ = write!(s, "0x{:X}", 1024);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/from_iter_instead_of_collect.txt b/src/tools/clippy/src/docs/from_iter_instead_of_collect.txt
new file mode 100644 (file)
index 0000000..f3fd275
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for `from_iter()` function calls on types that implement the `FromIterator`
+trait.
+
+### Why is this bad?
+It is recommended style to use collect. See
+[FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
+
+### Example
+```
+let five_fives = std::iter::repeat(5).take(5);
+
+let v = Vec::from_iter(five_fives);
+
+assert_eq!(v, vec![5, 5, 5, 5, 5]);
+```
+Use instead:
+```
+let five_fives = std::iter::repeat(5).take(5);
+
+let v: Vec<i32> = five_fives.collect();
+
+assert_eq!(v, vec![5, 5, 5, 5, 5]);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/from_over_into.txt b/src/tools/clippy/src/docs/from_over_into.txt
new file mode 100644 (file)
index 0000000..0770bcc
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead.
+
+### Why is this bad?
+According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true.
+
+### Example
+```
+struct StringWrapper(String);
+
+impl Into<StringWrapper> for String {
+    fn into(self) -> StringWrapper {
+        StringWrapper(self)
+    }
+}
+```
+Use instead:
+```
+struct StringWrapper(String);
+
+impl From<String> for StringWrapper {
+    fn from(s: String) -> StringWrapper {
+        StringWrapper(s)
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/from_str_radix_10.txt b/src/tools/clippy/src/docs/from_str_radix_10.txt
new file mode 100644 (file)
index 0000000..f6f319d
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+
+Checks for function invocations of the form `primitive::from_str_radix(s, 10)`
+
+### Why is this bad?
+
+This specific common use case can be rewritten as `s.parse::<primitive>()`
+(and in most cases, the turbofish can be removed), which reduces code length
+and complexity.
+
+### Known problems
+
+This lint may suggest using (&<expression>).parse() instead of <expression>.parse() directly
+in some cases, which is correct but adds unnecessary complexity to the code.
+
+### Example
+```
+let input: &str = get_input();
+let num = u16::from_str_radix(input, 10)?;
+```
+Use instead:
+```
+let input: &str = get_input();
+let num: u16 = input.parse()?;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/future_not_send.txt b/src/tools/clippy/src/docs/future_not_send.txt
new file mode 100644 (file)
index 0000000..0aa048d
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+This lint requires Future implementations returned from
+functions and methods to implement the `Send` marker trait. It is mostly
+used by library authors (public and internal) that target an audience where
+multithreaded executors are likely to be used for running these Futures.
+
+### Why is this bad?
+A Future implementation captures some state that it
+needs to eventually produce its final value. When targeting a multithreaded
+executor (which is the norm on non-embedded devices) this means that this
+state may need to be transported to other threads, in other words the
+whole Future needs to implement the `Send` marker trait. If it does not,
+then the resulting Future cannot be submitted to a thread pool in the
+end user’s code.
+
+Especially for generic functions it can be confusing to leave the
+discovery of this problem to the end user: the reported error location
+will be far from its cause and can in many cases not even be fixed without
+modifying the library where the offending Future implementation is
+produced.
+
+### Example
+```
+async fn not_send(bytes: std::rc::Rc<[u8]>) {}
+```
+Use instead:
+```
+async fn is_send(bytes: std::sync::Arc<[u8]>) {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/get_first.txt b/src/tools/clippy/src/docs/get_first.txt
new file mode 100644 (file)
index 0000000..c905a73
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for using `x.get(0)` instead of
+`x.first()`.
+
+### Why is this bad?
+Using `x.first()` is easier to read and has the same
+result.
+
+### Example
+```
+let x = vec![2, 3, 5];
+let first_element = x.get(0);
+```
+
+Use instead:
+```
+let x = vec![2, 3, 5];
+let first_element = x.first();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/get_last_with_len.txt b/src/tools/clippy/src/docs/get_last_with_len.txt
new file mode 100644 (file)
index 0000000..31c7f26
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for using `x.get(x.len() - 1)` instead of
+`x.last()`.
+
+### Why is this bad?
+Using `x.last()` is easier to read and has the same
+result.
+
+Note that using `x[x.len() - 1]` is semantically different from
+`x.last()`.  Indexing into the array will panic on out-of-bounds
+accesses, while `x.get()` and `x.last()` will return `None`.
+
+There is another lint (get_unwrap) that covers the case of using
+`x.get(index).unwrap()` instead of `x[index]`.
+
+### Example
+```
+let x = vec![2, 3, 5];
+let last_element = x.get(x.len() - 1);
+```
+
+Use instead:
+```
+let x = vec![2, 3, 5];
+let last_element = x.last();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/get_unwrap.txt b/src/tools/clippy/src/docs/get_unwrap.txt
new file mode 100644 (file)
index 0000000..8defc22
--- /dev/null
@@ -0,0 +1,30 @@
+### What it does
+Checks for use of `.get().unwrap()` (or
+`.get_mut().unwrap`) on a standard library type which implements `Index`
+
+### Why is this bad?
+Using the Index trait (`[]`) is more clear and more
+concise.
+
+### Known problems
+Not a replacement for error handling: Using either
+`.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic`
+if the value being accessed is `None`. If the use of `.get().unwrap()` is a
+temporary placeholder for dealing with the `Option` type, then this does
+not mitigate the need for error handling. If there is a chance that `.get()`
+will be `None` in your program, then it is advisable that the `None` case
+is handled in a future refactor instead of using `.unwrap()` or the Index
+trait.
+
+### Example
+```
+let mut some_vec = vec![0, 1, 2, 3];
+let last = some_vec.get(3).unwrap();
+*some_vec.get_mut(0).unwrap() = 1;
+```
+The correct use would be:
+```
+let mut some_vec = vec![0, 1, 2, 3];
+let last = some_vec[3];
+some_vec[0] = 1;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/identity_op.txt b/src/tools/clippy/src/docs/identity_op.txt
new file mode 100644 (file)
index 0000000..a8e40bb
--- /dev/null
@@ -0,0 +1,11 @@
+### What it does
+Checks for identity operations, e.g., `x + 0`.
+
+### Why is this bad?
+This code can be removed without changing the
+meaning. So it just obscures what's going on. Delete it mercilessly.
+
+### Example
+```
+x / 1 + 0 * 1 - 0 | 0;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/if_let_mutex.txt b/src/tools/clippy/src/docs/if_let_mutex.txt
new file mode 100644 (file)
index 0000000..4d873ad
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for `Mutex::lock` calls in `if let` expression
+with lock calls in any of the else blocks.
+
+### Why is this bad?
+The Mutex lock remains held for the whole
+`if let ... else` block and deadlocks.
+
+### Example
+```
+if let Ok(thing) = mutex.lock() {
+    do_thing();
+} else {
+    mutex.lock();
+}
+```
+Should be written
+```
+let locked = mutex.lock();
+if let Ok(thing) = locked {
+    do_thing(thing);
+} else {
+    use_locked(locked);
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/if_not_else.txt b/src/tools/clippy/src/docs/if_not_else.txt
new file mode 100644 (file)
index 0000000..0e5ac4c
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for usage of `!` or `!=` in an if condition with an
+else branch.
+
+### Why is this bad?
+Negations reduce the readability of statements.
+
+### Example
+```
+if !v.is_empty() {
+    a()
+} else {
+    b()
+}
+```
+
+Could be written:
+
+```
+if v.is_empty() {
+    b()
+} else {
+    a()
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/if_same_then_else.txt b/src/tools/clippy/src/docs/if_same_then_else.txt
new file mode 100644 (file)
index 0000000..7512701
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for `if/else` with the same body as the *then* part
+and the *else* part.
+
+### Why is this bad?
+This is probably a copy & paste error.
+
+### Example
+```
+let foo = if … {
+    42
+} else {
+    42
+};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/if_then_some_else_none.txt b/src/tools/clippy/src/docs/if_then_some_else_none.txt
new file mode 100644 (file)
index 0000000..13744f9
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for if-else that could be written using either `bool::then` or `bool::then_some`.
+
+### Why is this bad?
+Looks a little redundant. Using `bool::then` is more concise and incurs no loss of clarity.
+For simple calculations and known values, use `bool::then_some`, which is eagerly evaluated
+in comparison to `bool::then`.
+
+### Example
+```
+let a = if v.is_empty() {
+    println!("true!");
+    Some(42)
+} else {
+    None
+};
+```
+
+Could be written:
+
+```
+let a = v.is_empty().then(|| {
+    println!("true!");
+    42
+});
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ifs_same_cond.txt b/src/tools/clippy/src/docs/ifs_same_cond.txt
new file mode 100644 (file)
index 0000000..024ba5d
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for consecutive `if`s with the same condition.
+
+### Why is this bad?
+This is probably a copy & paste error.
+
+### Example
+```
+if a == b {
+    …
+} else if a == b {
+    …
+}
+```
+
+Note that this lint ignores all conditions with a function call as it could
+have side effects:
+
+```
+if foo() {
+    …
+} else if foo() { // not linted
+    …
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/implicit_clone.txt b/src/tools/clippy/src/docs/implicit_clone.txt
new file mode 100644 (file)
index 0000000..f5aa112
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer.
+
+### Why is this bad?
+These methods do the same thing as `_.clone()` but may be confusing as
+to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned.
+
+### Example
+```
+let a = vec![1, 2, 3];
+let b = a.to_vec();
+let c = a.to_owned();
+```
+Use instead:
+```
+let a = vec![1, 2, 3];
+let b = a.clone();
+let c = a.clone();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/implicit_hasher.txt b/src/tools/clippy/src/docs/implicit_hasher.txt
new file mode 100644 (file)
index 0000000..0c1f766
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for public `impl` or `fn` missing generalization
+over different hashers and implicitly defaulting to the default hashing
+algorithm (`SipHash`).
+
+### Why is this bad?
+`HashMap` or `HashSet` with custom hashers cannot be
+used with them.
+
+### Known problems
+Suggestions for replacing constructors can contain
+false-positives. Also applying suggestions can require modification of other
+pieces of code, possibly including external crates.
+
+### Example
+```
+impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { }
+
+pub fn foo(map: &mut HashMap<i32, i32>) { }
+```
+could be rewritten as
+```
+impl<K: Hash + Eq, V, S: BuildHasher> Serialize for HashMap<K, V, S> { }
+
+pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/implicit_return.txt b/src/tools/clippy/src/docs/implicit_return.txt
new file mode 100644 (file)
index 0000000..ee65a63
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for missing return statements at the end of a block.
+
+### Why is this bad?
+Actually omitting the return keyword is idiomatic Rust code. Programmers
+coming from other languages might prefer the expressiveness of `return`. It's possible to miss
+the last returning statement because the only difference is a missing `;`. Especially in bigger
+code with multiple return paths having a `return` keyword makes it easier to find the
+corresponding statements.
+
+### Example
+```
+fn foo(x: usize) -> usize {
+    x
+}
+```
+add return
+```
+fn foo(x: usize) -> usize {
+    return x;
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/implicit_saturating_sub.txt b/src/tools/clippy/src/docs/implicit_saturating_sub.txt
new file mode 100644 (file)
index 0000000..03b4790
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for implicit saturating subtraction.
+
+### Why is this bad?
+Simplicity and readability. Instead we can easily use an builtin function.
+
+### Example
+```
+let mut i: u32 = end - start;
+
+if i != 0 {
+    i -= 1;
+}
+```
+
+Use instead:
+```
+let mut i: u32 = end - start;
+
+i = i.saturating_sub(1);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/imprecise_flops.txt b/src/tools/clippy/src/docs/imprecise_flops.txt
new file mode 100644 (file)
index 0000000..e84d81c
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Looks for floating-point expressions that
+can be expressed using built-in methods to improve accuracy
+at the cost of performance.
+
+### Why is this bad?
+Negatively impacts accuracy.
+
+### Example
+```
+let a = 3f32;
+let _ = a.powf(1.0 / 3.0);
+let _ = (1.0 + a).ln();
+let _ = a.exp() - 1.0;
+```
+
+Use instead:
+```
+let a = 3f32;
+let _ = a.cbrt();
+let _ = a.ln_1p();
+let _ = a.exp_m1();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inconsistent_digit_grouping.txt b/src/tools/clippy/src/docs/inconsistent_digit_grouping.txt
new file mode 100644 (file)
index 0000000..aa0b072
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Warns if an integral or floating-point constant is
+grouped inconsistently with underscores.
+
+### Why is this bad?
+Readers may incorrectly interpret inconsistently
+grouped digits.
+
+### Example
+```
+618_64_9189_73_511
+```
+
+Use instead:
+```
+61_864_918_973_511
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inconsistent_struct_constructor.txt b/src/tools/clippy/src/docs/inconsistent_struct_constructor.txt
new file mode 100644 (file)
index 0000000..eb68210
--- /dev/null
@@ -0,0 +1,40 @@
+### What it does
+Checks for struct constructors where all fields are shorthand and
+the order of the field init shorthand in the constructor is inconsistent
+with the order in the struct definition.
+
+### Why is this bad?
+Since the order of fields in a constructor doesn't affect the
+resulted instance as the below example indicates,
+
+```
+#[derive(Debug, PartialEq, Eq)]
+struct Foo {
+    x: i32,
+    y: i32,
+}
+let x = 1;
+let y = 2;
+
+// This assertion never fails:
+assert_eq!(Foo { x, y }, Foo { y, x });
+```
+
+inconsistent order can be confusing and decreases readability and consistency.
+
+### Example
+```
+struct Foo {
+    x: i32,
+    y: i32,
+}
+let x = 1;
+let y = 2;
+
+Foo { y, x };
+```
+
+Use instead:
+```
+Foo { x, y };
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/index_refutable_slice.txt b/src/tools/clippy/src/docs/index_refutable_slice.txt
new file mode 100644 (file)
index 0000000..8a7d527
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+The lint checks for slice bindings in patterns that are only used to
+access individual slice values.
+
+### Why is this bad?
+Accessing slice values using indices can lead to panics. Using refutable
+patterns can avoid these. Binding to individual values also improves the
+readability as they can be named.
+
+### Limitations
+This lint currently only checks for immutable access inside `if let`
+patterns.
+
+### Example
+```
+let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+
+if let Some(slice) = slice {
+    println!("{}", slice[0]);
+}
+```
+Use instead:
+```
+let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+
+if let Some(&[first, ..]) = slice {
+    println!("{}", first);
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/indexing_slicing.txt b/src/tools/clippy/src/docs/indexing_slicing.txt
new file mode 100644 (file)
index 0000000..76ca6ed
--- /dev/null
@@ -0,0 +1,33 @@
+### What it does
+Checks for usage of indexing or slicing. Arrays are special cases, this lint
+does report on arrays if we can tell that slicing operations are in bounds and does not
+lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint.
+
+### Why is this bad?
+Indexing and slicing can panic at runtime and there are
+safe alternatives.
+
+### Example
+```
+// Vector
+let x = vec![0; 5];
+
+x[2];
+&x[2..100];
+
+// Array
+let y = [0, 1, 2, 3];
+
+&y[10..100];
+&y[10..];
+```
+
+Use instead:
+```
+
+x.get(2);
+x.get(2..100);
+
+y.get(10);
+y.get(10..100);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ineffective_bit_mask.txt b/src/tools/clippy/src/docs/ineffective_bit_mask.txt
new file mode 100644 (file)
index 0000000..f6e7ef5
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for bit masks in comparisons which can be removed
+without changing the outcome. The basic structure can be seen in the
+following table:
+
+|Comparison| Bit Op   |Example     |equals |
+|----------|----------|------------|-------|
+|`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`|
+|`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`|
+
+### Why is this bad?
+Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
+but still a bit misleading, because the bit mask is ineffective.
+
+### Known problems
+False negatives: This lint will only match instances
+where we have figured out the math (which is for a power-of-two compared
+value). This means things like `x | 1 >= 7` (which would be better written
+as `x >= 6`) will not be reported (but bit masks like this are fairly
+uncommon).
+
+### Example
+```
+if (x | 1 > 3) {  }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inefficient_to_string.txt b/src/tools/clippy/src/docs/inefficient_to_string.txt
new file mode 100644 (file)
index 0000000..f7061d1
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for usage of `.to_string()` on an `&&T` where
+`T` implements `ToString` directly (like `&&str` or `&&String`).
+
+### Why is this bad?
+This bypasses the specialized implementation of
+`ToString` and instead goes through the more expensive string formatting
+facilities.
+
+### Example
+```
+// Generic implementation for `T: Display` is used (slow)
+["foo", "bar"].iter().map(|s| s.to_string());
+
+// OK, the specialized impl is used
+["foo", "bar"].iter().map(|&s| s.to_string());
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/infallible_destructuring_match.txt b/src/tools/clippy/src/docs/infallible_destructuring_match.txt
new file mode 100644 (file)
index 0000000..4b5d3c4
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for matches being used to destructure a single-variant enum
+or tuple struct where a `let` will suffice.
+
+### Why is this bad?
+Just readability – `let` doesn't nest, whereas a `match` does.
+
+### Example
+```
+enum Wrapper {
+    Data(i32),
+}
+
+let wrapper = Wrapper::Data(42);
+
+let data = match wrapper {
+    Wrapper::Data(i) => i,
+};
+```
+
+The correct use would be:
+```
+enum Wrapper {
+    Data(i32),
+}
+
+let wrapper = Wrapper::Data(42);
+let Wrapper::Data(data) = wrapper;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/infinite_iter.txt b/src/tools/clippy/src/docs/infinite_iter.txt
new file mode 100644 (file)
index 0000000..8a22fab
--- /dev/null
@@ -0,0 +1,13 @@
+### What it does
+Checks for iteration that is guaranteed to be infinite.
+
+### Why is this bad?
+While there may be places where this is acceptable
+(e.g., in event streams), in most cases this is simply an error.
+
+### Example
+```
+use std::iter;
+
+iter::repeat(1_u8).collect::<Vec<_>>();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inherent_to_string.txt b/src/tools/clippy/src/docs/inherent_to_string.txt
new file mode 100644 (file)
index 0000000..b18e600
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`.
+
+### Why is this bad?
+This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred.
+
+### Example
+```
+pub struct A;
+
+impl A {
+    pub fn to_string(&self) -> String {
+        "I am A".to_string()
+    }
+}
+```
+
+Use instead:
+```
+use std::fmt;
+
+pub struct A;
+
+impl fmt::Display for A {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "I am A")
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inherent_to_string_shadow_display.txt b/src/tools/clippy/src/docs/inherent_to_string_shadow_display.txt
new file mode 100644 (file)
index 0000000..a4bd0b6
--- /dev/null
@@ -0,0 +1,37 @@
+### What it does
+Checks for the definition of inherent methods with a signature of `to_string(&self) -> String` and if the type implementing this method also implements the `Display` trait.
+
+### Why is this bad?
+This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`.
+
+### Example
+```
+use std::fmt;
+
+pub struct A;
+
+impl A {
+    pub fn to_string(&self) -> String {
+        "I am A".to_string()
+    }
+}
+
+impl fmt::Display for A {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "I am A, too")
+    }
+}
+```
+
+Use instead:
+```
+use std::fmt;
+
+pub struct A;
+
+impl fmt::Display for A {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "I am A")
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/init_numbered_fields.txt b/src/tools/clippy/src/docs/init_numbered_fields.txt
new file mode 100644 (file)
index 0000000..ba40af6
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for tuple structs initialized with field syntax.
+It will however not lint if a base initializer is present.
+The lint will also ignore code in macros.
+
+### Why is this bad?
+This may be confusing to the uninitiated and adds no
+benefit as opposed to tuple initializers
+
+### Example
+```
+struct TupleStruct(u8, u16);
+
+let _ = TupleStruct {
+    0: 1,
+    1: 23,
+};
+
+// should be written as
+let base = TupleStruct(1, 23);
+
+// This is OK however
+let _ = TupleStruct { 0: 42, ..base };
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inline_always.txt b/src/tools/clippy/src/docs/inline_always.txt
new file mode 100644 (file)
index 0000000..7721da4
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for items annotated with `#[inline(always)]`,
+unless the annotated function is empty or simply panics.
+
+### Why is this bad?
+While there are valid uses of this annotation (and once
+you know when to use it, by all means `allow` this lint), it's a common
+newbie-mistake to pepper one's code with it.
+
+As a rule of thumb, before slapping `#[inline(always)]` on a function,
+measure if that additional function call really affects your runtime profile
+sufficiently to make up for the increase in compile time.
+
+### Known problems
+False positives, big time. This lint is meant to be
+deactivated by everyone doing serious performance work. This means having
+done the measurement.
+
+### Example
+```
+#[inline(always)]
+fn not_quite_hot_code(..) { ... }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inline_asm_x86_att_syntax.txt b/src/tools/clippy/src/docs/inline_asm_x86_att_syntax.txt
new file mode 100644 (file)
index 0000000..8eb49d1
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of AT&T x86 assembly syntax.
+
+### Why is this bad?
+The lint has been enabled to indicate a preference
+for Intel x86 assembly syntax.
+
+### Example
+
+```
+asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
+```
+Use instead:
+```
+asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inline_asm_x86_intel_syntax.txt b/src/tools/clippy/src/docs/inline_asm_x86_intel_syntax.txt
new file mode 100644 (file)
index 0000000..5aa22c8
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of Intel x86 assembly syntax.
+
+### Why is this bad?
+The lint has been enabled to indicate a preference
+for AT&T x86 assembly syntax.
+
+### Example
+
+```
+asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
+```
+Use instead:
+```
+asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inline_fn_without_body.txt b/src/tools/clippy/src/docs/inline_fn_without_body.txt
new file mode 100644 (file)
index 0000000..127c161
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for `#[inline]` on trait methods without bodies
+
+### Why is this bad?
+Only implementations of trait methods may be inlined.
+The inline attribute is ignored for trait methods without bodies.
+
+### Example
+```
+trait Animal {
+    #[inline]
+    fn name(&self) -> &'static str;
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inspect_for_each.txt b/src/tools/clippy/src/docs/inspect_for_each.txt
new file mode 100644 (file)
index 0000000..01a46d6
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for usage of `inspect().for_each()`.
+
+### Why is this bad?
+It is the same as performing the computation
+inside `inspect` at the beginning of the closure in `for_each`.
+
+### Example
+```
+[1,2,3,4,5].iter()
+.inspect(|&x| println!("inspect the number: {}", x))
+.for_each(|&x| {
+    assert!(x >= 0);
+});
+```
+Can be written as
+```
+[1,2,3,4,5].iter()
+.for_each(|&x| {
+    println!("inspect the number: {}", x);
+    assert!(x >= 0);
+});
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/int_plus_one.txt b/src/tools/clippy/src/docs/int_plus_one.txt
new file mode 100644 (file)
index 0000000..1b68f3e
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
+
+### Why is this bad?
+Readability -- better to use `> y` instead of `>= y + 1`.
+
+### Example
+```
+if x >= y + 1 {}
+```
+
+Use instead:
+```
+if x > y {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/integer_arithmetic.txt b/src/tools/clippy/src/docs/integer_arithmetic.txt
new file mode 100644 (file)
index 0000000..ea57a2e
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for integer arithmetic operations which could overflow or panic.
+
+Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable
+of overflowing according to the [Rust
+Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
+or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is
+attempted.
+
+### Why is this bad?
+Integer overflow will trigger a panic in debug builds or will wrap in
+release mode. Division by zero will cause a panic in either mode. In some applications one
+wants explicitly checked, wrapping or saturating arithmetic.
+
+### Example
+```
+a + 1;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/integer_division.txt b/src/tools/clippy/src/docs/integer_division.txt
new file mode 100644 (file)
index 0000000..f6d3349
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for division of integers
+
+### Why is this bad?
+When outside of some very specific algorithms,
+integer division is very often a mistake because it discards the
+remainder.
+
+### Example
+```
+let x = 3 / 2;
+println!("{}", x);
+```
+
+Use instead:
+```
+let x = 3f32 / 2f32;
+println!("{}", x);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/into_iter_on_ref.txt b/src/tools/clippy/src/docs/into_iter_on_ref.txt
new file mode 100644 (file)
index 0000000..acb6bd4
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for `into_iter` calls on references which should be replaced by `iter`
+or `iter_mut`.
+
+### Why is this bad?
+Readability. Calling `into_iter` on a reference will not move out its
+content into the resulting iterator, which is confusing. It is better just call `iter` or
+`iter_mut` directly.
+
+### Example
+```
+(&vec).into_iter();
+```
+
+Use instead:
+```
+(&vec).iter();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/invalid_null_ptr_usage.txt b/src/tools/clippy/src/docs/invalid_null_ptr_usage.txt
new file mode 100644 (file)
index 0000000..6fb3fa3
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+This lint checks for invalid usages of `ptr::null`.
+
+### Why is this bad?
+This causes undefined behavior.
+
+### Example
+```
+// Undefined behavior
+unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
+```
+
+Use instead:
+```
+unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/invalid_regex.txt b/src/tools/clippy/src/docs/invalid_regex.txt
new file mode 100644 (file)
index 0000000..6c9969b
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks [regex](https://crates.io/crates/regex) creation
+(with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct
+regex syntax.
+
+### Why is this bad?
+This will lead to a runtime panic.
+
+### Example
+```
+Regex::new("(")
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/invalid_upcast_comparisons.txt b/src/tools/clippy/src/docs/invalid_upcast_comparisons.txt
new file mode 100644 (file)
index 0000000..77cb033
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for comparisons where the relation is always either
+true or false, but where one side has been upcast so that the comparison is
+necessary. Only integer types are checked.
+
+### Why is this bad?
+An expression like `let x : u8 = ...; (x as u32) > 300`
+will mistakenly imply that it is possible for `x` to be outside the range of
+`u8`.
+
+### Known problems
+https://github.com/rust-lang/rust-clippy/issues/886
+
+### Example
+```
+let x: u8 = 1;
+(x as u32) > 300;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/invalid_utf8_in_unchecked.txt b/src/tools/clippy/src/docs/invalid_utf8_in_unchecked.txt
new file mode 100644 (file)
index 0000000..afb5acb
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for `std::str::from_utf8_unchecked` with an invalid UTF-8 literal
+
+### Why is this bad?
+Creating such a `str` would result in undefined behavior
+
+### Example
+```
+unsafe {
+    std::str::from_utf8_unchecked(b"cl\x82ippy");
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/invisible_characters.txt b/src/tools/clippy/src/docs/invisible_characters.txt
new file mode 100644 (file)
index 0000000..3dda380
--- /dev/null
@@ -0,0 +1,10 @@
+### What it does
+Checks for invisible Unicode characters in the code.
+
+### Why is this bad?
+Having an invisible character in the code makes for all
+sorts of April fools, but otherwise is very much frowned upon.
+
+### Example
+You don't see it, but there may be a zero-width space or soft hyphen
+some­where in this text.
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/is_digit_ascii_radix.txt b/src/tools/clippy/src/docs/is_digit_ascii_radix.txt
new file mode 100644 (file)
index 0000000..9f11cf4
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Finds usages of [`char::is_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit) that
+can be replaced with [`is_ascii_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_digit) or
+[`is_ascii_hexdigit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_hexdigit).
+
+### Why is this bad?
+`is_digit(..)` is slower and requires specifying the radix.
+
+### Example
+```
+let c: char = '6';
+c.is_digit(10);
+c.is_digit(16);
+```
+Use instead:
+```
+let c: char = '6';
+c.is_ascii_digit();
+c.is_ascii_hexdigit();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/items_after_statements.txt b/src/tools/clippy/src/docs/items_after_statements.txt
new file mode 100644 (file)
index 0000000..6fdfff5
--- /dev/null
@@ -0,0 +1,37 @@
+### What it does
+Checks for items declared after some statement in a block.
+
+### Why is this bad?
+Items live for the entire scope they are declared
+in. But statements are processed in order. This might cause confusion as
+it's hard to figure out which item is meant in a statement.
+
+### Example
+```
+fn foo() {
+    println!("cake");
+}
+
+fn main() {
+    foo(); // prints "foo"
+    fn foo() {
+        println!("foo");
+    }
+    foo(); // prints "foo"
+}
+```
+
+Use instead:
+```
+fn foo() {
+    println!("cake");
+}
+
+fn main() {
+    fn foo() {
+        println!("foo");
+    }
+    foo(); // prints "foo"
+    foo(); // prints "foo"
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_cloned_collect.txt b/src/tools/clippy/src/docs/iter_cloned_collect.txt
new file mode 100644 (file)
index 0000000..90dc9eb
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for the use of `.cloned().collect()` on slice to
+create a `Vec`.
+
+### Why is this bad?
+`.to_vec()` is clearer
+
+### Example
+```
+let s = [1, 2, 3, 4, 5];
+let s2: Vec<isize> = s[..].iter().cloned().collect();
+```
+The better use would be:
+```
+let s = [1, 2, 3, 4, 5];
+let s2: Vec<isize> = s.to_vec();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_count.txt b/src/tools/clippy/src/docs/iter_count.txt
new file mode 100644 (file)
index 0000000..f3db4a2
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for the use of `.iter().count()`.
+
+### Why is this bad?
+`.len()` is more efficient and more
+readable.
+
+### Example
+```
+let some_vec = vec![0, 1, 2, 3];
+
+some_vec.iter().count();
+&some_vec[..].iter().count();
+```
+
+Use instead:
+```
+let some_vec = vec![0, 1, 2, 3];
+
+some_vec.len();
+&some_vec[..].len();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_next_loop.txt b/src/tools/clippy/src/docs/iter_next_loop.txt
new file mode 100644 (file)
index 0000000..b33eb39
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for loops on `x.next()`.
+
+### Why is this bad?
+`next()` returns either `Some(value)` if there was a
+value, or `None` otherwise. The insidious thing is that `Option<_>`
+implements `IntoIterator`, so that possibly one value will be iterated,
+leading to some hard to find bugs. No one will want to write such code
+[except to win an Underhanded Rust
+Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr).
+
+### Example
+```
+for x in y.next() {
+    ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_next_slice.txt b/src/tools/clippy/src/docs/iter_next_slice.txt
new file mode 100644 (file)
index 0000000..1cea25e
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `iter().next()` on a Slice or an Array
+
+### Why is this bad?
+These can be shortened into `.get()`
+
+### Example
+```
+a[2..].iter().next();
+b.iter().next();
+```
+should be written as:
+```
+a.get(2);
+b.get(0);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_not_returning_iterator.txt b/src/tools/clippy/src/docs/iter_not_returning_iterator.txt
new file mode 100644 (file)
index 0000000..0ca8629
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Detects methods named `iter` or `iter_mut` that do not have a return type that implements `Iterator`.
+
+### Why is this bad?
+Methods named `iter` or `iter_mut` conventionally return an `Iterator`.
+
+### Example
+```
+// `String` does not implement `Iterator`
+struct Data {}
+impl Data {
+    fn iter(&self) -> String {
+        todo!()
+    }
+}
+```
+Use instead:
+```
+use std::str::Chars;
+struct Data {}
+impl Data {
+   fn iter(&self) -> Chars<'static> {
+       todo!()
+   }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_nth.txt b/src/tools/clippy/src/docs/iter_nth.txt
new file mode 100644 (file)
index 0000000..3d67d58
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for use of `.iter().nth()` (and the related
+`.iter_mut().nth()`) on standard library types with *O*(1) element access.
+
+### Why is this bad?
+`.get()` and `.get_mut()` are more efficient and more
+readable.
+
+### Example
+```
+let some_vec = vec![0, 1, 2, 3];
+let bad_vec = some_vec.iter().nth(3);
+let bad_slice = &some_vec[..].iter().nth(3);
+```
+The correct use would be:
+```
+let some_vec = vec![0, 1, 2, 3];
+let bad_vec = some_vec.get(3);
+let bad_slice = &some_vec[..].get(3);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_nth_zero.txt b/src/tools/clippy/src/docs/iter_nth_zero.txt
new file mode 100644 (file)
index 0000000..8efe47a
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for the use of `iter.nth(0)`.
+
+### Why is this bad?
+`iter.next()` is equivalent to
+`iter.nth(0)`, as they both consume the next element,
+ but is more readable.
+
+### Example
+```
+let x = s.iter().nth(0);
+```
+
+Use instead:
+```
+let x = s.iter().next();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_on_empty_collections.txt b/src/tools/clippy/src/docs/iter_on_empty_collections.txt
new file mode 100644 (file)
index 0000000..87c4ec1
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+
+Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections
+
+### Why is this bad?
+
+It is simpler to use the empty function from the standard library:
+
+### Example
+
+```
+use std::{slice, option};
+let a: slice::Iter<i32> = [].iter();
+let f: option::IntoIter<i32> = None.into_iter();
+```
+Use instead:
+```
+use std::iter;
+let a: iter::Empty<i32> = iter::empty();
+let b: iter::Empty<i32> = iter::empty();
+```
+
+### Known problems
+
+The type of the resulting iterator might become incompatible with its usage
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_on_single_items.txt b/src/tools/clippy/src/docs/iter_on_single_items.txt
new file mode 100644 (file)
index 0000000..d0388f2
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+
+Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item
+
+### Why is this bad?
+
+It is simpler to use the once function from the standard library:
+
+### Example
+
+```
+let a = [123].iter();
+let b = Some(123).into_iter();
+```
+Use instead:
+```
+use std::iter;
+let a = iter::once(&123);
+let b = iter::once(123);
+```
+
+### Known problems
+
+The type of the resulting iterator might become incompatible with its usage
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_overeager_cloned.txt b/src/tools/clippy/src/docs/iter_overeager_cloned.txt
new file mode 100644 (file)
index 0000000..2f902a0
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `_.cloned().<func>()` where call to `.cloned()` can be postponed.
+
+### Why is this bad?
+It's often inefficient to clone all elements of an iterator, when eventually, only some
+of them will be consumed.
+
+### Known Problems
+This `lint` removes the side of effect of cloning items in the iterator.
+A code that relies on that side-effect could fail.
+
+### Examples
+```
+vec.iter().cloned().take(10);
+vec.iter().cloned().last();
+```
+
+Use instead:
+```
+vec.iter().take(10).cloned();
+vec.iter().last().cloned();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_skip_next.txt b/src/tools/clippy/src/docs/iter_skip_next.txt
new file mode 100644 (file)
index 0000000..da226b0
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for use of `.skip(x).next()` on iterators.
+
+### Why is this bad?
+`.nth(x)` is cleaner
+
+### Example
+```
+let some_vec = vec![0, 1, 2, 3];
+let bad_vec = some_vec.iter().skip(3).next();
+let bad_slice = &some_vec[..].iter().skip(3).next();
+```
+The correct use would be:
+```
+let some_vec = vec![0, 1, 2, 3];
+let bad_vec = some_vec.iter().nth(3);
+let bad_slice = &some_vec[..].iter().nth(3);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_with_drain.txt b/src/tools/clippy/src/docs/iter_with_drain.txt
new file mode 100644 (file)
index 0000000..2c52b99
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for use of `.drain(..)` on `Vec` and `VecDeque` for iteration.
+
+### Why is this bad?
+`.into_iter()` is simpler with better performance.
+
+### Example
+```
+let mut foo = vec![0, 1, 2, 3];
+let bar: HashSet<usize> = foo.drain(..).collect();
+```
+Use instead:
+```
+let foo = vec![0, 1, 2, 3];
+let bar: HashSet<usize> = foo.into_iter().collect();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iterator_step_by_zero.txt b/src/tools/clippy/src/docs/iterator_step_by_zero.txt
new file mode 100644 (file)
index 0000000..73ecc99
--- /dev/null
@@ -0,0 +1,13 @@
+### What it does
+Checks for calling `.step_by(0)` on iterators which panics.
+
+### Why is this bad?
+This very much looks like an oversight. Use `panic!()` instead if you
+actually intend to panic.
+
+### Example
+```
+for x in (0..100).step_by(0) {
+    //..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/just_underscores_and_digits.txt b/src/tools/clippy/src/docs/just_underscores_and_digits.txt
new file mode 100644 (file)
index 0000000..a8790bc
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks if you have variables whose name consists of just
+underscores and digits.
+
+### Why is this bad?
+It's hard to memorize what a variable means without a
+descriptive name.
+
+### Example
+```
+let _1 = 1;
+let ___1 = 1;
+let __1___2 = 11;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/large_const_arrays.txt b/src/tools/clippy/src/docs/large_const_arrays.txt
new file mode 100644 (file)
index 0000000..71f6785
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for large `const` arrays that should
+be defined as `static` instead.
+
+### Why is this bad?
+Performance: const variables are inlined upon use.
+Static items result in only one instance and has a fixed location in memory.
+
+### Example
+```
+pub const a = [0u32; 1_000_000];
+```
+
+Use instead:
+```
+pub static a = [0u32; 1_000_000];
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/large_digit_groups.txt b/src/tools/clippy/src/docs/large_digit_groups.txt
new file mode 100644 (file)
index 0000000..f60b193
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Warns if the digits of an integral or floating-point
+constant are grouped into groups that
+are too large.
+
+### Why is this bad?
+Negatively impacts readability.
+
+### Example
+```
+let x: u64 = 6186491_8973511;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/large_enum_variant.txt b/src/tools/clippy/src/docs/large_enum_variant.txt
new file mode 100644 (file)
index 0000000..1f95430
--- /dev/null
@@ -0,0 +1,41 @@
+### What it does
+Checks for large size differences between variants on
+`enum`s.
+
+### Why is this bad?
+Enum size is bounded by the largest variant. Having one
+large variant can penalize the memory layout of that enum.
+
+### Known problems
+This lint obviously cannot take the distribution of
+variants in your running program into account. It is possible that the
+smaller variants make up less than 1% of all instances, in which case
+the overhead is negligible and the boxing is counter-productive. Always
+measure the change this lint suggests.
+
+For types that implement `Copy`, the suggestion to `Box` a variant's
+data would require removing the trait impl. The types can of course
+still be `Clone`, but that is worse ergonomically. Depending on the
+use case it may be possible to store the large data in an auxiliary
+structure (e.g. Arena or ECS).
+
+The lint will ignore the impact of generic types to the type layout by
+assuming every type parameter is zero-sized. Depending on your use case,
+this may lead to a false positive.
+
+### Example
+```
+enum Test {
+    A(i32),
+    B([i32; 8000]),
+}
+```
+
+Use instead:
+```
+// Possibly better
+enum Test2 {
+    A(i32),
+    B(Box<[i32; 8000]>),
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/large_include_file.txt b/src/tools/clippy/src/docs/large_include_file.txt
new file mode 100644 (file)
index 0000000..b2a54bd
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for the inclusion of large files via `include_bytes!()`
+and `include_str!()`
+
+### Why is this bad?
+Including large files can increase the size of the binary
+
+### Example
+```
+let included_str = include_str!("very_large_file.txt");
+let included_bytes = include_bytes!("very_large_file.txt");
+```
+
+Use instead:
+```
+use std::fs;
+
+// You can load the file at runtime
+let string = fs::read_to_string("very_large_file.txt")?;
+let bytes = fs::read("very_large_file.txt")?;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/large_stack_arrays.txt b/src/tools/clippy/src/docs/large_stack_arrays.txt
new file mode 100644 (file)
index 0000000..4a6f347
--- /dev/null
@@ -0,0 +1,10 @@
+### What it does
+Checks for local arrays that may be too large.
+
+### Why is this bad?
+Large local arrays may cause stack overflow.
+
+### Example
+```
+let a = [0u32; 1_000_000];
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/large_types_passed_by_value.txt b/src/tools/clippy/src/docs/large_types_passed_by_value.txt
new file mode 100644 (file)
index 0000000..bca07f3
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for functions taking arguments by value, where
+the argument type is `Copy` and large enough to be worth considering
+passing by reference. Does not trigger if the function is being exported,
+because that might induce API breakage, if the parameter is declared as mutable,
+or if the argument is a `self`.
+
+### Why is this bad?
+Arguments passed by value might result in an unnecessary
+shallow copy, taking up more space in the stack and requiring a call to
+`memcpy`, which can be expensive.
+
+### Example
+```
+#[derive(Clone, Copy)]
+struct TooLarge([u8; 2048]);
+
+fn foo(v: TooLarge) {}
+```
+
+Use instead:
+```
+fn foo(v: &TooLarge) {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/len_without_is_empty.txt b/src/tools/clippy/src/docs/len_without_is_empty.txt
new file mode 100644 (file)
index 0000000..47a2e85
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for items that implement `.len()` but not
+`.is_empty()`.
+
+### Why is this bad?
+It is good custom to have both methods, because for
+some data structures, asking about the length will be a costly operation,
+whereas `.is_empty()` can usually answer in constant time. Also it used to
+lead to false positives on the [`len_zero`](#len_zero) lint – currently that
+lint will ignore such entities.
+
+### Example
+```
+impl X {
+    pub fn len(&self) -> usize {
+        ..
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/len_zero.txt b/src/tools/clippy/src/docs/len_zero.txt
new file mode 100644 (file)
index 0000000..664124b
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+Checks for getting the length of something via `.len()`
+just to compare to zero, and suggests using `.is_empty()` where applicable.
+
+### Why is this bad?
+Some structures can answer `.is_empty()` much faster
+than calculating their length. So it is good to get into the habit of using
+`.is_empty()`, and having it is cheap.
+Besides, it makes the intent clearer than a manual comparison in some contexts.
+
+### Example
+```
+if x.len() == 0 {
+    ..
+}
+if y.len() != 0 {
+    ..
+}
+```
+instead use
+```
+if x.is_empty() {
+    ..
+}
+if !y.is_empty() {
+    ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/let_and_return.txt b/src/tools/clippy/src/docs/let_and_return.txt
new file mode 100644 (file)
index 0000000..eba5a90
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for `let`-bindings, which are subsequently
+returned.
+
+### Why is this bad?
+It is just extraneous code. Remove it to make your code
+more rusty.
+
+### Example
+```
+fn foo() -> String {
+    let x = String::new();
+    x
+}
+```
+instead, use
+```
+fn foo() -> String {
+    String::new()
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/let_underscore_drop.txt b/src/tools/clippy/src/docs/let_underscore_drop.txt
new file mode 100644 (file)
index 0000000..29ce9bf
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for `let _ = <expr>`
+where expr has a type that implements `Drop`
+
+### Why is this bad?
+This statement immediately drops the initializer
+expression instead of extending its lifetime to the end of the scope, which
+is often not intended. To extend the expression's lifetime to the end of the
+scope, use an underscore-prefixed name instead (i.e. _var). If you want to
+explicitly drop the expression, `std::mem::drop` conveys your intention
+better and is less error-prone.
+
+### Example
+```
+{
+    let _ = DroppableItem;
+    //                   ^ dropped here
+    /* more code */
+}
+```
+
+Use instead:
+```
+{
+    let _droppable = DroppableItem;
+    /* more code */
+    // dropped at end of scope
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/let_underscore_lock.txt b/src/tools/clippy/src/docs/let_underscore_lock.txt
new file mode 100644 (file)
index 0000000..bd8217f
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for `let _ = sync_lock`.
+This supports `mutex` and `rwlock` in `std::sync` and `parking_lot`.
+
+### Why is this bad?
+This statement immediately drops the lock instead of
+extending its lifetime to the end of the scope, which is often not intended.
+To extend lock lifetime to the end of the scope, use an underscore-prefixed
+name instead (i.e. _lock). If you want to explicitly drop the lock,
+`std::mem::drop` conveys your intention better and is less error-prone.
+
+### Example
+```
+let _ = mutex.lock();
+```
+
+Use instead:
+```
+let _lock = mutex.lock();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/let_underscore_must_use.txt b/src/tools/clippy/src/docs/let_underscore_must_use.txt
new file mode 100644 (file)
index 0000000..270b81d
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for `let _ = <expr>` where expr is `#[must_use]`
+
+### Why is this bad?
+It's better to explicitly handle the value of a `#[must_use]`
+expr
+
+### Example
+```
+fn f() -> Result<u32, u32> {
+    Ok(0)
+}
+
+let _ = f();
+// is_ok() is marked #[must_use]
+let _ = f().is_ok();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/let_unit_value.txt b/src/tools/clippy/src/docs/let_unit_value.txt
new file mode 100644 (file)
index 0000000..bc16d5b
--- /dev/null
@@ -0,0 +1,13 @@
+### What it does
+Checks for binding a unit value.
+
+### Why is this bad?
+A unit value cannot usefully be used anywhere. So
+binding one is kind of pointless.
+
+### Example
+```
+let x = {
+    1;
+};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/linkedlist.txt b/src/tools/clippy/src/docs/linkedlist.txt
new file mode 100644 (file)
index 0000000..986ff13
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Checks for usage of any `LinkedList`, suggesting to use a
+`Vec` or a `VecDeque` (formerly called `RingBuf`).
+
+### Why is this bad?
+Gankro says:
+
+> The TL;DR of `LinkedList` is that it's built on a massive amount of
+pointers and indirection.
+> It wastes memory, it has terrible cache locality, and is all-around slow.
+`RingBuf`, while
+> "only" amortized for push/pop, should be faster in the general case for
+almost every possible
+> workload, and isn't even amortized at all if you can predict the capacity
+you need.
+>
+> `LinkedList`s are only really good if you're doing a lot of merging or
+splitting of lists.
+> This is because they can just mangle some pointers instead of actually
+copying the data. Even
+> if you're doing a lot of insertion in the middle of the list, `RingBuf`
+can still be better
+> because of how expensive it is to seek to the middle of a `LinkedList`.
+
+### Known problems
+False positives – the instances where using a
+`LinkedList` makes sense are few and far between, but they can still happen.
+
+### Example
+```
+let x: LinkedList<usize> = LinkedList::new();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/lossy_float_literal.txt b/src/tools/clippy/src/docs/lossy_float_literal.txt
new file mode 100644 (file)
index 0000000..bbcb911
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for whole number float literals that
+cannot be represented as the underlying type without loss.
+
+### Why is this bad?
+Rust will silently lose precision during
+conversion to a float.
+
+### Example
+```
+let _: f32 = 16_777_217.0; // 16_777_216.0
+```
+
+Use instead:
+```
+let _: f32 = 16_777_216.0;
+let _: f64 = 16_777_217.0;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/macro_use_imports.txt b/src/tools/clippy/src/docs/macro_use_imports.txt
new file mode 100644 (file)
index 0000000..6a8180a
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for `#[macro_use] use...`.
+
+### Why is this bad?
+Since the Rust 2018 edition you can import
+macro's directly, this is considered idiomatic.
+
+### Example
+```
+#[macro_use]
+use some_macro;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/main_recursion.txt b/src/tools/clippy/src/docs/main_recursion.txt
new file mode 100644 (file)
index 0000000..e49becd
--- /dev/null
@@ -0,0 +1,13 @@
+### What it does
+Checks for recursion using the entrypoint.
+
+### Why is this bad?
+Apart from special setups (which we could detect following attributes like #![no_std]),
+recursing into main() seems like an unintuitive anti-pattern we should be able to detect.
+
+### Example
+```
+fn main() {
+    main();
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_assert.txt b/src/tools/clippy/src/docs/manual_assert.txt
new file mode 100644 (file)
index 0000000..9365308
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Detects `if`-then-`panic!` that can be replaced with `assert!`.
+
+### Why is this bad?
+`assert!` is simpler than `if`-then-`panic!`.
+
+### Example
+```
+let sad_people: Vec<&str> = vec![];
+if !sad_people.is_empty() {
+    panic!("there are sad people: {:?}", sad_people);
+}
+```
+Use instead:
+```
+let sad_people: Vec<&str> = vec![];
+assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_async_fn.txt b/src/tools/clippy/src/docs/manual_async_fn.txt
new file mode 100644 (file)
index 0000000..d01ac40
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+It checks for manual implementations of `async` functions.
+
+### Why is this bad?
+It's more idiomatic to use the dedicated syntax.
+
+### Example
+```
+use std::future::Future;
+
+fn foo() -> impl Future<Output = i32> { async { 42 } }
+```
+Use instead:
+```
+async fn foo() -> i32 { 42 }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_bits.txt b/src/tools/clippy/src/docs/manual_bits.txt
new file mode 100644 (file)
index 0000000..b96c2eb
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for uses of `std::mem::size_of::<T>() * 8` when
+`T::BITS` is available.
+
+### Why is this bad?
+Can be written as the shorter `T::BITS`.
+
+### Example
+```
+std::mem::size_of::<usize>() * 8;
+```
+Use instead:
+```
+usize::BITS as usize;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_filter_map.txt b/src/tools/clippy/src/docs/manual_filter_map.txt
new file mode 100644 (file)
index 0000000..3b68607
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `_.filter(_).map(_)` that can be written more simply
+as `filter_map(_)`.
+
+### Why is this bad?
+Redundant code in the `filter` and `map` operations is poor style and
+less performant.
+
+### Example
+```
+(0_i32..10)
+    .filter(|n| n.checked_add(1).is_some())
+    .map(|n| n.checked_add(1).unwrap());
+```
+
+Use instead:
+```
+(0_i32..10).filter_map(|n| n.checked_add(1));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_find.txt b/src/tools/clippy/src/docs/manual_find.txt
new file mode 100644 (file)
index 0000000..e3e07a2
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Check for manual implementations of Iterator::find
+
+### Why is this bad?
+It doesn't affect performance, but using `find` is shorter and easier to read.
+
+### Example
+
+```
+fn example(arr: Vec<i32>) -> Option<i32> {
+    for el in arr {
+        if el == 1 {
+            return Some(el);
+        }
+    }
+    None
+}
+```
+Use instead:
+```
+fn example(arr: Vec<i32>) -> Option<i32> {
+    arr.into_iter().find(|&el| el == 1)
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_find_map.txt b/src/tools/clippy/src/docs/manual_find_map.txt
new file mode 100644 (file)
index 0000000..83b2206
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `_.find(_).map(_)` that can be written more simply
+as `find_map(_)`.
+
+### Why is this bad?
+Redundant code in the `find` and `map` operations is poor style and
+less performant.
+
+### Example
+```
+(0_i32..10)
+    .find(|n| n.checked_add(1).is_some())
+    .map(|n| n.checked_add(1).unwrap());
+```
+
+Use instead:
+```
+(0_i32..10).find_map(|n| n.checked_add(1));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_flatten.txt b/src/tools/clippy/src/docs/manual_flatten.txt
new file mode 100644 (file)
index 0000000..62d5f3e
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Check for unnecessary `if let` usage in a for loop
+where only the `Some` or `Ok` variant of the iterator element is used.
+
+### Why is this bad?
+It is verbose and can be simplified
+by first calling the `flatten` method on the `Iterator`.
+
+### Example
+
+```
+let x = vec![Some(1), Some(2), Some(3)];
+for n in x {
+    if let Some(n) = n {
+        println!("{}", n);
+    }
+}
+```
+Use instead:
+```
+let x = vec![Some(1), Some(2), Some(3)];
+for n in x.into_iter().flatten() {
+    println!("{}", n);
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_instant_elapsed.txt b/src/tools/clippy/src/docs/manual_instant_elapsed.txt
new file mode 100644 (file)
index 0000000..dde3d49
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Lints subtraction between `Instant::now()` and another `Instant`.
+
+### Why is this bad?
+It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
+as `Instant` subtraction saturates.
+
+`prev_instant.elapsed()` also more clearly signals intention.
+
+### Example
+```
+use std::time::Instant;
+let prev_instant = Instant::now();
+let duration = Instant::now() - prev_instant;
+```
+Use instead:
+```
+use std::time::Instant;
+let prev_instant = Instant::now();
+let duration = prev_instant.elapsed();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_map.txt b/src/tools/clippy/src/docs/manual_map.txt
new file mode 100644 (file)
index 0000000..7f68ccd
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for usages of `match` which could be implemented using `map`
+
+### Why is this bad?
+Using the `map` method is clearer and more concise.
+
+### Example
+```
+match Some(0) {
+    Some(x) => Some(x + 1),
+    None => None,
+};
+```
+Use instead:
+```
+Some(0).map(|x| x + 1);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_memcpy.txt b/src/tools/clippy/src/docs/manual_memcpy.txt
new file mode 100644 (file)
index 0000000..d7690bf
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for for-loops that manually copy items between
+slices that could be optimized by having a memcpy.
+
+### Why is this bad?
+It is not as fast as a memcpy.
+
+### Example
+```
+for i in 0..src.len() {
+    dst[i + 64] = src[i];
+}
+```
+
+Use instead:
+```
+dst[64..(src.len() + 64)].clone_from_slice(&src[..]);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_non_exhaustive.txt b/src/tools/clippy/src/docs/manual_non_exhaustive.txt
new file mode 100644 (file)
index 0000000..fb02139
--- /dev/null
@@ -0,0 +1,41 @@
+### What it does
+Checks for manual implementations of the non-exhaustive pattern.
+
+### Why is this bad?
+Using the #[non_exhaustive] attribute expresses better the intent
+and allows possible optimizations when applied to enums.
+
+### Example
+```
+struct S {
+    pub a: i32,
+    pub b: i32,
+    _c: (),
+}
+
+enum E {
+    A,
+    B,
+    #[doc(hidden)]
+    _C,
+}
+
+struct T(pub i32, pub i32, ());
+```
+Use instead:
+```
+#[non_exhaustive]
+struct S {
+    pub a: i32,
+    pub b: i32,
+}
+
+#[non_exhaustive]
+enum E {
+    A,
+    B,
+}
+
+#[non_exhaustive]
+struct T(pub i32, pub i32);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_ok_or.txt b/src/tools/clippy/src/docs/manual_ok_or.txt
new file mode 100644 (file)
index 0000000..5accdf2
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+
+Finds patterns that reimplement `Option::ok_or`.
+
+### Why is this bad?
+
+Concise code helps focusing on behavior instead of boilerplate.
+
+### Examples
+```
+let foo: Option<i32> = None;
+foo.map_or(Err("error"), |v| Ok(v));
+```
+
+Use instead:
+```
+let foo: Option<i32> = None;
+foo.ok_or("error");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_range_contains.txt b/src/tools/clippy/src/docs/manual_range_contains.txt
new file mode 100644 (file)
index 0000000..0ade269
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for expressions like `x >= 3 && x < 8` that could
+be more readably expressed as `(3..8).contains(x)`.
+
+### Why is this bad?
+`contains` expresses the intent better and has less
+failure modes (such as fencepost errors or using `||` instead of `&&`).
+
+### Example
+```
+// given
+let x = 6;
+
+assert!(x >= 3 && x < 8);
+```
+Use instead:
+```
+assert!((3..8).contains(&x));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_rem_euclid.txt b/src/tools/clippy/src/docs/manual_rem_euclid.txt
new file mode 100644 (file)
index 0000000..d3bb8c6
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for an expression like `((x % 4) + 4) % 4` which is a common manual reimplementation
+of `x.rem_euclid(4)`.
+
+### Why is this bad?
+It's simpler and more readable.
+
+### Example
+```
+let x: i32 = 24;
+let rem = ((x % 4) + 4) % 4;
+```
+Use instead:
+```
+let x: i32 = 24;
+let rem = x.rem_euclid(4);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_retain.txt b/src/tools/clippy/src/docs/manual_retain.txt
new file mode 100644 (file)
index 0000000..cd4f65a
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for code to be replaced by `.retain()`.
+### Why is this bad?
+`.retain()` is simpler and avoids needless allocation.
+### Example
+```
+let mut vec = vec![0, 1, 2];
+vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect();
+vec = vec.into_iter().filter(|x| x % 2 == 0).collect();
+```
+Use instead:
+```
+let mut vec = vec![0, 1, 2];
+vec.retain(|x| x % 2 == 0);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_saturating_arithmetic.txt b/src/tools/clippy/src/docs/manual_saturating_arithmetic.txt
new file mode 100644 (file)
index 0000000..d9f5d3d
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`.
+
+### Why is this bad?
+These can be written simply with `saturating_add/sub` methods.
+
+### Example
+```
+let add = x.checked_add(y).unwrap_or(u32::MAX);
+let sub = x.checked_sub(y).unwrap_or(u32::MIN);
+```
+
+can be written using dedicated methods for saturating addition/subtraction as:
+
+```
+let add = x.saturating_add(y);
+let sub = x.saturating_sub(y);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_split_once.txt b/src/tools/clippy/src/docs/manual_split_once.txt
new file mode 100644 (file)
index 0000000..291ae44
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for usages of `str::splitn(2, _)`
+
+### Why is this bad?
+`split_once` is both clearer in intent and slightly more efficient.
+
+### Example
+```
+let s = "key=value=add";
+let (key, value) = s.splitn(2, '=').next_tuple()?;
+let value = s.splitn(2, '=').nth(1)?;
+
+let mut parts = s.splitn(2, '=');
+let key = parts.next()?;
+let value = parts.next()?;
+```
+
+Use instead:
+```
+let s = "key=value=add";
+let (key, value) = s.split_once('=')?;
+let value = s.split_once('=')?.1;
+
+let (key, value) = s.split_once('=')?;
+```
+
+### Limitations
+The multiple statement variant currently only detects `iter.next()?`/`iter.next().unwrap()`
+in two separate `let` statements that immediately follow the `splitn()`
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_str_repeat.txt b/src/tools/clippy/src/docs/manual_str_repeat.txt
new file mode 100644 (file)
index 0000000..1d4a7a4
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for manual implementations of `str::repeat`
+
+### Why is this bad?
+These are both harder to read, as well as less performant.
+
+### Example
+```
+let x: String = std::iter::repeat('x').take(10).collect();
+```
+
+Use instead:
+```
+let x: String = "x".repeat(10);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_string_new.txt b/src/tools/clippy/src/docs/manual_string_new.txt
new file mode 100644 (file)
index 0000000..4cbc43f
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+
+Checks for usage of `""` to create a `String`, such as `"".to_string()`, `"".to_owned()`,
+`String::from("")` and others.
+
+### Why is this bad?
+
+Different ways of creating an empty string makes your code less standardized, which can
+be confusing.
+
+### Example
+```
+let a = "".to_string();
+let b: String = "".into();
+```
+Use instead:
+```
+let a = String::new();
+let b = String::new();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_strip.txt b/src/tools/clippy/src/docs/manual_strip.txt
new file mode 100644 (file)
index 0000000..f32d8e7
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using
+the pattern's length.
+
+### Why is this bad?
+Using `str:strip_{prefix,suffix}` is safer and may have better performance as there is no
+slicing which may panic and the compiler does not need to insert this panic code. It is
+also sometimes more readable as it removes the need for duplicating or storing the pattern
+used by `str::{starts,ends}_with` and in the slicing.
+
+### Example
+```
+let s = "hello, world!";
+if s.starts_with("hello, ") {
+    assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
+}
+```
+Use instead:
+```
+let s = "hello, world!";
+if let Some(end) = s.strip_prefix("hello, ") {
+    assert_eq!(end.to_uppercase(), "WORLD!");
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_swap.txt b/src/tools/clippy/src/docs/manual_swap.txt
new file mode 100644 (file)
index 0000000..bd95262
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for manual swapping.
+
+### Why is this bad?
+The `std::mem::swap` function exposes the intent better
+without deinitializing or copying either variable.
+
+### Example
+```
+let mut a = 42;
+let mut b = 1337;
+
+let t = b;
+b = a;
+a = t;
+```
+Use std::mem::swap():
+```
+let mut a = 1;
+let mut b = 2;
+std::mem::swap(&mut a, &mut b);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_unwrap_or.txt b/src/tools/clippy/src/docs/manual_unwrap_or.txt
new file mode 100644 (file)
index 0000000..1fd7d83
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Finds patterns that reimplement `Option::unwrap_or` or `Result::unwrap_or`.
+
+### Why is this bad?
+Concise code helps focusing on behavior instead of boilerplate.
+
+### Example
+```
+let foo: Option<i32> = None;
+match foo {
+    Some(v) => v,
+    None => 1,
+};
+```
+
+Use instead:
+```
+let foo: Option<i32> = None;
+foo.unwrap_or(1);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/many_single_char_names.txt b/src/tools/clippy/src/docs/many_single_char_names.txt
new file mode 100644 (file)
index 0000000..55ee5da
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for too many variables whose name consists of a
+single character.
+
+### Why is this bad?
+It's hard to memorize what a variable means without a
+descriptive name.
+
+### Example
+```
+let (a, b, c, d, e, f, g) = (...);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_clone.txt b/src/tools/clippy/src/docs/map_clone.txt
new file mode 100644 (file)
index 0000000..3ee27f0
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `map(|x| x.clone())` or
+dereferencing closures for `Copy` types, on `Iterator` or `Option`,
+and suggests `cloned()` or `copied()` instead
+
+### Why is this bad?
+Readability, this can be written more concisely
+
+### Example
+```
+let x = vec![42, 43];
+let y = x.iter();
+let z = y.map(|i| *i);
+```
+
+The correct use would be:
+
+```
+let x = vec![42, 43];
+let y = x.iter();
+let z = y.cloned();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_collect_result_unit.txt b/src/tools/clippy/src/docs/map_collect_result_unit.txt
new file mode 100644 (file)
index 0000000..9b72061
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for usage of `_.map(_).collect::<Result<(), _>()`.
+
+### Why is this bad?
+Using `try_for_each` instead is more readable and idiomatic.
+
+### Example
+```
+(0..3).map(|t| Err(t)).collect::<Result<(), _>>();
+```
+Use instead:
+```
+(0..3).try_for_each(|t| Err(t));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_entry.txt b/src/tools/clippy/src/docs/map_entry.txt
new file mode 100644 (file)
index 0000000..20dba17
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+Checks for uses of `contains_key` + `insert` on `HashMap`
+or `BTreeMap`.
+
+### Why is this bad?
+Using `entry` is more efficient.
+
+### Known problems
+The suggestion may have type inference errors in some cases. e.g.
+```
+let mut map = std::collections::HashMap::new();
+let _ = if !map.contains_key(&0) {
+    map.insert(0, 0)
+} else {
+    None
+};
+```
+
+### Example
+```
+if !map.contains_key(&k) {
+    map.insert(k, v);
+}
+```
+Use instead:
+```
+map.entry(k).or_insert(v);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_err_ignore.txt b/src/tools/clippy/src/docs/map_err_ignore.txt
new file mode 100644 (file)
index 0000000..2606c13
--- /dev/null
@@ -0,0 +1,93 @@
+### What it does
+Checks for instances of `map_err(|_| Some::Enum)`
+
+### Why is this bad?
+This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error
+
+### Example
+Before:
+```
+use std::fmt;
+
+#[derive(Debug)]
+enum Error {
+    Indivisible,
+    Remainder(u8),
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Error::Indivisible => write!(f, "could not divide input by three"),
+            Error::Remainder(remainder) => write!(
+                f,
+                "input is not divisible by three, remainder = {}",
+                remainder
+            ),
+        }
+    }
+}
+
+impl std::error::Error for Error {}
+
+fn divisible_by_3(input: &str) -> Result<(), Error> {
+    input
+        .parse::<i32>()
+        .map_err(|_| Error::Indivisible)
+        .map(|v| v % 3)
+        .and_then(|remainder| {
+            if remainder == 0 {
+                Ok(())
+            } else {
+                Err(Error::Remainder(remainder as u8))
+            }
+        })
+}
+ ```
+
+ After:
+ ```rust
+use std::{fmt, num::ParseIntError};
+
+#[derive(Debug)]
+enum Error {
+    Indivisible(ParseIntError),
+    Remainder(u8),
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Error::Indivisible(_) => write!(f, "could not divide input by three"),
+            Error::Remainder(remainder) => write!(
+                f,
+                "input is not divisible by three, remainder = {}",
+                remainder
+            ),
+        }
+    }
+}
+
+impl std::error::Error for Error {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        match self {
+            Error::Indivisible(source) => Some(source),
+            _ => None,
+        }
+    }
+}
+
+fn divisible_by_3(input: &str) -> Result<(), Error> {
+    input
+        .parse::<i32>()
+        .map_err(Error::Indivisible)
+        .map(|v| v % 3)
+        .and_then(|remainder| {
+            if remainder == 0 {
+                Ok(())
+            } else {
+                Err(Error::Remainder(remainder as u8))
+            }
+        })
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_flatten.txt b/src/tools/clippy/src/docs/map_flatten.txt
new file mode 100644 (file)
index 0000000..73c0e51
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option`
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option`
+
+### Example
+```
+let vec = vec![vec![1]];
+let opt = Some(5);
+
+vec.iter().map(|x| x.iter()).flatten();
+opt.map(|x| Some(x * 2)).flatten();
+```
+
+Use instead:
+```
+vec.iter().flat_map(|x| x.iter());
+opt.and_then(|x| Some(x * 2));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_identity.txt b/src/tools/clippy/src/docs/map_identity.txt
new file mode 100644 (file)
index 0000000..e2e7af0
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for instances of `map(f)` where `f` is the identity function.
+
+### Why is this bad?
+It can be written more concisely without the call to `map`.
+
+### Example
+```
+let x = [1, 2, 3];
+let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
+```
+Use instead:
+```
+let x = [1, 2, 3];
+let y: Vec<_> = x.iter().map(|x| 2*x).collect();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_unwrap_or.txt b/src/tools/clippy/src/docs/map_unwrap_or.txt
new file mode 100644 (file)
index 0000000..485b29f
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or
+`result.map(_).unwrap_or_else(_)`.
+
+### Why is this bad?
+Readability, these can be written more concisely (resp.) as
+`option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`.
+
+### Known problems
+The order of the arguments is not in execution order
+
+### Examples
+```
+option.map(|a| a + 1).unwrap_or(0);
+result.map(|a| a + 1).unwrap_or_else(some_function);
+```
+
+Use instead:
+```
+option.map_or(0, |a| a + 1);
+result.map_or_else(some_function, |a| a + 1);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_as_ref.txt b/src/tools/clippy/src/docs/match_as_ref.txt
new file mode 100644 (file)
index 0000000..5e5f3d6
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for match which is used to add a reference to an
+`Option` value.
+
+### Why is this bad?
+Using `as_ref()` or `as_mut()` instead is shorter.
+
+### Example
+```
+let x: Option<()> = None;
+
+let r: Option<&()> = match x {
+    None => None,
+    Some(ref v) => Some(v),
+};
+```
+
+Use instead:
+```
+let x: Option<()> = None;
+
+let r: Option<&()> = x.as_ref();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_bool.txt b/src/tools/clippy/src/docs/match_bool.txt
new file mode 100644 (file)
index 0000000..96f9e1f
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for matches where match expression is a `bool`. It
+suggests to replace the expression with an `if...else` block.
+
+### Why is this bad?
+It makes the code less readable.
+
+### Example
+```
+let condition: bool = true;
+match condition {
+    true => foo(),
+    false => bar(),
+}
+```
+Use if/else instead:
+```
+let condition: bool = true;
+if condition {
+    foo();
+} else {
+    bar();
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_like_matches_macro.txt b/src/tools/clippy/src/docs/match_like_matches_macro.txt
new file mode 100644 (file)
index 0000000..643e2dd
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Checks for `match`  or `if let` expressions producing a
+`bool` that could be written using `matches!`
+
+### Why is this bad?
+Readability and needless complexity.
+
+### Known problems
+This lint falsely triggers, if there are arms with
+`cfg` attributes that remove an arm evaluating to `false`.
+
+### Example
+```
+let x = Some(5);
+
+let a = match x {
+    Some(0) => true,
+    _ => false,
+};
+
+let a = if let Some(0) = x {
+    true
+} else {
+    false
+};
+```
+
+Use instead:
+```
+let x = Some(5);
+let a = matches!(x, Some(0));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_on_vec_items.txt b/src/tools/clippy/src/docs/match_on_vec_items.txt
new file mode 100644 (file)
index 0000000..981d18d
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for `match vec[idx]` or `match vec[n..m]`.
+
+### Why is this bad?
+This can panic at runtime.
+
+### Example
+```
+let arr = vec![0, 1, 2, 3];
+let idx = 1;
+
+match arr[idx] {
+    0 => println!("{}", 0),
+    1 => println!("{}", 3),
+    _ => {},
+}
+```
+
+Use instead:
+```
+let arr = vec![0, 1, 2, 3];
+let idx = 1;
+
+match arr.get(idx) {
+    Some(0) => println!("{}", 0),
+    Some(1) => println!("{}", 3),
+    _ => {},
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_overlapping_arm.txt b/src/tools/clippy/src/docs/match_overlapping_arm.txt
new file mode 100644 (file)
index 0000000..841c091
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for overlapping match arms.
+
+### Why is this bad?
+It is likely to be an error and if not, makes the code
+less obvious.
+
+### Example
+```
+let x = 5;
+match x {
+    1..=10 => println!("1 ... 10"),
+    5..=15 => println!("5 ... 15"),
+    _ => (),
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_ref_pats.txt b/src/tools/clippy/src/docs/match_ref_pats.txt
new file mode 100644 (file)
index 0000000..b1d9029
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for matches where all arms match a reference,
+suggesting to remove the reference and deref the matched expression
+instead. It also checks for `if let &foo = bar` blocks.
+
+### Why is this bad?
+It just makes the code less readable. That reference
+destructuring adds nothing to the code.
+
+### Example
+```
+match x {
+    &A(ref y) => foo(y),
+    &B => bar(),
+    _ => frob(&x),
+}
+```
+
+Use instead:
+```
+match *x {
+    A(ref y) => foo(y),
+    B => bar(),
+    _ => frob(x),
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_result_ok.txt b/src/tools/clippy/src/docs/match_result_ok.txt
new file mode 100644 (file)
index 0000000..eea7c8e
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for unnecessary `ok()` in `while let`.
+
+### Why is this bad?
+Calling `ok()` in `while let` is unnecessary, instead match
+on `Ok(pat)`
+
+### Example
+```
+while let Some(value) = iter.next().ok() {
+    vec.push(value)
+}
+
+if let Some(value) = iter.next().ok() {
+    vec.push(value)
+}
+```
+Use instead:
+```
+while let Ok(value) = iter.next() {
+    vec.push(value)
+}
+
+if let Ok(value) = iter.next() {
+       vec.push(value)
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_same_arms.txt b/src/tools/clippy/src/docs/match_same_arms.txt
new file mode 100644 (file)
index 0000000..14edf12
--- /dev/null
@@ -0,0 +1,38 @@
+### What it does
+Checks for `match` with identical arm bodies.
+
+### Why is this bad?
+This is probably a copy & paste error. If arm bodies
+are the same on purpose, you can factor them
+[using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
+
+### Known problems
+False positive possible with order dependent `match`
+(see issue
+[#860](https://github.com/rust-lang/rust-clippy/issues/860)).
+
+### Example
+```
+match foo {
+    Bar => bar(),
+    Quz => quz(),
+    Baz => bar(), // <= oops
+}
+```
+
+This should probably be
+```
+match foo {
+    Bar => bar(),
+    Quz => quz(),
+    Baz => baz(), // <= fixed
+}
+```
+
+or if the original code was not a typo:
+```
+match foo {
+    Bar | Baz => bar(), // <= shows the intent better
+    Quz => quz(),
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_single_binding.txt b/src/tools/clippy/src/docs/match_single_binding.txt
new file mode 100644 (file)
index 0000000..67ded0b
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for useless match that binds to only one value.
+
+### Why is this bad?
+Readability and needless complexity.
+
+### Known problems
+ Suggested replacements may be incorrect when `match`
+is actually binding temporary value, bringing a 'dropped while borrowed' error.
+
+### Example
+```
+match (a, b) {
+    (c, d) => {
+        // useless match
+    }
+}
+```
+
+Use instead:
+```
+let (c, d) = (a, b);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_str_case_mismatch.txt b/src/tools/clippy/src/docs/match_str_case_mismatch.txt
new file mode 100644 (file)
index 0000000..19e74c2
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for `match` expressions modifying the case of a string with non-compliant arms
+
+### Why is this bad?
+The arm is unreachable, which is likely a mistake
+
+### Example
+```
+match &*text.to_ascii_lowercase() {
+    "foo" => {},
+    "Bar" => {},
+    _ => {},
+}
+```
+Use instead:
+```
+match &*text.to_ascii_lowercase() {
+    "foo" => {},
+    "bar" => {},
+    _ => {},
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_wild_err_arm.txt b/src/tools/clippy/src/docs/match_wild_err_arm.txt
new file mode 100644 (file)
index 0000000..f89b3a2
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for arm which matches all errors with `Err(_)`
+and take drastic actions like `panic!`.
+
+### Why is this bad?
+It is generally a bad practice, similar to
+catching all exceptions in java with `catch(Exception)`
+
+### Example
+```
+let x: Result<i32, &str> = Ok(3);
+match x {
+    Ok(_) => println!("ok"),
+    Err(_) => panic!("err"),
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_wildcard_for_single_variants.txt b/src/tools/clippy/src/docs/match_wildcard_for_single_variants.txt
new file mode 100644 (file)
index 0000000..25559b9
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for wildcard enum matches for a single variant.
+
+### Why is this bad?
+New enum variants added by library updates can be missed.
+
+### Known problems
+Suggested replacements may not use correct path to enum
+if it's not present in the current scope.
+
+### Example
+```
+match x {
+    Foo::A => {},
+    Foo::B => {},
+    _ => {},
+}
+```
+
+Use instead:
+```
+match x {
+    Foo::A => {},
+    Foo::B => {},
+    Foo::C => {},
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/maybe_infinite_iter.txt b/src/tools/clippy/src/docs/maybe_infinite_iter.txt
new file mode 100644 (file)
index 0000000..1204a49
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for iteration that may be infinite.
+
+### Why is this bad?
+While there may be places where this is acceptable
+(e.g., in event streams), in most cases this is simply an error.
+
+### Known problems
+The code may have a condition to stop iteration, but
+this lint is not clever enough to analyze it.
+
+### Example
+```
+let infinite_iter = 0..;
+[0..].iter().zip(infinite_iter.take_while(|x| *x > 5));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mem_forget.txt b/src/tools/clippy/src/docs/mem_forget.txt
new file mode 100644 (file)
index 0000000..a6888c4
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for usage of `std::mem::forget(t)` where `t` is
+`Drop`.
+
+### Why is this bad?
+`std::mem::forget(t)` prevents `t` from running its
+destructor, possibly causing leaks.
+
+### Example
+```
+mem::forget(Rc::new(55))
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mem_replace_option_with_none.txt b/src/tools/clippy/src/docs/mem_replace_option_with_none.txt
new file mode 100644 (file)
index 0000000..7f243d1
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for `mem::replace()` on an `Option` with
+`None`.
+
+### Why is this bad?
+`Option` already has the method `take()` for
+taking its current value (Some(..) or None) and replacing it with
+`None`.
+
+### Example
+```
+use std::mem;
+
+let mut an_option = Some(0);
+let replaced = mem::replace(&mut an_option, None);
+```
+Is better expressed with:
+```
+let mut an_option = Some(0);
+let taken = an_option.take();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mem_replace_with_default.txt b/src/tools/clippy/src/docs/mem_replace_with_default.txt
new file mode 100644 (file)
index 0000000..24e0913
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for `std::mem::replace` on a value of type
+`T` with `T::default()`.
+
+### Why is this bad?
+`std::mem` module already has the method `take` to
+take the current value and replace it with the default value of that type.
+
+### Example
+```
+let mut text = String::from("foo");
+let replaced = std::mem::replace(&mut text, String::default());
+```
+Is better expressed with:
+```
+let mut text = String::from("foo");
+let taken = std::mem::take(&mut text);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mem_replace_with_uninit.txt b/src/tools/clippy/src/docs/mem_replace_with_uninit.txt
new file mode 100644 (file)
index 0000000..0bb4836
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for `mem::replace(&mut _, mem::uninitialized())`
+and `mem::replace(&mut _, mem::zeroed())`.
+
+### Why is this bad?
+This will lead to undefined behavior even if the
+value is overwritten later, because the uninitialized value may be
+observed in the case of a panic.
+
+### Example
+```
+use std::mem;
+
+#[allow(deprecated, invalid_value)]
+fn myfunc (v: &mut Vec<i32>) {
+    let taken_v = unsafe { mem::replace(v, mem::uninitialized()) };
+    let new_v = may_panic(taken_v); // undefined behavior on panic
+    mem::forget(mem::replace(v, new_v));
+}
+```
+
+The [take_mut](https://docs.rs/take_mut) crate offers a sound solution,
+at the cost of either lazily creating a replacement value or aborting
+on panic, to ensure that the uninitialized value cannot be observed.
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/min_max.txt b/src/tools/clippy/src/docs/min_max.txt
new file mode 100644 (file)
index 0000000..6acf0f9
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for expressions where `std::cmp::min` and `max` are
+used to clamp values, but switched so that the result is constant.
+
+### Why is this bad?
+This is in all probability not the intended outcome. At
+the least it hurts readability of the code.
+
+### Example
+```
+min(0, max(100, x))
+
+// or
+
+x.max(100).min(0)
+```
+It will always be equal to `0`. Probably the author meant to clamp the value
+between 0 and 100, but has erroneously swapped `min` and `max`.
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mismatched_target_os.txt b/src/tools/clippy/src/docs/mismatched_target_os.txt
new file mode 100644 (file)
index 0000000..51e5ec6
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for cfg attributes having operating systems used in target family position.
+
+### Why is this bad?
+The configuration option will not be recognised and the related item will not be included
+by the conditional compilation engine.
+
+### Example
+```
+#[cfg(linux)]
+fn conditional() { }
+```
+
+Use instead:
+```
+#[cfg(target_os = "linux")]
+fn conditional() { }
+
+// or
+
+#[cfg(unix)]
+fn conditional() { }
+```
+Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details.
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mismatching_type_param_order.txt b/src/tools/clippy/src/docs/mismatching_type_param_order.txt
new file mode 100644 (file)
index 0000000..ffc7f32
--- /dev/null
@@ -0,0 +1,33 @@
+### What it does
+Checks for type parameters which are positioned inconsistently between
+a type definition and impl block. Specifically, a parameter in an impl
+block which has the same name as a parameter in the type def, but is in
+a different place.
+
+### Why is this bad?
+Type parameters are determined by their position rather than name.
+Naming type parameters inconsistently may cause you to refer to the
+wrong type parameter.
+
+### Limitations
+This lint only applies to impl blocks with simple generic params, e.g.
+`A`. If there is anything more complicated, such as a tuple, it will be
+ignored.
+
+### Example
+```
+struct Foo<A, B> {
+    x: A,
+    y: B,
+}
+// inside the impl, B refers to Foo::A
+impl<B, A> Foo<B, A> {}
+```
+Use instead:
+```
+struct Foo<A, B> {
+    x: A,
+    y: B,
+}
+impl<A, B> Foo<A, B> {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/misrefactored_assign_op.txt b/src/tools/clippy/src/docs/misrefactored_assign_op.txt
new file mode 100644 (file)
index 0000000..3d691fe
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for `a op= a op b` or `a op= b op a` patterns.
+
+### Why is this bad?
+Most likely these are bugs where one meant to write `a
+op= b`.
+
+### Known problems
+Clippy cannot know for sure if `a op= a op b` should have
+been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both.
+If `a op= a op b` is really the correct behavior it should be
+written as `a = a op a op b` as it's less confusing.
+
+### Example
+```
+let mut a = 5;
+let b = 2;
+// ...
+a += a + b;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_const_for_fn.txt b/src/tools/clippy/src/docs/missing_const_for_fn.txt
new file mode 100644 (file)
index 0000000..067614d
--- /dev/null
@@ -0,0 +1,40 @@
+### What it does
+Suggests the use of `const` in functions and methods where possible.
+
+### Why is this bad?
+Not having the function const prevents callers of the function from being const as well.
+
+### Known problems
+Const functions are currently still being worked on, with some features only being available
+on nightly. This lint does not consider all edge cases currently and the suggestions may be
+incorrect if you are using this lint on stable.
+
+Also, the lint only runs one pass over the code. Consider these two non-const functions:
+
+```
+fn a() -> i32 {
+    0
+}
+fn b() -> i32 {
+    a()
+}
+```
+
+When running Clippy, the lint will only suggest to make `a` const, because `b` at this time
+can't be const as it calls a non-const function. Making `a` const and running Clippy again,
+will suggest to make `b` const, too.
+
+### Example
+```
+fn new() -> Self {
+    Self { random_number: 42 }
+}
+```
+
+Could be a const fn:
+
+```
+const fn new() -> Self {
+    Self { random_number: 42 }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_docs_in_private_items.txt b/src/tools/clippy/src/docs/missing_docs_in_private_items.txt
new file mode 100644 (file)
index 0000000..5d37505
--- /dev/null
@@ -0,0 +1,9 @@
+### What it does
+Warns if there is missing doc for any documentable item
+(public or private).
+
+### Why is this bad?
+Doc is good. *rustc* has a `MISSING_DOCS`
+allowed-by-default lint for
+public members, but has no way to enforce documentation of private items.
+This lint fixes that.
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_enforced_import_renames.txt b/src/tools/clippy/src/docs/missing_enforced_import_renames.txt
new file mode 100644 (file)
index 0000000..8f4649b
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for imports that do not rename the item as specified
+in the `enforce-import-renames` config option.
+
+### Why is this bad?
+Consistency is important, if a project has defined import
+renames they should be followed. More practically, some item names are too
+vague outside of their defining scope this can enforce a more meaningful naming.
+
+### Example
+An example clippy.toml configuration:
+```
+enforced-import-renames = [ { path = "serde_json::Value", rename = "JsonValue" }]
+```
+
+```
+use serde_json::Value;
+```
+Use instead:
+```
+use serde_json::Value as JsonValue;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_errors_doc.txt b/src/tools/clippy/src/docs/missing_errors_doc.txt
new file mode 100644 (file)
index 0000000..028778d
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks the doc comments of publicly visible functions that
+return a `Result` type and warns if there is no `# Errors` section.
+
+### Why is this bad?
+Documenting the type of errors that can be returned from a
+function can help callers write code to handle the errors appropriately.
+
+### Examples
+Since the following function returns a `Result` it has an `# Errors` section in
+its doc comment:
+
+```
+/// # Errors
+///
+/// Will return `Err` if `filename` does not exist or the user does not have
+/// permission to read it.
+pub fn read(filename: String) -> io::Result<String> {
+    unimplemented!();
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_inline_in_public_items.txt b/src/tools/clippy/src/docs/missing_inline_in_public_items.txt
new file mode 100644 (file)
index 0000000..d90c50f
--- /dev/null
@@ -0,0 +1,45 @@
+### What it does
+It lints if an exported function, method, trait method with default impl,
+or trait method impl is not `#[inline]`.
+
+### Why is this bad?
+In general, it is not. Functions can be inlined across
+crates when that's profitable as long as any form of LTO is used. When LTO is disabled,
+functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates
+might intend for most of the methods in their public API to be able to be inlined across
+crates even when LTO is disabled. For these types of crates, enabling this lint might make
+sense. It allows the crate to require all exported methods to be `#[inline]` by default, and
+then opt out for specific methods where this might not make sense.
+
+### Example
+```
+pub fn foo() {} // missing #[inline]
+fn ok() {} // ok
+#[inline] pub fn bar() {} // ok
+#[inline(always)] pub fn baz() {} // ok
+
+pub trait Bar {
+  fn bar(); // ok
+  fn def_bar() {} // missing #[inline]
+}
+
+struct Baz;
+impl Baz {
+   fn private() {} // ok
+}
+
+impl Bar for Baz {
+  fn bar() {} // ok - Baz is not exported
+}
+
+pub struct PubBaz;
+impl PubBaz {
+   fn private() {} // ok
+   pub fn not_private() {} // missing #[inline]
+}
+
+impl Bar for PubBaz {
+   fn bar() {} // missing #[inline]
+   fn def_bar() {} // missing #[inline]
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_panics_doc.txt b/src/tools/clippy/src/docs/missing_panics_doc.txt
new file mode 100644 (file)
index 0000000..e5e39a8
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks the doc comments of publicly visible functions that
+may panic and warns if there is no `# Panics` section.
+
+### Why is this bad?
+Documenting the scenarios in which panicking occurs
+can help callers who do not want to panic to avoid those situations.
+
+### Examples
+Since the following function may panic it has a `# Panics` section in
+its doc comment:
+
+```
+/// # Panics
+///
+/// Will panic if y is 0
+pub fn divide_by(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        panic!("Cannot divide by 0")
+    } else {
+        x / y
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_safety_doc.txt b/src/tools/clippy/src/docs/missing_safety_doc.txt
new file mode 100644 (file)
index 0000000..6492eb8
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for the doc comments of publicly visible
+unsafe functions and warns if there is no `# Safety` section.
+
+### Why is this bad?
+Unsafe functions should document their safety
+preconditions, so that users can be sure they are using them safely.
+
+### Examples
+```
+/// This function should really be documented
+pub unsafe fn start_apocalypse(u: &mut Universe) {
+    unimplemented!();
+}
+```
+
+At least write a line about safety:
+
+```
+/// # Safety
+///
+/// This function should not be called before the horsemen are ready.
+pub unsafe fn start_apocalypse(u: &mut Universe) {
+    unimplemented!();
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_spin_loop.txt b/src/tools/clippy/src/docs/missing_spin_loop.txt
new file mode 100644 (file)
index 0000000..3a06a91
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Check for empty spin loops
+
+### Why is this bad?
+The loop body should have something like `thread::park()` or at least
+`std::hint::spin_loop()` to avoid needlessly burning cycles and conserve
+energy. Perhaps even better use an actual lock, if possible.
+
+### Known problems
+This lint doesn't currently trigger on `while let` or
+`loop { match .. { .. } }` loops, which would be considered idiomatic in
+combination with e.g. `AtomicBool::compare_exchange_weak`.
+
+### Example
+
+```
+use core::sync::atomic::{AtomicBool, Ordering};
+let b = AtomicBool::new(true);
+// give a ref to `b` to another thread,wait for it to become false
+while b.load(Ordering::Acquire) {};
+```
+Use instead:
+```
+while b.load(Ordering::Acquire) {
+    std::hint::spin_loop()
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mistyped_literal_suffixes.txt b/src/tools/clippy/src/docs/mistyped_literal_suffixes.txt
new file mode 100644 (file)
index 0000000..1760fcb
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Warns for mistyped suffix in literals
+
+### Why is this bad?
+This is most probably a typo
+
+### Known problems
+- Does not match on integers too large to fit in the corresponding unsigned type
+- Does not match on `_127` since that is a valid grouping for decimal and octal numbers
+
+### Example
+```
+`2_32` => `2_i32`
+`250_8 => `250_u8`
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mixed_case_hex_literals.txt b/src/tools/clippy/src/docs/mixed_case_hex_literals.txt
new file mode 100644 (file)
index 0000000..d2d01e0
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Warns on hexadecimal literals with mixed-case letter
+digits.
+
+### Why is this bad?
+It looks confusing.
+
+### Example
+```
+0x1a9BAcD
+```
+
+Use instead:
+```
+0x1A9BACD
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mixed_read_write_in_expression.txt b/src/tools/clippy/src/docs/mixed_read_write_in_expression.txt
new file mode 100644 (file)
index 0000000..02d1c5d
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Checks for a read and a write to the same variable where
+whether the read occurs before or after the write depends on the evaluation
+order of sub-expressions.
+
+### Why is this bad?
+It is often confusing to read. As described [here](https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands),
+the operands of these expressions are evaluated before applying the effects of the expression.
+
+### Known problems
+Code which intentionally depends on the evaluation
+order, or which is correct for any evaluation order.
+
+### Example
+```
+let mut x = 0;
+
+let a = {
+    x = 1;
+    1
+} + x;
+// Unclear whether a is 1 or 2.
+```
+
+Use instead:
+```
+let tmp = {
+    x = 1;
+    1
+};
+let a = tmp + x;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mod_module_files.txt b/src/tools/clippy/src/docs/mod_module_files.txt
new file mode 100644 (file)
index 0000000..95bca58
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks that module layout uses only self named module files, bans `mod.rs` files.
+
+### Why is this bad?
+Having multiple module layout styles in a project can be confusing.
+
+### Example
+```
+src/
+  stuff/
+    stuff_files.rs
+    mod.rs
+  lib.rs
+```
+Use instead:
+```
+src/
+  stuff/
+    stuff_files.rs
+  stuff.rs
+  lib.rs
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/module_inception.txt b/src/tools/clippy/src/docs/module_inception.txt
new file mode 100644 (file)
index 0000000..d80a1b8
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for modules that have the same name as their
+parent module
+
+### Why is this bad?
+A typical beginner mistake is to have `mod foo;` and
+again `mod foo { ..
+}` in `foo.rs`.
+The expectation is that items inside the inner `mod foo { .. }` are then
+available
+through `foo::x`, but they are only available through
+`foo::foo::x`.
+If this is done on purpose, it would be better to choose a more
+representative module name.
+
+### Example
+```
+// lib.rs
+mod foo;
+// foo.rs
+mod foo {
+    ...
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/module_name_repetitions.txt b/src/tools/clippy/src/docs/module_name_repetitions.txt
new file mode 100644 (file)
index 0000000..3bc05d0
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Detects type names that are prefixed or suffixed by the
+containing module's name.
+
+### Why is this bad?
+It requires the user to type the module name twice.
+
+### Example
+```
+mod cake {
+    struct BlackForestCake;
+}
+```
+
+Use instead:
+```
+mod cake {
+    struct BlackForest;
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/modulo_arithmetic.txt b/src/tools/clippy/src/docs/modulo_arithmetic.txt
new file mode 100644 (file)
index 0000000..ff7296f
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for modulo arithmetic.
+
+### Why is this bad?
+The results of modulo (%) operation might differ
+depending on the language, when negative numbers are involved.
+If you interop with different languages it might be beneficial
+to double check all places that use modulo arithmetic.
+
+For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`.
+
+### Example
+```
+let x = -17 % 3;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/modulo_one.txt b/src/tools/clippy/src/docs/modulo_one.txt
new file mode 100644 (file)
index 0000000..bc8f95b
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for getting the remainder of a division by one or minus
+one.
+
+### Why is this bad?
+The result for a divisor of one can only ever be zero; for
+minus one it can cause panic/overflow (if the left operand is the minimal value of
+the respective integer type) or results in zero. No one will write such code
+deliberately, unless trying to win an Underhanded Rust Contest. Even for that
+contest, it's probably a bad idea. Use something more underhanded.
+
+### Example
+```
+let a = x % 1;
+let a = x % -1;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/multi_assignments.txt b/src/tools/clippy/src/docs/multi_assignments.txt
new file mode 100644 (file)
index 0000000..ed1f1b4
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for nested assignments.
+
+### Why is this bad?
+While this is in most cases already a type mismatch,
+the result of an assignment being `()` can throw off people coming from languages like python or C,
+where such assignments return a copy of the assigned value.
+
+### Example
+```
+a = b = 42;
+```
+Use instead:
+```
+b = 42;
+a = b;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/multiple_crate_versions.txt b/src/tools/clippy/src/docs/multiple_crate_versions.txt
new file mode 100644 (file)
index 0000000..cf2d2c6
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks to see if multiple versions of a crate are being
+used.
+
+### Why is this bad?
+This bloats the size of targets, and can lead to
+confusing error messages when structs or traits are used interchangeably
+between different versions of a crate.
+
+### Known problems
+Because this can be caused purely by the dependencies
+themselves, it's not always possible to fix this issue.
+
+### Example
+```
+[dependencies]
+ctrlc = "=3.1.0"
+ansi_term = "=0.11.0"
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/multiple_inherent_impl.txt b/src/tools/clippy/src/docs/multiple_inherent_impl.txt
new file mode 100644 (file)
index 0000000..9d42286
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for multiple inherent implementations of a struct
+
+### Why is this bad?
+Splitting the implementation of a type makes the code harder to navigate.
+
+### Example
+```
+struct X;
+impl X {
+    fn one() {}
+}
+impl X {
+    fn other() {}
+}
+```
+
+Could be written:
+
+```
+struct X;
+impl X {
+    fn one() {}
+    fn other() {}
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/must_use_candidate.txt b/src/tools/clippy/src/docs/must_use_candidate.txt
new file mode 100644 (file)
index 0000000..7089034
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for public functions that have no
+`#[must_use]` attribute, but return something not already marked
+must-use, have no mutable arg and mutate no statics.
+
+### Why is this bad?
+Not bad at all, this lint just shows places where
+you could add the attribute.
+
+### Known problems
+The lint only checks the arguments for mutable
+types without looking if they are actually changed. On the other hand,
+it also ignores a broad range of potentially interesting side effects,
+because we cannot decide whether the programmer intends the function to
+be called for the side effect or the result. Expect many false
+positives. At least we don't lint if the result type is unit or already
+`#[must_use]`.
+
+### Examples
+```
+// this could be annotated with `#[must_use]`.
+fn id<T>(t: T) -> T { t }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/must_use_unit.txt b/src/tools/clippy/src/docs/must_use_unit.txt
new file mode 100644 (file)
index 0000000..cabbb23
--- /dev/null
@@ -0,0 +1,13 @@
+### What it does
+Checks for a `#[must_use]` attribute on
+unit-returning functions and methods.
+
+### Why is this bad?
+Unit values are useless. The attribute is likely
+a remnant of a refactoring that removed the return type.
+
+### Examples
+```
+#[must_use]
+fn useless() { }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mut_from_ref.txt b/src/tools/clippy/src/docs/mut_from_ref.txt
new file mode 100644 (file)
index 0000000..cc1da12
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+This lint checks for functions that take immutable references and return
+mutable ones. This will not trigger if no unsafe code exists as there
+are multiple safe functions which will do this transformation
+
+To be on the conservative side, if there's at least one mutable
+reference with the output lifetime, this lint will not trigger.
+
+### Why is this bad?
+Creating a mutable reference which can be repeatably derived from an
+immutable reference is unsound as it allows creating multiple live
+mutable references to the same object.
+
+This [error](https://github.com/rust-lang/rust/issues/39465) actually
+lead to an interim Rust release 1.15.1.
+
+### Known problems
+This pattern is used by memory allocators to allow allocating multiple
+objects while returning mutable references to each one. So long as
+different mutable references are returned each time such a function may
+be safe.
+
+### Example
+```
+fn foo(&Foo) -> &mut Bar { .. }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mut_mut.txt b/src/tools/clippy/src/docs/mut_mut.txt
new file mode 100644 (file)
index 0000000..0bd34dd
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for instances of `mut mut` references.
+
+### Why is this bad?
+Multiple `mut`s don't add anything meaningful to the
+source. This is either a copy'n'paste error, or it shows a fundamental
+misunderstanding of references.
+
+### Example
+```
+let x = &mut &mut y;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mut_mutex_lock.txt b/src/tools/clippy/src/docs/mut_mutex_lock.txt
new file mode 100644 (file)
index 0000000..5e9ad8a
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for `&mut Mutex::lock` calls
+
+### Why is this bad?
+`Mutex::lock` is less efficient than
+calling `Mutex::get_mut`. In addition you also have a statically
+guarantee that the mutex isn't locked, instead of just a runtime
+guarantee.
+
+### Example
+```
+use std::sync::{Arc, Mutex};
+
+let mut value_rc = Arc::new(Mutex::new(42_u8));
+let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
+
+let mut value = value_mutex.lock().unwrap();
+*value += 1;
+```
+Use instead:
+```
+use std::sync::{Arc, Mutex};
+
+let mut value_rc = Arc::new(Mutex::new(42_u8));
+let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
+
+let value = value_mutex.get_mut().unwrap();
+*value += 1;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mut_range_bound.txt b/src/tools/clippy/src/docs/mut_range_bound.txt
new file mode 100644 (file)
index 0000000..e9c38a5
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for loops which have a range bound that is a mutable variable
+
+### Why is this bad?
+One might think that modifying the mutable variable changes the loop bounds
+
+### Known problems
+False positive when mutation is followed by a `break`, but the `break` is not immediately
+after the mutation:
+
+```
+let mut x = 5;
+for _ in 0..x {
+    x += 1; // x is a range bound that is mutated
+    ..; // some other expression
+    break; // leaves the loop, so mutation is not an issue
+}
+```
+
+False positive on nested loops ([#6072](https://github.com/rust-lang/rust-clippy/issues/6072))
+
+### Example
+```
+let mut foo = 42;
+for i in 0..foo {
+    foo -= 1;
+    println!("{}", i); // prints numbers from 0 to 42, not 0 to 21
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mutable_key_type.txt b/src/tools/clippy/src/docs/mutable_key_type.txt
new file mode 100644 (file)
index 0000000..15fe34f
--- /dev/null
@@ -0,0 +1,61 @@
+### What it does
+Checks for sets/maps with mutable key types.
+
+### Why is this bad?
+All of `HashMap`, `HashSet`, `BTreeMap` and
+`BtreeSet` rely on either the hash or the order of keys be unchanging,
+so having types with interior mutability is a bad idea.
+
+### Known problems
+
+#### False Positives
+It's correct to use a struct that contains interior mutability as a key, when its
+implementation of `Hash` or `Ord` doesn't access any of the interior mutable types.
+However, this lint is unable to recognize this, so it will often cause false positives in
+theses cases.  The `bytes` crate is a great example of this.
+
+#### False Negatives
+For custom `struct`s/`enum`s, this lint is unable to check for interior mutability behind
+indirection.  For example, `struct BadKey<'a>(&'a Cell<usize>)` will be seen as immutable
+and cause a false negative if its implementation of `Hash`/`Ord` accesses the `Cell`.
+
+This lint does check a few cases for indirection.  Firstly, using some standard library
+types (`Option`, `Result`, `Box`, `Rc`, `Arc`, `Vec`, `VecDeque`, `BTreeMap` and
+`BTreeSet`) directly as keys (e.g. in `HashMap<Box<Cell<usize>>, ()>`) **will** trigger the
+lint, because the impls of `Hash`/`Ord` for these types directly call `Hash`/`Ord` on their
+contained type.
+
+Secondly, the implementations of `Hash` and `Ord` for raw pointers (`*const T` or `*mut T`)
+apply only to the **address** of the contained value.  Therefore, interior mutability
+behind raw pointers (e.g. in `HashSet<*mut Cell<usize>>`) can't impact the value of `Hash`
+or `Ord`, and therefore will not trigger this link.  For more info, see issue
+[#6745](https://github.com/rust-lang/rust-clippy/issues/6745).
+
+### Example
+```
+use std::cmp::{PartialEq, Eq};
+use std::collections::HashSet;
+use std::hash::{Hash, Hasher};
+use std::sync::atomic::AtomicUsize;
+
+struct Bad(AtomicUsize);
+impl PartialEq for Bad {
+    fn eq(&self, rhs: &Self) -> bool {
+         ..
+; unimplemented!();
+    }
+}
+
+impl Eq for Bad {}
+
+impl Hash for Bad {
+    fn hash<H: Hasher>(&self, h: &mut H) {
+        ..
+; unimplemented!();
+    }
+}
+
+fn main() {
+    let _: HashSet<Bad> = HashSet::new();
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mutex_atomic.txt b/src/tools/clippy/src/docs/mutex_atomic.txt
new file mode 100644 (file)
index 0000000..062ac8b
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for usages of `Mutex<X>` where an atomic will do.
+
+### Why is this bad?
+Using a mutex just to make access to a plain bool or
+reference sequential is shooting flies with cannons.
+`std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and
+faster.
+
+### Known problems
+This lint cannot detect if the mutex is actually used
+for waiting before a critical section.
+
+### Example
+```
+let x = Mutex::new(&y);
+```
+
+Use instead:
+```
+let x = AtomicBool::new(y);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mutex_integer.txt b/src/tools/clippy/src/docs/mutex_integer.txt
new file mode 100644 (file)
index 0000000..f9dbdfb
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for usages of `Mutex<X>` where `X` is an integral
+type.
+
+### Why is this bad?
+Using a mutex just to make access to a plain integer
+sequential is
+shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster.
+
+### Known problems
+This lint cannot detect if the mutex is actually used
+for waiting before a critical section.
+
+### Example
+```
+let x = Mutex::new(0usize);
+```
+
+Use instead:
+```
+let x = AtomicUsize::new(0usize);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/naive_bytecount.txt b/src/tools/clippy/src/docs/naive_bytecount.txt
new file mode 100644 (file)
index 0000000..24659dc
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for naive byte counts
+
+### Why is this bad?
+The [`bytecount`](https://crates.io/crates/bytecount)
+crate has methods to count your bytes faster, especially for large slices.
+
+### Known problems
+If you have predominantly small slices, the
+`bytecount::count(..)` method may actually be slower. However, if you can
+ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
+faster in those cases.
+
+### Example
+```
+let count = vec.iter().filter(|x| **x == 0u8).count();
+```
+
+Use instead:
+```
+let count = bytecount::count(&vec, 0u8);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_arbitrary_self_type.txt b/src/tools/clippy/src/docs/needless_arbitrary_self_type.txt
new file mode 100644 (file)
index 0000000..8216a3a
--- /dev/null
@@ -0,0 +1,44 @@
+### What it does
+The lint checks for `self` in fn parameters that
+specify the `Self`-type explicitly
+### Why is this bad?
+Increases the amount and decreases the readability of code
+
+### Example
+```
+enum ValType {
+    I32,
+    I64,
+    F32,
+    F64,
+}
+
+impl ValType {
+    pub fn bytes(self: Self) -> usize {
+        match self {
+            Self::I32 | Self::F32 => 4,
+            Self::I64 | Self::F64 => 8,
+        }
+    }
+}
+```
+
+Could be rewritten as
+
+```
+enum ValType {
+    I32,
+    I64,
+    F32,
+    F64,
+}
+
+impl ValType {
+    pub fn bytes(self) -> usize {
+        match self {
+            Self::I32 | Self::F32 => 4,
+            Self::I64 | Self::F64 => 8,
+        }
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_bitwise_bool.txt b/src/tools/clippy/src/docs/needless_bitwise_bool.txt
new file mode 100644 (file)
index 0000000..fcd7b73
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using
+a lazy and.
+
+### Why is this bad?
+The bitwise operators do not support short-circuiting, so it may hinder code performance.
+Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold`
+
+### Known problems
+This lint evaluates only when the right side is determined to have no side effects. At this time, that
+determination is quite conservative.
+
+### Example
+```
+let (x,y) = (true, false);
+if x & !y {} // where both x and y are booleans
+```
+Use instead:
+```
+let (x,y) = (true, false);
+if x && !y {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_bool.txt b/src/tools/clippy/src/docs/needless_bool.txt
new file mode 100644 (file)
index 0000000..b5c7887
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for expressions of the form `if c { true } else {
+false }` (or vice versa) and suggests using the condition directly.
+
+### Why is this bad?
+Redundant code.
+
+### Known problems
+Maybe false positives: Sometimes, the two branches are
+painstakingly documented (which we, of course, do not detect), so they *may*
+have some value. Even then, the documentation can be rewritten to match the
+shorter code.
+
+### Example
+```
+if x {
+    false
+} else {
+    true
+}
+```
+
+Use instead:
+```
+!x
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_borrow.txt b/src/tools/clippy/src/docs/needless_borrow.txt
new file mode 100644 (file)
index 0000000..4debcf4
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for address of operations (`&`) that are going to
+be dereferenced immediately by the compiler.
+
+### Why is this bad?
+Suggests that the receiver of the expression borrows
+the expression.
+
+### Example
+```
+fn fun(_a: &i32) {}
+
+let x: &i32 = &&&&&&5;
+fun(&x);
+```
+
+Use instead:
+```
+let x: &i32 = &5;
+fun(x);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_borrowed_reference.txt b/src/tools/clippy/src/docs/needless_borrowed_reference.txt
new file mode 100644 (file)
index 0000000..55faa0c
--- /dev/null
@@ -0,0 +1,30 @@
+### What it does
+Checks for bindings that destructure a reference and borrow the inner
+value with `&ref`.
+
+### Why is this bad?
+This pattern has no effect in almost all cases.
+
+### Known problems
+In some cases, `&ref` is needed to avoid a lifetime mismatch error.
+Example:
+```
+fn foo(a: &Option<String>, b: &Option<String>) {
+    match (a, b) {
+        (None, &ref c) | (&ref c, None) => (),
+        (&Some(ref c), _) => (),
+    };
+}
+```
+
+### Example
+```
+let mut v = Vec::<String>::new();
+v.iter_mut().filter(|&ref a| a.is_empty());
+```
+
+Use instead:
+```
+let mut v = Vec::<String>::new();
+v.iter_mut().filter(|a| a.is_empty());
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_collect.txt b/src/tools/clippy/src/docs/needless_collect.txt
new file mode 100644 (file)
index 0000000..275c39a
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for functions collecting an iterator when collect
+is not needed.
+
+### Why is this bad?
+`collect` causes the allocation of a new data structure,
+when this allocation may not be needed.
+
+### Example
+```
+let len = iterator.clone().collect::<Vec<_>>().len();
+// should be
+let len = iterator.count();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_continue.txt b/src/tools/clippy/src/docs/needless_continue.txt
new file mode 100644 (file)
index 0000000..2cee621
--- /dev/null
@@ -0,0 +1,61 @@
+### What it does
+The lint checks for `if`-statements appearing in loops
+that contain a `continue` statement in either their main blocks or their
+`else`-blocks, when omitting the `else`-block possibly with some
+rearrangement of code can make the code easier to understand.
+
+### Why is this bad?
+Having explicit `else` blocks for `if` statements
+containing `continue` in their THEN branch adds unnecessary branching and
+nesting to the code. Having an else block containing just `continue` can
+also be better written by grouping the statements following the whole `if`
+statement within the THEN block and omitting the else block completely.
+
+### Example
+```
+while condition() {
+    update_condition();
+    if x {
+        // ...
+    } else {
+        continue;
+    }
+    println!("Hello, world");
+}
+```
+
+Could be rewritten as
+
+```
+while condition() {
+    update_condition();
+    if x {
+        // ...
+        println!("Hello, world");
+    }
+}
+```
+
+As another example, the following code
+
+```
+loop {
+    if waiting() {
+        continue;
+    } else {
+        // Do something useful
+    }
+    # break;
+}
+```
+Could be rewritten as
+
+```
+loop {
+    if waiting() {
+        continue;
+    }
+    // Do something useful
+    # break;
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_doctest_main.txt b/src/tools/clippy/src/docs/needless_doctest_main.txt
new file mode 100644 (file)
index 0000000..8f91a7b
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for `fn main() { .. }` in doctests
+
+### Why is this bad?
+The test can be shorter (and likely more readable)
+if the `fn main()` is left implicit.
+
+### Examples
+```
+/// An example of a doctest with a `main()` function
+///
+/// # Examples
+///
+/// ```
+/// fn main() {
+///     // this needs not be in an `fn`
+/// }
+/// ```
+fn needless_main() {
+    unimplemented!();
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_for_each.txt b/src/tools/clippy/src/docs/needless_for_each.txt
new file mode 100644 (file)
index 0000000..9ae6dd3
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for usage of `for_each` that would be more simply written as a
+`for` loop.
+
+### Why is this bad?
+`for_each` may be used after applying iterator transformers like
+`filter` for better readability and performance. It may also be used to fit a simple
+operation on one line.
+But when none of these apply, a simple `for` loop is more idiomatic.
+
+### Example
+```
+let v = vec![0, 1, 2];
+v.iter().for_each(|elem| {
+    println!("{}", elem);
+})
+```
+Use instead:
+```
+let v = vec![0, 1, 2];
+for elem in v.iter() {
+    println!("{}", elem);
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_late_init.txt b/src/tools/clippy/src/docs/needless_late_init.txt
new file mode 100644 (file)
index 0000000..9e7bbce
--- /dev/null
@@ -0,0 +1,42 @@
+### What it does
+Checks for late initializations that can be replaced by a `let` statement
+with an initializer.
+
+### Why is this bad?
+Assigning in the `let` statement is less repetitive.
+
+### Example
+```
+let a;
+a = 1;
+
+let b;
+match 3 {
+    0 => b = "zero",
+    1 => b = "one",
+    _ => b = "many",
+}
+
+let c;
+if true {
+    c = 1;
+} else {
+    c = -1;
+}
+```
+Use instead:
+```
+let a = 1;
+
+let b = match 3 {
+    0 => "zero",
+    1 => "one",
+    _ => "many",
+};
+
+let c = if true {
+    1
+} else {
+    -1
+};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_lifetimes.txt b/src/tools/clippy/src/docs/needless_lifetimes.txt
new file mode 100644 (file)
index 0000000..b280caa
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for lifetime annotations which can be removed by
+relying on lifetime elision.
+
+### Why is this bad?
+The additional lifetimes make the code look more
+complicated, while there is nothing out of the ordinary going on. Removing
+them leads to more readable code.
+
+### Known problems
+- We bail out if the function has a `where` clause where lifetimes
+are mentioned due to potential false positives.
+- Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the
+placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`.
+
+### Example
+```
+// Unnecessary lifetime annotations
+fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 {
+    x
+}
+```
+
+Use instead:
+```
+fn elided(x: &u8, y: u8) -> &u8 {
+    x
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_match.txt b/src/tools/clippy/src/docs/needless_match.txt
new file mode 100644 (file)
index 0000000..92b40a5
--- /dev/null
@@ -0,0 +1,36 @@
+### What it does
+Checks for unnecessary `match` or match-like `if let` returns for `Option` and `Result`
+when function signatures are the same.
+
+### Why is this bad?
+This `match` block does nothing and might not be what the coder intended.
+
+### Example
+```
+fn foo() -> Result<(), i32> {
+    match result {
+        Ok(val) => Ok(val),
+        Err(err) => Err(err),
+    }
+}
+
+fn bar() -> Option<i32> {
+    if let Some(val) = option {
+        Some(val)
+    } else {
+        None
+    }
+}
+```
+
+Could be replaced as
+
+```
+fn foo() -> Result<(), i32> {
+    result
+}
+
+fn bar() -> Option<i32> {
+    option
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_option_as_deref.txt b/src/tools/clippy/src/docs/needless_option_as_deref.txt
new file mode 100644 (file)
index 0000000..226396c
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for no-op uses of `Option::{as_deref, as_deref_mut}`,
+for example, `Option<&T>::as_deref()` returns the same type.
+
+### Why is this bad?
+Redundant code and improving readability.
+
+### Example
+```
+let a = Some(&1);
+let b = a.as_deref(); // goes from Option<&i32> to Option<&i32>
+```
+
+Use instead:
+```
+let a = Some(&1);
+let b = a;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_option_take.txt b/src/tools/clippy/src/docs/needless_option_take.txt
new file mode 100644 (file)
index 0000000..6bac65a
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for calling `take` function after `as_ref`.
+
+### Why is this bad?
+Redundant code. `take` writes `None` to its argument.
+In this case the modification is useless as it's a temporary that cannot be read from afterwards.
+
+### Example
+```
+let x = Some(3);
+x.as_ref().take();
+```
+Use instead:
+```
+let x = Some(3);
+x.as_ref();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_parens_on_range_literals.txt b/src/tools/clippy/src/docs/needless_parens_on_range_literals.txt
new file mode 100644 (file)
index 0000000..85fab10
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+The lint checks for parenthesis on literals in range statements that are
+superfluous.
+
+### Why is this bad?
+Having superfluous parenthesis makes the code less readable
+overhead when reading.
+
+### Example
+
+```
+for i in (0)..10 {
+  println!("{i}");
+}
+```
+
+Use instead:
+
+```
+for i in 0..10 {
+  println!("{i}");
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_pass_by_value.txt b/src/tools/clippy/src/docs/needless_pass_by_value.txt
new file mode 100644 (file)
index 0000000..58c420b
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for functions taking arguments by value, but not
+consuming them in its
+body.
+
+### Why is this bad?
+Taking arguments by reference is more flexible and can
+sometimes avoid
+unnecessary allocations.
+
+### Known problems
+* This lint suggests taking an argument by reference,
+however sometimes it is better to let users decide the argument type
+(by using `Borrow` trait, for example), depending on how the function is used.
+
+### Example
+```
+fn foo(v: Vec<i32>) {
+    assert_eq!(v.len(), 42);
+}
+```
+should be
+```
+fn foo(v: &[i32]) {
+    assert_eq!(v.len(), 42);
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_question_mark.txt b/src/tools/clippy/src/docs/needless_question_mark.txt
new file mode 100644 (file)
index 0000000..540739f
--- /dev/null
@@ -0,0 +1,43 @@
+### What it does
+Suggests alternatives for useless applications of `?` in terminating expressions
+
+### Why is this bad?
+There's no reason to use `?` to short-circuit when execution of the body will end there anyway.
+
+### Example
+```
+struct TO {
+    magic: Option<usize>,
+}
+
+fn f(to: TO) -> Option<usize> {
+    Some(to.magic?)
+}
+
+struct TR {
+    magic: Result<usize, bool>,
+}
+
+fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
+    tr.and_then(|t| Ok(t.magic?))
+}
+
+```
+Use instead:
+```
+struct TO {
+    magic: Option<usize>,
+}
+
+fn f(to: TO) -> Option<usize> {
+   to.magic
+}
+
+struct TR {
+    magic: Result<usize, bool>,
+}
+
+fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
+    tr.and_then(|t| t.magic)
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_range_loop.txt b/src/tools/clippy/src/docs/needless_range_loop.txt
new file mode 100644 (file)
index 0000000..583c09b
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for looping over the range of `0..len` of some
+collection just to get the values by index.
+
+### Why is this bad?
+Just iterating the collection itself makes the intent
+more clear and is probably faster.
+
+### Example
+```
+let vec = vec!['a', 'b', 'c'];
+for i in 0..vec.len() {
+    println!("{}", vec[i]);
+}
+```
+
+Use instead:
+```
+let vec = vec!['a', 'b', 'c'];
+for i in vec {
+    println!("{}", i);
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_return.txt b/src/tools/clippy/src/docs/needless_return.txt
new file mode 100644 (file)
index 0000000..48782cb
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for return statements at the end of a block.
+
+### Why is this bad?
+Removing the `return` and semicolon will make the code
+more rusty.
+
+### Example
+```
+fn foo(x: usize) -> usize {
+    return x;
+}
+```
+simplify to
+```
+fn foo(x: usize) -> usize {
+    x
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_splitn.txt b/src/tools/clippy/src/docs/needless_splitn.txt
new file mode 100644 (file)
index 0000000..b10a84f
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same.
+### Why is this bad?
+The function `split` is simpler and there is no performance difference in these cases, considering
+that both functions return a lazy iterator.
+### Example
+```
+let str = "key=value=add";
+let _ = str.splitn(3, '=').next().unwrap();
+```
+
+Use instead:
+```
+let str = "key=value=add";
+let _ = str.split('=').next().unwrap();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_update.txt b/src/tools/clippy/src/docs/needless_update.txt
new file mode 100644 (file)
index 0000000..82adabf
--- /dev/null
@@ -0,0 +1,30 @@
+### What it does
+Checks for needlessly including a base struct on update
+when all fields are changed anyway.
+
+This lint is not applied to structs marked with
+[non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html).
+
+### Why is this bad?
+This will cost resources (because the base has to be
+somewhere), and make the code less readable.
+
+### Example
+```
+Point {
+    x: 1,
+    y: 1,
+    z: 1,
+    ..zero_point
+};
+```
+
+Use instead:
+```
+// Missing field `z`
+Point {
+    x: 1,
+    y: 1,
+    ..zero_point
+};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/neg_cmp_op_on_partial_ord.txt b/src/tools/clippy/src/docs/neg_cmp_op_on_partial_ord.txt
new file mode 100644 (file)
index 0000000..fa55c6c
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for the usage of negated comparison operators on types which only implement
+`PartialOrd` (e.g., `f64`).
+
+### Why is this bad?
+These operators make it easy to forget that the underlying types actually allow not only three
+potential Orderings (Less, Equal, Greater) but also a fourth one (Uncomparable). This is
+especially easy to miss if the operator based comparison result is negated.
+
+### Example
+```
+let a = 1.0;
+let b = f64::NAN;
+
+let not_less_or_equal = !(a <= b);
+```
+
+Use instead:
+```
+use std::cmp::Ordering;
+
+let _not_less_or_equal = match a.partial_cmp(&b) {
+    None | Some(Ordering::Greater) => true,
+    _ => false,
+};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/neg_multiply.txt b/src/tools/clippy/src/docs/neg_multiply.txt
new file mode 100644 (file)
index 0000000..4e8b096
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for multiplication by -1 as a form of negation.
+
+### Why is this bad?
+It's more readable to just negate.
+
+### Known problems
+This only catches integers (for now).
+
+### Example
+```
+let a = x * -1;
+```
+
+Use instead:
+```
+let a = -x;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/negative_feature_names.txt b/src/tools/clippy/src/docs/negative_feature_names.txt
new file mode 100644 (file)
index 0000000..01ee9ef
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for negative feature names with prefix `no-` or `not-`
+
+### Why is this bad?
+Features are supposed to be additive, and negatively-named features violate it.
+
+### Example
+```
+[features]
+default = []
+no-abc = []
+not-def = []
+
+```
+Use instead:
+```
+[features]
+default = ["abc", "def"]
+abc = []
+def = []
+
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/never_loop.txt b/src/tools/clippy/src/docs/never_loop.txt
new file mode 100644 (file)
index 0000000..737ccf4
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for loops that will always `break`, `return` or
+`continue` an outer loop.
+
+### Why is this bad?
+This loop never loops, all it does is obfuscating the
+code.
+
+### Example
+```
+loop {
+    ..;
+    break;
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/new_ret_no_self.txt b/src/tools/clippy/src/docs/new_ret_no_self.txt
new file mode 100644 (file)
index 0000000..291bad2
--- /dev/null
@@ -0,0 +1,47 @@
+### What it does
+Checks for `new` not returning a type that contains `Self`.
+
+### Why is this bad?
+As a convention, `new` methods are used to make a new
+instance of a type.
+
+### Example
+In an impl block:
+```
+impl Foo {
+    fn new() -> NotAFoo {
+    }
+}
+```
+
+```
+struct Bar(Foo);
+impl Foo {
+    // Bad. The type name must contain `Self`
+    fn new() -> Bar {
+    }
+}
+```
+
+```
+impl Foo {
+    // Good. Return type contains `Self`
+    fn new() -> Result<Foo, FooError> {
+    }
+}
+```
+
+Or in a trait definition:
+```
+pub trait Trait {
+    // Bad. The type name must contain `Self`
+    fn new();
+}
+```
+
+```
+pub trait Trait {
+    // Good. Return type contains `Self`
+    fn new() -> Self;
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/new_without_default.txt b/src/tools/clippy/src/docs/new_without_default.txt
new file mode 100644 (file)
index 0000000..662d39c
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Checks for public types with a `pub fn new() -> Self` method and no
+implementation of
+[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html).
+
+### Why is this bad?
+The user might expect to be able to use
+[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
+type can be constructed without arguments.
+
+### Example
+```
+pub struct Foo(Bar);
+
+impl Foo {
+    pub fn new() -> Self {
+        Foo(Bar::new())
+    }
+}
+```
+
+To fix the lint, add a `Default` implementation that delegates to `new`:
+
+```
+pub struct Foo(Bar);
+
+impl Default for Foo {
+    fn default() -> Self {
+        Foo::new()
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/no_effect.txt b/src/tools/clippy/src/docs/no_effect.txt
new file mode 100644 (file)
index 0000000..d4cc08f
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for statements which have no effect.
+
+### Why is this bad?
+Unlike dead code, these statements are actually
+executed. However, as they have no effect, all they do is make the code less
+readable.
+
+### Example
+```
+0;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/no_effect_replace.txt b/src/tools/clippy/src/docs/no_effect_replace.txt
new file mode 100644 (file)
index 0000000..646d452
--- /dev/null
@@ -0,0 +1,11 @@
+### What it does
+Checks for `replace` statements which have no effect.
+
+### Why is this bad?
+It's either a mistake or confusing.
+
+### Example
+```
+"1234".replace("12", "12");
+"1234".replacen("12", "12", 1);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/no_effect_underscore_binding.txt b/src/tools/clippy/src/docs/no_effect_underscore_binding.txt
new file mode 100644 (file)
index 0000000..972f60d
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for binding to underscore prefixed variable without side-effects.
+
+### Why is this bad?
+Unlike dead code, these bindings are actually
+executed. However, as they have no effect and shouldn't be used further on, all they
+do is make the code less readable.
+
+### Known problems
+Further usage of this variable is not checked, which can lead to false positives if it is
+used later in the code.
+
+### Example
+```
+let _i_serve_no_purpose = 1;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/non_ascii_literal.txt b/src/tools/clippy/src/docs/non_ascii_literal.txt
new file mode 100644 (file)
index 0000000..164902b
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for non-ASCII characters in string and char literals.
+
+### Why is this bad?
+Yeah, we know, the 90's called and wanted their charset
+back. Even so, there still are editors and other programs out there that
+don't work well with Unicode. So if the code is meant to be used
+internationally, on multiple operating systems, or has other portability
+requirements, activating this lint could be useful.
+
+### Example
+```
+let x = String::from("€");
+```
+
+Use instead:
+```
+let x = String::from("\u{20ac}");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/non_octal_unix_permissions.txt b/src/tools/clippy/src/docs/non_octal_unix_permissions.txt
new file mode 100644 (file)
index 0000000..4a468e9
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for non-octal values used to set Unix file permissions.
+
+### Why is this bad?
+They will be converted into octal, creating potentially
+unintended file permissions.
+
+### Example
+```
+use std::fs::OpenOptions;
+use std::os::unix::fs::OpenOptionsExt;
+
+let mut options = OpenOptions::new();
+options.mode(644);
+```
+Use instead:
+```
+use std::fs::OpenOptions;
+use std::os::unix::fs::OpenOptionsExt;
+
+let mut options = OpenOptions::new();
+options.mode(0o644);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/non_send_fields_in_send_ty.txt b/src/tools/clippy/src/docs/non_send_fields_in_send_ty.txt
new file mode 100644 (file)
index 0000000..11e6f6e
--- /dev/null
@@ -0,0 +1,36 @@
+### What it does
+This lint warns about a `Send` implementation for a type that
+contains fields that are not safe to be sent across threads.
+It tries to detect fields that can cause a soundness issue
+when sent to another thread (e.g., `Rc`) while allowing `!Send` fields
+that are expected to exist in a `Send` type, such as raw pointers.
+
+### Why is this bad?
+Sending the struct to another thread effectively sends all of its fields,
+and the fields that do not implement `Send` can lead to soundness bugs
+such as data races when accessed in a thread
+that is different from the thread that created it.
+
+See:
+* [*The Rustonomicon* about *Send and Sync*](https://doc.rust-lang.org/nomicon/send-and-sync.html)
+* [The documentation of `Send`](https://doc.rust-lang.org/std/marker/trait.Send.html)
+
+### Known Problems
+This lint relies on heuristics to distinguish types that are actually
+unsafe to be sent across threads and `!Send` types that are expected to
+exist in  `Send` type. Its rule can filter out basic cases such as
+`Vec<*const T>`, but it's not perfect. Feel free to create an issue if
+you have a suggestion on how this heuristic can be improved.
+
+### Example
+```
+struct ExampleStruct<T> {
+    rc_is_not_send: Rc<String>,
+    unbounded_generic_field: T,
+}
+
+// This impl is unsound because it allows sending `!Send` types through `ExampleStruct`
+unsafe impl<T> Send for ExampleStruct<T> {}
+```
+Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html)
+or specify correct bounds on generic type parameters (`T: Send`).
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/nonminimal_bool.txt b/src/tools/clippy/src/docs/nonminimal_bool.txt
new file mode 100644 (file)
index 0000000..488980d
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for boolean expressions that can be written more
+concisely.
+
+### Why is this bad?
+Readability of boolean expressions suffers from
+unnecessary duplication.
+
+### Known problems
+Ignores short circuiting behavior of `||` and
+`&&`. Ignores `|`, `&` and `^`.
+
+### Example
+```
+if a && true {}
+if !(a == b) {}
+```
+
+Use instead:
+```
+if a {}
+if a != b {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/nonsensical_open_options.txt b/src/tools/clippy/src/docs/nonsensical_open_options.txt
new file mode 100644 (file)
index 0000000..7a95443
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for duplicate open options as well as combinations
+that make no sense.
+
+### Why is this bad?
+In the best case, the code will be harder to read than
+necessary. I don't know the worst case.
+
+### Example
+```
+use std::fs::OpenOptions;
+
+OpenOptions::new().read(true).truncate(true);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/nonstandard_macro_braces.txt b/src/tools/clippy/src/docs/nonstandard_macro_braces.txt
new file mode 100644 (file)
index 0000000..7e8d0d2
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks that common macros are used with consistent bracing.
+
+### Why is this bad?
+This is mostly a consistency lint although using () or []
+doesn't give you a semicolon in item position, which can be unexpected.
+
+### Example
+```
+vec!{1, 2, 3};
+```
+Use instead:
+```
+vec![1, 2, 3];
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/not_unsafe_ptr_arg_deref.txt b/src/tools/clippy/src/docs/not_unsafe_ptr_arg_deref.txt
new file mode 100644 (file)
index 0000000..31355fb
--- /dev/null
@@ -0,0 +1,30 @@
+### What it does
+Checks for public functions that dereference raw pointer
+arguments but are not marked `unsafe`.
+
+### Why is this bad?
+The function should probably be marked `unsafe`, since
+for an arbitrary raw pointer, there is no way of telling for sure if it is
+valid.
+
+### Known problems
+* It does not check functions recursively so if the pointer is passed to a
+private non-`unsafe` function which does the dereferencing, the lint won't
+trigger.
+* It only checks for arguments whose type are raw pointers, not raw pointers
+got from an argument in some other way (`fn foo(bar: &[*const u8])` or
+`some_argument.get_raw_ptr()`).
+
+### Example
+```
+pub fn foo(x: *const u8) {
+    println!("{}", unsafe { *x });
+}
+```
+
+Use instead:
+```
+pub unsafe fn foo(x: *const u8) {
+    println!("{}", unsafe { *x });
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/obfuscated_if_else.txt b/src/tools/clippy/src/docs/obfuscated_if_else.txt
new file mode 100644 (file)
index 0000000..638f63b
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for usages of `.then_some(..).unwrap_or(..)`
+
+### Why is this bad?
+This can be written more clearly with `if .. else ..`
+
+### Limitations
+This lint currently only looks for usages of
+`.then_some(..).unwrap_or(..)`, but will be expanded
+to account for similar patterns.
+
+### Example
+```
+let x = true;
+x.then_some("a").unwrap_or("b");
+```
+Use instead:
+```
+let x = true;
+if x { "a" } else { "b" };
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/octal_escapes.txt b/src/tools/clippy/src/docs/octal_escapes.txt
new file mode 100644 (file)
index 0000000..eee8205
--- /dev/null
@@ -0,0 +1,33 @@
+### What it does
+Checks for `\0` escapes in string and byte literals that look like octal
+character escapes in C.
+
+### Why is this bad?
+
+C and other languages support octal character escapes in strings, where
+a backslash is followed by up to three octal digits. For example, `\033`
+stands for the ASCII character 27 (ESC). Rust does not support this
+notation, but has the escape code `\0` which stands for a null
+byte/character, and any following digits do not form part of the escape
+sequence. Therefore, `\033` is not a compiler error but the result may
+be surprising.
+
+### Known problems
+The actual meaning can be the intended one. `\x00` can be used in these
+cases to be unambiguous.
+
+The lint does not trigger for format strings in `print!()`, `write!()`
+and friends since the string is already preprocessed when Clippy lints
+can see it.
+
+### Example
+```
+let one = "\033[1m Bold? \033[0m";  // \033 intended as escape
+let two = "\033\0";                 // \033 intended as null-3-3
+```
+
+Use instead:
+```
+let one = "\x1b[1mWill this be bold?\x1b[0m";
+let two = "\x0033\x00";
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ok_expect.txt b/src/tools/clippy/src/docs/ok_expect.txt
new file mode 100644 (file)
index 0000000..fd5205d
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `ok().expect(..)`.
+
+### Why is this bad?
+Because you usually call `expect()` on the `Result`
+directly to get a better error message.
+
+### Known problems
+The error type needs to implement `Debug`
+
+### Example
+```
+x.ok().expect("why did I do this again?");
+```
+
+Use instead:
+```
+x.expect("why did I do this again?");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/only_used_in_recursion.txt b/src/tools/clippy/src/docs/only_used_in_recursion.txt
new file mode 100644 (file)
index 0000000..f19f47f
--- /dev/null
@@ -0,0 +1,58 @@
+### What it does
+Checks for arguments that are only used in recursion with no side-effects.
+
+### Why is this bad?
+It could contain a useless calculation and can make function simpler.
+
+The arguments can be involved in calculations and assignments but as long as
+the calculations have no side-effects (function calls or mutating dereference)
+and the assigned variables are also only in recursion, it is useless.
+
+### Known problems
+Too many code paths in the linting code are currently untested and prone to produce false
+positives or are prone to have performance implications.
+
+In some cases, this would not catch all useless arguments.
+
+```
+fn foo(a: usize, b: usize) -> usize {
+    let f = |x| x + 1;
+
+    if a == 0 {
+        1
+    } else {
+        foo(a - 1, f(b))
+    }
+}
+```
+
+For example, the argument `b` is only used in recursion, but the lint would not catch it.
+
+List of some examples that can not be caught:
+- binary operation of non-primitive types
+- closure usage
+- some `break` relative operations
+- struct pattern binding
+
+Also, when you recurse the function name with path segments, it is not possible to detect.
+
+### Example
+```
+fn f(a: usize, b: usize) -> usize {
+    if a == 0 {
+        1
+    } else {
+        f(a - 1, b + 1)
+    }
+}
+```
+Use instead:
+```
+fn f(a: usize) -> usize {
+    if a == 0 {
+        1
+    } else {
+        f(a - 1)
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/op_ref.txt b/src/tools/clippy/src/docs/op_ref.txt
new file mode 100644 (file)
index 0000000..7a7ed1b
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for arguments to `==` which have their address
+taken to satisfy a bound
+and suggests to dereference the other argument instead
+
+### Why is this bad?
+It is more idiomatic to dereference the other argument.
+
+### Example
+```
+&x == y
+```
+
+Use instead:
+```
+x == *y
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_as_ref_deref.txt b/src/tools/clippy/src/docs/option_as_ref_deref.txt
new file mode 100644 (file)
index 0000000..ad7411d
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.as_deref()`.
+
+### Example
+```
+opt.as_ref().map(String::as_str)
+```
+Can be written as
+```
+opt.as_deref()
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_env_unwrap.txt b/src/tools/clippy/src/docs/option_env_unwrap.txt
new file mode 100644 (file)
index 0000000..c952cba
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `option_env!(...).unwrap()` and
+suggests usage of the `env!` macro.
+
+### Why is this bad?
+Unwrapping the result of `option_env!` will panic
+at run-time if the environment variable doesn't exist, whereas `env!`
+catches it at compile-time.
+
+### Example
+```
+let _ = option_env!("HOME").unwrap();
+```
+
+Is better expressed as:
+
+```
+let _ = env!("HOME");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_filter_map.txt b/src/tools/clippy/src/docs/option_filter_map.txt
new file mode 100644 (file)
index 0000000..25f7bde
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for indirect collection of populated `Option`
+
+### Why is this bad?
+`Option` is like a collection of 0-1 things, so `flatten`
+automatically does this without suspicious-looking `unwrap` calls.
+
+### Example
+```
+let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap);
+```
+Use instead:
+```
+let _ = std::iter::empty::<Option<i32>>().flatten();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_if_let_else.txt b/src/tools/clippy/src/docs/option_if_let_else.txt
new file mode 100644 (file)
index 0000000..43652db
--- /dev/null
@@ -0,0 +1,46 @@
+### What it does
+Lints usage of `if let Some(v) = ... { y } else { x }` and
+`match .. { Some(v) => y, None/_ => x }` which are more
+idiomatically done with `Option::map_or` (if the else bit is a pure
+expression) or `Option::map_or_else` (if the else bit is an impure
+expression).
+
+### Why is this bad?
+Using the dedicated functions of the `Option` type is clearer and
+more concise than an `if let` expression.
+
+### Known problems
+This lint uses a deliberately conservative metric for checking
+if the inside of either body contains breaks or continues which will
+cause it to not suggest a fix if either block contains a loop with
+continues or breaks contained within the loop.
+
+### Example
+```
+let _ = if let Some(foo) = optional {
+    foo
+} else {
+    5
+};
+let _ = match optional {
+    Some(val) => val + 1,
+    None => 5
+};
+let _ = if let Some(foo) = optional {
+    foo
+} else {
+    let y = do_complicated_function();
+    y*y
+};
+```
+
+should be
+
+```
+let _ = optional.map_or(5, |foo| foo);
+let _ = optional.map_or(5, |val| val + 1);
+let _ = optional.map_or_else(||{
+    let y = do_complicated_function();
+    y*y
+}, |foo| foo);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_map_or_none.txt b/src/tools/clippy/src/docs/option_map_or_none.txt
new file mode 100644 (file)
index 0000000..c86c652
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `_.map_or(None, _)`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.and_then(_)`.
+
+### Known problems
+The order of the arguments is not in execution order.
+
+### Example
+```
+opt.map_or(None, |a| Some(a + 1));
+```
+
+Use instead:
+```
+opt.and_then(|a| Some(a + 1));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_map_unit_fn.txt b/src/tools/clippy/src/docs/option_map_unit_fn.txt
new file mode 100644 (file)
index 0000000..fc4b528
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for usage of `option.map(f)` where f is a function
+or closure that returns the unit type `()`.
+
+### Why is this bad?
+Readability, this can be written more clearly with
+an if let statement
+
+### Example
+```
+let x: Option<String> = do_stuff();
+x.map(log_err_msg);
+x.map(|msg| log_err_msg(format_msg(msg)));
+```
+
+The correct use would be:
+
+```
+let x: Option<String> = do_stuff();
+if let Some(msg) = x {
+    log_err_msg(msg);
+}
+
+if let Some(msg) = x {
+    log_err_msg(format_msg(msg));
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_option.txt b/src/tools/clippy/src/docs/option_option.txt
new file mode 100644 (file)
index 0000000..b4324bd
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Checks for use of `Option<Option<_>>` in function signatures and type
+definitions
+
+### Why is this bad?
+`Option<_>` represents an optional value. `Option<Option<_>>`
+represents an optional optional value which is logically the same thing as an optional
+value but has an unneeded extra level of wrapping.
+
+If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases,
+consider a custom `enum` instead, with clear names for each case.
+
+### Example
+```
+fn get_data() -> Option<Option<u32>> {
+    None
+}
+```
+
+Better:
+
+```
+pub enum Contents {
+    Data(Vec<u8>), // Was Some(Some(Vec<u8>))
+    NotYetFetched, // Was Some(None)
+    None,          // Was None
+}
+
+fn get_data() -> Contents {
+    Contents::None
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/or_fun_call.txt b/src/tools/clippy/src/docs/or_fun_call.txt
new file mode 100644 (file)
index 0000000..6ce77cc
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
+`.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`,
+`.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()`
+etc. instead.
+
+### Why is this bad?
+The function will always be called and potentially
+allocate an object acting as the default.
+
+### Known problems
+If the function has side-effects, not calling it will
+change the semantic of the program, but you shouldn't rely on that anyway.
+
+### Example
+```
+foo.unwrap_or(String::new());
+```
+
+Use instead:
+```
+foo.unwrap_or_else(String::new);
+
+// or
+
+foo.unwrap_or_default();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/or_then_unwrap.txt b/src/tools/clippy/src/docs/or_then_unwrap.txt
new file mode 100644 (file)
index 0000000..64ac537
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for `.or(…).unwrap()` calls to Options and Results.
+
+### Why is this bad?
+You should use `.unwrap_or(…)` instead for clarity.
+
+### Example
+```
+// Result
+let value = result.or::<Error>(Ok(fallback)).unwrap();
+
+// Option
+let value = option.or(Some(fallback)).unwrap();
+```
+Use instead:
+```
+// Result
+let value = result.unwrap_or(fallback);
+
+// Option
+let value = option.unwrap_or(fallback);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/out_of_bounds_indexing.txt b/src/tools/clippy/src/docs/out_of_bounds_indexing.txt
new file mode 100644 (file)
index 0000000..5802eea
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for out of bounds array indexing with a constant
+index.
+
+### Why is this bad?
+This will always panic at runtime.
+
+### Example
+```
+let x = [1, 2, 3, 4];
+
+x[9];
+&x[2..9];
+```
+
+Use instead:
+```
+// Index within bounds
+
+x[0];
+x[3];
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/overflow_check_conditional.txt b/src/tools/clippy/src/docs/overflow_check_conditional.txt
new file mode 100644 (file)
index 0000000..a09cc18
--- /dev/null
@@ -0,0 +1,11 @@
+### What it does
+Detects classic underflow/overflow checks.
+
+### Why is this bad?
+Most classic C underflow/overflow checks will fail in
+Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
+
+### Example
+```
+a + b < a;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/overly_complex_bool_expr.txt b/src/tools/clippy/src/docs/overly_complex_bool_expr.txt
new file mode 100644 (file)
index 0000000..65ca183
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for boolean expressions that contain terminals that
+can be eliminated.
+
+### Why is this bad?
+This is most likely a logic bug.
+
+### Known problems
+Ignores short circuiting behavior.
+
+### Example
+```
+// The `b` is unnecessary, the expression is equivalent to `if a`.
+if a && b || a { ... }
+```
+
+Use instead:
+```
+if a {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/panic.txt b/src/tools/clippy/src/docs/panic.txt
new file mode 100644 (file)
index 0000000..f9bdc6e
--- /dev/null
@@ -0,0 +1,10 @@
+### What it does
+Checks for usage of `panic!`.
+
+### Why is this bad?
+`panic!` will stop the execution of the executable
+
+### Example
+```
+panic!("even with a good reason");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/panic_in_result_fn.txt b/src/tools/clippy/src/docs/panic_in_result_fn.txt
new file mode 100644 (file)
index 0000000..51c2f8a
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result.
+
+### Why is this bad?
+For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided.
+
+### Known problems
+Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked.
+
+### Example
+```
+fn result_with_panic() -> Result<bool, String>
+{
+    panic!("error");
+}
+```
+Use instead:
+```
+fn result_without_panic() -> Result<bool, String> {
+    Err(String::from("error"))
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/panicking_unwrap.txt b/src/tools/clippy/src/docs/panicking_unwrap.txt
new file mode 100644 (file)
index 0000000..1fbc245
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for calls of `unwrap[_err]()` that will always fail.
+
+### Why is this bad?
+If panicking is desired, an explicit `panic!()` should be used.
+
+### Known problems
+This lint only checks `if` conditions not assignments.
+So something like `let x: Option<()> = None; x.unwrap();` will not be recognized.
+
+### Example
+```
+if option.is_none() {
+    do_something_with(option.unwrap())
+}
+```
+
+This code will always panic. The if condition should probably be inverted.
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/partialeq_ne_impl.txt b/src/tools/clippy/src/docs/partialeq_ne_impl.txt
new file mode 100644 (file)
index 0000000..78f5518
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for manual re-implementations of `PartialEq::ne`.
+
+### Why is this bad?
+`PartialEq::ne` is required to always return the
+negated result of `PartialEq::eq`, which is exactly what the default
+implementation does. Therefore, there should never be any need to
+re-implement it.
+
+### Example
+```
+struct Foo;
+
+impl PartialEq for Foo {
+   fn eq(&self, other: &Foo) -> bool { true }
+   fn ne(&self, other: &Foo) -> bool { !(self == other) }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/partialeq_to_none.txt b/src/tools/clippy/src/docs/partialeq_to_none.txt
new file mode 100644 (file)
index 0000000..5cc07bf
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+
+Checks for binary comparisons to a literal `Option::None`.
+
+### Why is this bad?
+
+A programmer checking if some `foo` is `None` via a comparison `foo == None`
+is usually inspired from other programming languages (e.g. `foo is None`
+in Python).
+Checking if a value of type `Option<T>` is (not) equal to `None` in that
+way relies on `T: PartialEq` to do the comparison, which is unneeded.
+
+### Example
+```
+fn foo(f: Option<u32>) -> &'static str {
+    if f != None { "yay" } else { "nay" }
+}
+```
+Use instead:
+```
+fn foo(f: Option<u32>) -> &'static str {
+    if f.is_some() { "yay" } else { "nay" }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/path_buf_push_overwrite.txt b/src/tools/clippy/src/docs/path_buf_push_overwrite.txt
new file mode 100644 (file)
index 0000000..34f8901
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push)
+calls on `PathBuf` that can cause overwrites.
+
+### Why is this bad?
+Calling `push` with a root path at the start can overwrite the
+previous defined path.
+
+### Example
+```
+use std::path::PathBuf;
+
+let mut x = PathBuf::from("/foo");
+x.push("/bar");
+assert_eq!(x, PathBuf::from("/bar"));
+```
+Could be written:
+
+```
+use std::path::PathBuf;
+
+let mut x = PathBuf::from("/foo");
+x.push("bar");
+assert_eq!(x, PathBuf::from("/foo/bar"));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/pattern_type_mismatch.txt b/src/tools/clippy/src/docs/pattern_type_mismatch.txt
new file mode 100644 (file)
index 0000000..64da881
--- /dev/null
@@ -0,0 +1,64 @@
+### What it does
+Checks for patterns that aren't exact representations of the types
+they are applied to.
+
+To satisfy this lint, you will have to adjust either the expression that is matched
+against or the pattern itself, as well as the bindings that are introduced by the
+adjusted patterns. For matching you will have to either dereference the expression
+with the `*` operator, or amend the patterns to explicitly match against `&<pattern>`
+or `&mut <pattern>` depending on the reference mutability. For the bindings you need
+to use the inverse. You can leave them as plain bindings if you wish for the value
+to be copied, but you must use `ref mut <variable>` or `ref <variable>` to construct
+a reference into the matched structure.
+
+If you are looking for a way to learn about ownership semantics in more detail, it
+is recommended to look at IDE options available to you to highlight types, lifetimes
+and reference semantics in your code. The available tooling would expose these things
+in a general way even outside of the various pattern matching mechanics. Of course
+this lint can still be used to highlight areas of interest and ensure a good understanding
+of ownership semantics.
+
+### Why is this bad?
+It isn't bad in general. But in some contexts it can be desirable
+because it increases ownership hints in the code, and will guard against some changes
+in ownership.
+
+### Example
+This example shows the basic adjustments necessary to satisfy the lint. Note how
+the matched expression is explicitly dereferenced with `*` and the `inner` variable
+is bound to a shared borrow via `ref inner`.
+
+```
+// Bad
+let value = &Some(Box::new(23));
+match value {
+    Some(inner) => println!("{}", inner),
+    None => println!("none"),
+}
+
+// Good
+let value = &Some(Box::new(23));
+match *value {
+    Some(ref inner) => println!("{}", inner),
+    None => println!("none"),
+}
+```
+
+The following example demonstrates one of the advantages of the more verbose style.
+Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable
+borrow, while `b` is simply taken by value. This ensures that the loop body cannot
+accidentally modify the wrong part of the structure.
+
+```
+// Bad
+let mut values = vec![(2, 3), (3, 4)];
+for (a, b) in &mut values {
+    *a += *b;
+}
+
+// Good
+let mut values = vec![(2, 3), (3, 4)];
+for &mut (ref mut a, b) in &mut values {
+    *a += b;
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/positional_named_format_parameters.txt b/src/tools/clippy/src/docs/positional_named_format_parameters.txt
new file mode 100644 (file)
index 0000000..e391d24
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+This lint warns when a named parameter in a format string is used as a positional one.
+
+### Why is this bad?
+It may be confused for an assignment and obfuscates which parameter is being used.
+
+### Example
+```
+println!("{}", x = 10);
+```
+
+Use instead:
+```
+println!("{x}", x = 10);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/possible_missing_comma.txt b/src/tools/clippy/src/docs/possible_missing_comma.txt
new file mode 100644 (file)
index 0000000..5d92f4c
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for possible missing comma in an array. It lints if
+an array element is a binary operator expression and it lies on two lines.
+
+### Why is this bad?
+This could lead to unexpected results.
+
+### Example
+```
+let a = &[
+    -1, -2, -3 // <= no comma here
+    -4, -5, -6
+];
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/precedence.txt b/src/tools/clippy/src/docs/precedence.txt
new file mode 100644 (file)
index 0000000..fda0b83
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for operations where precedence may be unclear
+and suggests to add parentheses. Currently it catches the following:
+* mixed usage of arithmetic and bit shifting/combining operators without
+parentheses
+* a "negative" numeric literal (which is really a unary `-` followed by a
+numeric literal)
+  followed by a method call
+
+### Why is this bad?
+Not everyone knows the precedence of those operators by
+heart, so expressions like these may trip others trying to reason about the
+code.
+
+### Example
+* `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7
+* `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/print_in_format_impl.txt b/src/tools/clippy/src/docs/print_in_format_impl.txt
new file mode 100644 (file)
index 0000000..140d23d
--- /dev/null
@@ -0,0 +1,34 @@
+### What it does
+Checks for use of `println`, `print`, `eprintln` or `eprint` in an
+implementation of a formatting trait.
+
+### Why is this bad?
+Using a print macro is likely unintentional since formatting traits
+should write to the `Formatter`, not stdout/stderr.
+
+### Example
+```
+use std::fmt::{Display, Error, Formatter};
+
+struct S;
+impl Display for S {
+    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+        println!("S");
+
+        Ok(())
+    }
+}
+```
+Use instead:
+```
+use std::fmt::{Display, Error, Formatter};
+
+struct S;
+impl Display for S {
+    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+        writeln!(f, "S");
+
+        Ok(())
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/print_literal.txt b/src/tools/clippy/src/docs/print_literal.txt
new file mode 100644 (file)
index 0000000..1600734
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+This lint warns about the use of literals as `print!`/`println!` args.
+
+### Why is this bad?
+Using literals as `println!` args is inefficient
+(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
+(i.e., just put the literal in the format string)
+
+### Known problems
+Will also warn with macro calls as arguments that expand to literals
+-- e.g., `println!("{}", env!("FOO"))`.
+
+### Example
+```
+println!("{}", "foo");
+```
+use the literal without formatting:
+```
+println!("foo");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/print_stderr.txt b/src/tools/clippy/src/docs/print_stderr.txt
new file mode 100644 (file)
index 0000000..fc14511
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for printing on *stderr*. The purpose of this lint
+is to catch debugging remnants.
+
+### Why is this bad?
+People often print on *stderr* while debugging an
+application and might forget to remove those prints afterward.
+
+### Known problems
+* Only catches `eprint!` and `eprintln!` calls.
+* The lint level is unaffected by crate attributes. The level can still
+  be set for functions, modules and other items. To change the level for
+  the entire crate, please use command line flags. More information and a
+  configuration example can be found in [clippy#6610].
+
+[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
+
+### Example
+```
+eprintln!("Hello world!");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/print_stdout.txt b/src/tools/clippy/src/docs/print_stdout.txt
new file mode 100644 (file)
index 0000000..6c9a4b9
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for printing on *stdout*. The purpose of this lint
+is to catch debugging remnants.
+
+### Why is this bad?
+People often print on *stdout* while debugging an
+application and might forget to remove those prints afterward.
+
+### Known problems
+* Only catches `print!` and `println!` calls.
+* The lint level is unaffected by crate attributes. The level can still
+  be set for functions, modules and other items. To change the level for
+  the entire crate, please use command line flags. More information and a
+  configuration example can be found in [clippy#6610].
+
+[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
+
+### Example
+```
+println!("Hello world!");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/print_with_newline.txt b/src/tools/clippy/src/docs/print_with_newline.txt
new file mode 100644 (file)
index 0000000..640323e
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+This lint warns when you use `print!()` with a format
+string that ends in a newline.
+
+### Why is this bad?
+You should use `println!()` instead, which appends the
+newline.
+
+### Example
+```
+print!("Hello {}!\n", name);
+```
+use println!() instead
+```
+println!("Hello {}!", name);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/println_empty_string.txt b/src/tools/clippy/src/docs/println_empty_string.txt
new file mode 100644 (file)
index 0000000..b980413
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+This lint warns when you use `println!("")` to
+print a newline.
+
+### Why is this bad?
+You should use `println!()`, which is simpler.
+
+### Example
+```
+println!("");
+```
+
+Use instead:
+```
+println!();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ptr_arg.txt b/src/tools/clippy/src/docs/ptr_arg.txt
new file mode 100644 (file)
index 0000000..796b0a6
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+This lint checks for function arguments of type `&String`, `&Vec`,
+`&PathBuf`, and `Cow<_>`. It will also suggest you replace `.clone()` calls
+with the appropriate `.to_owned()`/`to_string()` calls.
+
+### Why is this bad?
+Requiring the argument to be of the specific size
+makes the function less useful for no benefit; slices in the form of `&[T]`
+or `&str` usually suffice and can be obtained from other types, too.
+
+### Known problems
+There may be `fn(&Vec)`-typed references pointing to your function.
+If you have them, you will get a compiler error after applying this lint's
+suggestions. You then have the choice to undo your changes or change the
+type of the reference.
+
+Note that if the function is part of your public interface, there may be
+other crates referencing it, of which you may not be aware. Carefully
+deprecate the function before applying the lint suggestions in this case.
+
+### Example
+```
+fn foo(&Vec<u32>) { .. }
+```
+
+Use instead:
+```
+fn foo(&[u32]) { .. }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ptr_as_ptr.txt b/src/tools/clippy/src/docs/ptr_as_ptr.txt
new file mode 100644 (file)
index 0000000..8fb35c4
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for `as` casts between raw pointers without changing its mutability,
+namely `*const T` to `*const U` and `*mut T` to `*mut U`.
+
+### Why is this bad?
+Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because
+it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
+
+### Example
+```
+let ptr: *const u32 = &42_u32;
+let mut_ptr: *mut u32 = &mut 42_u32;
+let _ = ptr as *const i32;
+let _ = mut_ptr as *mut i32;
+```
+Use instead:
+```
+let ptr: *const u32 = &42_u32;
+let mut_ptr: *mut u32 = &mut 42_u32;
+let _ = ptr.cast::<i32>();
+let _ = mut_ptr.cast::<i32>();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ptr_eq.txt b/src/tools/clippy/src/docs/ptr_eq.txt
new file mode 100644 (file)
index 0000000..06b36ca
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Use `std::ptr::eq` when applicable
+
+### Why is this bad?
+`ptr::eq` can be used to compare `&T` references
+(which coerce to `*const T` implicitly) by their address rather than
+comparing the values they point to.
+
+### Example
+```
+let a = &[1, 2, 3];
+let b = &[1, 2, 3];
+
+assert!(a as *const _ as usize == b as *const _ as usize);
+```
+Use instead:
+```
+let a = &[1, 2, 3];
+let b = &[1, 2, 3];
+
+assert!(std::ptr::eq(a, b));
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ptr_offset_with_cast.txt b/src/tools/clippy/src/docs/ptr_offset_with_cast.txt
new file mode 100644 (file)
index 0000000..f204e76
--- /dev/null
@@ -0,0 +1,30 @@
+### What it does
+Checks for usage of the `offset` pointer method with a `usize` casted to an
+`isize`.
+
+### Why is this bad?
+If we’re always increasing the pointer address, we can avoid the numeric
+cast by using the `add` method instead.
+
+### Example
+```
+let vec = vec![b'a', b'b', b'c'];
+let ptr = vec.as_ptr();
+let offset = 1_usize;
+
+unsafe {
+    ptr.offset(offset as isize);
+}
+```
+
+Could be written:
+
+```
+let vec = vec![b'a', b'b', b'c'];
+let ptr = vec.as_ptr();
+let offset = 1_usize;
+
+unsafe {
+    ptr.add(offset);
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/pub_use.txt b/src/tools/clippy/src/docs/pub_use.txt
new file mode 100644 (file)
index 0000000..407cafa
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+
+Restricts the usage of `pub use ...`
+
+### Why is this bad?
+
+`pub use` is usually fine, but a project may wish to limit `pub use` instances to prevent
+unintentional exports or to encourage placing exported items directly in public modules
+
+### Example
+```
+pub mod outer {
+    mod inner {
+        pub struct Test {}
+    }
+    pub use inner::Test;
+}
+
+use outer::Test;
+```
+Use instead:
+```
+pub mod outer {
+    pub struct Test {}
+}
+
+use outer::Test;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/question_mark.txt b/src/tools/clippy/src/docs/question_mark.txt
new file mode 100644 (file)
index 0000000..4dc987b
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for expressions that could be replaced by the question mark operator.
+
+### Why is this bad?
+Question mark usage is more idiomatic.
+
+### Example
+```
+if option.is_none() {
+    return None;
+}
+```
+
+Could be written:
+
+```
+option?;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/range_minus_one.txt b/src/tools/clippy/src/docs/range_minus_one.txt
new file mode 100644 (file)
index 0000000..fcb96dc
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for inclusive ranges where 1 is subtracted from
+the upper bound, e.g., `x..=(y-1)`.
+
+### Why is this bad?
+The code is more readable with an exclusive range
+like `x..y`.
+
+### Known problems
+This will cause a warning that cannot be fixed if
+the consumer of the range only accepts a specific range type, instead of
+the generic `RangeBounds` trait
+([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
+
+### Example
+```
+for i in x..=(y-1) {
+    // ..
+}
+```
+
+Use instead:
+```
+for i in x..y {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/range_plus_one.txt b/src/tools/clippy/src/docs/range_plus_one.txt
new file mode 100644 (file)
index 0000000..193c85f
--- /dev/null
@@ -0,0 +1,36 @@
+### What it does
+Checks for exclusive ranges where 1 is added to the
+upper bound, e.g., `x..(y+1)`.
+
+### Why is this bad?
+The code is more readable with an inclusive range
+like `x..=y`.
+
+### Known problems
+Will add unnecessary pair of parentheses when the
+expression is not wrapped in a pair but starts with an opening parenthesis
+and ends with a closing one.
+I.e., `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..=f())`.
+
+Also in many cases, inclusive ranges are still slower to run than
+exclusive ranges, because they essentially add an extra branch that
+LLVM may fail to hoist out of the loop.
+
+This will cause a warning that cannot be fixed if the consumer of the
+range only accepts a specific range type, instead of the generic
+`RangeBounds` trait
+([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
+
+### Example
+```
+for i in x..(y+1) {
+    // ..
+}
+```
+
+Use instead:
+```
+for i in x..=y {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/range_zip_with_len.txt b/src/tools/clippy/src/docs/range_zip_with_len.txt
new file mode 100644 (file)
index 0000000..24c1efe
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for zipping a collection with the range of
+`0.._.len()`.
+
+### Why is this bad?
+The code is better expressed with `.enumerate()`.
+
+### Example
+```
+let _ = x.iter().zip(0..x.len());
+```
+
+Use instead:
+```
+let _ = x.iter().enumerate();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/rc_buffer.txt b/src/tools/clippy/src/docs/rc_buffer.txt
new file mode 100644 (file)
index 0000000..82ac58e
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for `Rc<T>` and `Arc<T>` when `T` is a mutable buffer type such as `String` or `Vec`.
+
+### Why is this bad?
+Expressions such as `Rc<String>` usually have no advantage over `Rc<str>`, since
+it is larger and involves an extra level of indirection, and doesn't implement `Borrow<str>`.
+
+While mutating a buffer type would still be possible with `Rc::get_mut()`, it only
+works if there are no additional references yet, which usually defeats the purpose of
+enclosing it in a shared ownership type. Instead, additionally wrapping the inner
+type with an interior mutable container (such as `RefCell` or `Mutex`) would normally
+be used.
+
+### Known problems
+This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for
+cases where mutation only happens before there are any additional references.
+
+### Example
+```
+fn foo(interned: Rc<String>) { ... }
+```
+
+Better:
+
+```
+fn foo(interned: Rc<str>) { ... }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/rc_clone_in_vec_init.txt b/src/tools/clippy/src/docs/rc_clone_in_vec_init.txt
new file mode 100644 (file)
index 0000000..6fc08aa
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for reference-counted pointers (`Arc`, `Rc`, `rc::Weak`, and `sync::Weak`)
+in `vec![elem; len]`
+
+### Why is this bad?
+This will create `elem` once and clone it `len` times - doing so with `Arc`/`Rc`/`Weak`
+is a bit misleading, as it will create references to the same pointer, rather
+than different instances.
+
+### Example
+```
+let v = vec![std::sync::Arc::new("some data".to_string()); 100];
+// or
+let v = vec![std::rc::Rc::new("some data".to_string()); 100];
+```
+Use instead:
+```
+// Initialize each value separately:
+let mut data = Vec::with_capacity(100);
+for _ in 0..100 {
+    data.push(std::rc::Rc::new("some data".to_string()));
+}
+
+// Or if you want clones of the same reference,
+// Create the reference beforehand to clarify that
+// it should be cloned for each value
+let data = std::rc::Rc::new("some data".to_string());
+let v = vec![data; 100];
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/rc_mutex.txt b/src/tools/clippy/src/docs/rc_mutex.txt
new file mode 100644 (file)
index 0000000..ed7a1e3
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for `Rc<Mutex<T>>`.
+
+### Why is this bad?
+`Rc` is used in single thread and `Mutex` is used in multi thread.
+Consider using `Rc<RefCell<T>>` in single thread or `Arc<Mutex<T>>` in multi thread.
+
+### Known problems
+Sometimes combining generic types can lead to the requirement that a
+type use Rc in conjunction with Mutex. We must consider those cases false positives, but
+alas they are quite hard to rule out. Luckily they are also rare.
+
+### Example
+```
+use std::rc::Rc;
+use std::sync::Mutex;
+fn foo(interned: Rc<Mutex<i32>>) { ... }
+```
+
+Better:
+
+```
+use std::rc::Rc;
+use std::cell::RefCell
+fn foo(interned: Rc<RefCell<i32>>) { ... }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/read_zero_byte_vec.txt b/src/tools/clippy/src/docs/read_zero_byte_vec.txt
new file mode 100644 (file)
index 0000000..cef5604
--- /dev/null
@@ -0,0 +1,30 @@
+### What it does
+This lint catches reads into a zero-length `Vec`.
+Especially in the case of a call to `with_capacity`, this lint warns that read
+gets the number of bytes from the `Vec`'s length, not its capacity.
+
+### Why is this bad?
+Reading zero bytes is almost certainly not the intended behavior.
+
+### Known problems
+In theory, a very unusual read implementation could assign some semantic meaning
+to zero-byte reads. But it seems exceptionally unlikely that code intending to do
+a zero-byte read would allocate a `Vec` for it.
+
+### Example
+```
+use std::io;
+fn foo<F: io::Read>(mut f: F) {
+    let mut data = Vec::with_capacity(100);
+    f.read(&mut data).unwrap();
+}
+```
+Use instead:
+```
+use std::io;
+fn foo<F: io::Read>(mut f: F) {
+    let mut data = Vec::with_capacity(100);
+    data.resize(100, 0);
+    f.read(&mut data).unwrap();
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/recursive_format_impl.txt b/src/tools/clippy/src/docs/recursive_format_impl.txt
new file mode 100644 (file)
index 0000000..32fffd8
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Checks for format trait implementations (e.g. `Display`) with a recursive call to itself
+which uses `self` as a parameter.
+This is typically done indirectly with the `write!` macro or with `to_string()`.
+
+### Why is this bad?
+This will lead to infinite recursion and a stack overflow.
+
+### Example
+
+```
+use std::fmt;
+
+struct Structure(i32);
+impl fmt::Display for Structure {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.to_string())
+    }
+}
+
+```
+Use instead:
+```
+use std::fmt;
+
+struct Structure(i32);
+impl fmt::Display for Structure {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.0)
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_allocation.txt b/src/tools/clippy/src/docs/redundant_allocation.txt
new file mode 100644 (file)
index 0000000..86bf51e
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for use of redundant allocations anywhere in the code.
+
+### Why is this bad?
+Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Arc<T>>`, `Rc<Box<T>>`, `Arc<&T>`, `Arc<Rc<T>>`,
+`Arc<Arc<T>>`, `Arc<Box<T>>`, `Box<&T>`, `Box<Rc<T>>`, `Box<Arc<T>>`, `Box<Box<T>>`, add an unnecessary level of indirection.
+
+### Example
+```
+fn foo(bar: Rc<&usize>) {}
+```
+
+Better:
+
+```
+fn foo(bar: &usize) {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_clone.txt b/src/tools/clippy/src/docs/redundant_clone.txt
new file mode 100644 (file)
index 0000000..b29aed0
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for a redundant `clone()` (and its relatives) which clones an owned
+value that is going to be dropped without further use.
+
+### Why is this bad?
+It is not always possible for the compiler to eliminate useless
+allocations and deallocations generated by redundant `clone()`s.
+
+### Known problems
+False-negatives: analysis performed by this lint is conservative and limited.
+
+### Example
+```
+{
+    let x = Foo::new();
+    call(x.clone());
+    call(x.clone()); // this can just pass `x`
+}
+
+["lorem", "ipsum"].join(" ").to_string();
+
+Path::new("/a/b").join("c").to_path_buf();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_closure.txt b/src/tools/clippy/src/docs/redundant_closure.txt
new file mode 100644 (file)
index 0000000..0faa951
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for closures which just call another function where
+the function can be called directly. `unsafe` functions or calls where types
+get adjusted are ignored.
+
+### Why is this bad?
+Needlessly creating a closure adds code for no benefit
+and gives the optimizer more work.
+
+### Known problems
+If creating the closure inside the closure has a side-
+effect then moving the closure creation out will change when that side-
+effect runs.
+See [#1439](https://github.com/rust-lang/rust-clippy/issues/1439) for more details.
+
+### Example
+```
+xs.map(|x| foo(x))
+```
+
+Use instead:
+```
+// where `foo(_)` is a plain function that takes the exact argument type of `x`.
+xs.map(foo)
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_closure_call.txt b/src/tools/clippy/src/docs/redundant_closure_call.txt
new file mode 100644 (file)
index 0000000..913d1a7
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Detects closures called in the same expression where they
+are defined.
+
+### Why is this bad?
+It is unnecessarily adding to the expression's
+complexity.
+
+### Example
+```
+let a = (|| 42)();
+```
+
+Use instead:
+```
+let a = 42;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_closure_for_method_calls.txt b/src/tools/clippy/src/docs/redundant_closure_for_method_calls.txt
new file mode 100644 (file)
index 0000000..865510e
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for closures which only invoke a method on the closure
+argument and can be replaced by referencing the method directly.
+
+### Why is this bad?
+It's unnecessary to create the closure.
+
+### Example
+```
+Some('a').map(|s| s.to_uppercase());
+```
+may be rewritten as
+```
+Some('a').map(char::to_uppercase);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_else.txt b/src/tools/clippy/src/docs/redundant_else.txt
new file mode 100644 (file)
index 0000000..3f4e869
--- /dev/null
@@ -0,0 +1,30 @@
+### What it does
+Checks for `else` blocks that can be removed without changing semantics.
+
+### Why is this bad?
+The `else` block adds unnecessary indentation and verbosity.
+
+### Known problems
+Some may prefer to keep the `else` block for clarity.
+
+### Example
+```
+fn my_func(count: u32) {
+    if count == 0 {
+        print!("Nothing to do");
+        return;
+    } else {
+        print!("Moving on...");
+    }
+}
+```
+Use instead:
+```
+fn my_func(count: u32) {
+    if count == 0 {
+        print!("Nothing to do");
+        return;
+    }
+    print!("Moving on...");
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_feature_names.txt b/src/tools/clippy/src/docs/redundant_feature_names.txt
new file mode 100644 (file)
index 0000000..5bd6925
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for feature names with prefix `use-`, `with-` or suffix `-support`
+
+### Why is this bad?
+These prefixes and suffixes have no significant meaning.
+
+### Example
+```
+[features]
+default = ["use-abc", "with-def", "ghi-support"]
+use-abc = []  // redundant
+with-def = []   // redundant
+ghi-support = []   // redundant
+```
+
+Use instead:
+```
+[features]
+default = ["abc", "def", "ghi"]
+abc = []
+def = []
+ghi = []
+```
diff --git a/src/tools/clippy/src/docs/redundant_field_names.txt b/src/tools/clippy/src/docs/redundant_field_names.txt
new file mode 100644 (file)
index 0000000..35f20a4
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for fields in struct literals where shorthands
+could be used.
+
+### Why is this bad?
+If the field and variable names are the same,
+the field name is redundant.
+
+### Example
+```
+let bar: u8 = 123;
+
+struct Foo {
+    bar: u8,
+}
+
+let foo = Foo { bar: bar };
+```
+the last line can be simplified to
+```
+let foo = Foo { bar };
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_pattern.txt b/src/tools/clippy/src/docs/redundant_pattern.txt
new file mode 100644 (file)
index 0000000..45f6cfc
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for patterns in the form `name @ _`.
+
+### Why is this bad?
+It's almost always more readable to just use direct
+bindings.
+
+### Example
+```
+match v {
+    Some(x) => (),
+    y @ _ => (),
+}
+```
+
+Use instead:
+```
+match v {
+    Some(x) => (),
+    y => (),
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_pattern_matching.txt b/src/tools/clippy/src/docs/redundant_pattern_matching.txt
new file mode 100644 (file)
index 0000000..77b1021
--- /dev/null
@@ -0,0 +1,45 @@
+### What it does
+Lint for redundant pattern matching over `Result`, `Option`,
+`std::task::Poll` or `std::net::IpAddr`
+
+### Why is this bad?
+It's more concise and clear to just use the proper
+utility function
+
+### Known problems
+This will change the drop order for the matched type. Both `if let` and
+`while let` will drop the value at the end of the block, both `if` and `while` will drop the
+value before entering the block. For most types this change will not matter, but for a few
+types this will not be an acceptable change (e.g. locks). See the
+[reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
+drop order.
+
+### Example
+```
+if let Ok(_) = Ok::<i32, i32>(42) {}
+if let Err(_) = Err::<i32, i32>(42) {}
+if let None = None::<()> {}
+if let Some(_) = Some(42) {}
+if let Poll::Pending = Poll::Pending::<()> {}
+if let Poll::Ready(_) = Poll::Ready(42) {}
+if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {}
+if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {}
+match Ok::<i32, i32>(42) {
+    Ok(_) => true,
+    Err(_) => false,
+};
+```
+
+The more idiomatic use would be:
+
+```
+if Ok::<i32, i32>(42).is_ok() {}
+if Err::<i32, i32>(42).is_err() {}
+if None::<()>.is_none() {}
+if Some(42).is_some() {}
+if Poll::Pending::<()>.is_pending() {}
+if Poll::Ready(42).is_ready() {}
+if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
+if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
+Ok::<i32, i32>(42).is_ok();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_pub_crate.txt b/src/tools/clippy/src/docs/redundant_pub_crate.txt
new file mode 100644 (file)
index 0000000..a527bb5
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for items declared `pub(crate)` that are not crate visible because they
+are inside a private module.
+
+### Why is this bad?
+Writing `pub(crate)` is misleading when it's redundant due to the parent
+module's visibility.
+
+### Example
+```
+mod internal {
+    pub(crate) fn internal_fn() { }
+}
+```
+This function is not visible outside the module and it can be declared with `pub` or
+private visibility
+```
+mod internal {
+    pub fn internal_fn() { }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_slicing.txt b/src/tools/clippy/src/docs/redundant_slicing.txt
new file mode 100644 (file)
index 0000000..6798911
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for redundant slicing expressions which use the full range, and
+do not change the type.
+
+### Why is this bad?
+It unnecessarily adds complexity to the expression.
+
+### Known problems
+If the type being sliced has an implementation of `Index<RangeFull>`
+that actually changes anything then it can't be removed. However, this would be surprising
+to people reading the code and should have a note with it.
+
+### Example
+```
+fn get_slice(x: &[u32]) -> &[u32] {
+    &x[..]
+}
+```
+Use instead:
+```
+fn get_slice(x: &[u32]) -> &[u32] {
+    x
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_static_lifetimes.txt b/src/tools/clippy/src/docs/redundant_static_lifetimes.txt
new file mode 100644 (file)
index 0000000..edb8e7b
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for constants and statics with an explicit `'static` lifetime.
+
+### Why is this bad?
+Adding `'static` to every reference can create very
+complicated types.
+
+### Example
+```
+const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
+&[...]
+static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
+&[...]
+```
+This code can be rewritten as
+```
+ const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
+ static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ref_binding_to_reference.txt b/src/tools/clippy/src/docs/ref_binding_to_reference.txt
new file mode 100644 (file)
index 0000000..dc391cd
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for `ref` bindings which create a reference to a reference.
+
+### Why is this bad?
+The address-of operator at the use site is clearer about the need for a reference.
+
+### Example
+```
+let x = Some("");
+if let Some(ref x) = x {
+    // use `x` here
+}
+```
+
+Use instead:
+```
+let x = Some("");
+if let Some(x) = x {
+    // use `&x` here
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ref_option_ref.txt b/src/tools/clippy/src/docs/ref_option_ref.txt
new file mode 100644 (file)
index 0000000..951c7bd
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `&Option<&T>`.
+
+### Why is this bad?
+Since `&` is Copy, it's useless to have a
+reference on `Option<&T>`.
+
+### Known problems
+It may be irrelevant to use this lint on
+public API code as it will make a breaking change to apply it.
+
+### Example
+```
+let x: &Option<&u32> = &Some(&0u32);
+```
+Use instead:
+```
+let x: Option<&u32> = Some(&0u32);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/repeat_once.txt b/src/tools/clippy/src/docs/repeat_once.txt
new file mode 100644 (file)
index 0000000..3ba189c
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for usage of `.repeat(1)` and suggest the following method for each types.
+- `.to_string()` for `str`
+- `.clone()` for `String`
+- `.to_vec()` for `slice`
+
+The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if
+they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))
+
+### Why is this bad?
+For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning
+the string is the intention behind this, `clone()` should be used.
+
+### Example
+```
+fn main() {
+    let x = String::from("hello world").repeat(1);
+}
+```
+Use instead:
+```
+fn main() {
+    let x = String::from("hello world").clone();
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/rest_pat_in_fully_bound_structs.txt b/src/tools/clippy/src/docs/rest_pat_in_fully_bound_structs.txt
new file mode 100644 (file)
index 0000000..40ebbe7
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched.
+
+### Why is this bad?
+Correctness and readability. It's like having a wildcard pattern after
+matching all enum variants explicitly.
+
+### Example
+```
+let a = A { a: 5 };
+
+match a {
+    A { a: 5, .. } => {},
+    _ => {},
+}
+```
+
+Use instead:
+```
+match a {
+    A { a: 5 } => {},
+    _ => {},
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/result_large_err.txt b/src/tools/clippy/src/docs/result_large_err.txt
new file mode 100644 (file)
index 0000000..e5fab3c
--- /dev/null
@@ -0,0 +1,36 @@
+### What it does
+Checks for functions that return `Result` with an unusually large
+`Err`-variant.
+
+### Why is this bad?
+A `Result` is at least as large as the `Err`-variant. While we
+expect that variant to be seldomly used, the compiler needs to reserve
+and move that much memory every single time.
+
+### Known problems
+The size determined by Clippy is platform-dependent.
+
+### Examples
+```
+pub enum ParseError {
+    UnparsedBytes([u8; 512]),
+    UnexpectedEof,
+}
+
+// The `Result` has at least 512 bytes, even in the `Ok`-case
+pub fn parse() -> Result<(), ParseError> {
+    Ok(())
+}
+```
+should be
+```
+pub enum ParseError {
+    UnparsedBytes(Box<[u8; 512]>),
+    UnexpectedEof,
+}
+
+// The `Result` is slightly larger than a pointer
+pub fn parse() -> Result<(), ParseError> {
+    Ok(())
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/result_map_or_into_option.txt b/src/tools/clippy/src/docs/result_map_or_into_option.txt
new file mode 100644 (file)
index 0000000..899d98c
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `_.map_or(None, Some)`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.ok()`.
+
+### Example
+```
+assert_eq!(Some(1), r.map_or(None, Some));
+```
+
+Use instead:
+```
+assert_eq!(Some(1), r.ok());
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/result_map_unit_fn.txt b/src/tools/clippy/src/docs/result_map_unit_fn.txt
new file mode 100644 (file)
index 0000000..3455c5c
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for usage of `result.map(f)` where f is a function
+or closure that returns the unit type `()`.
+
+### Why is this bad?
+Readability, this can be written more clearly with
+an if let statement
+
+### Example
+```
+let x: Result<String, String> = do_stuff();
+x.map(log_err_msg);
+x.map(|msg| log_err_msg(format_msg(msg)));
+```
+
+The correct use would be:
+
+```
+let x: Result<String, String> = do_stuff();
+if let Ok(msg) = x {
+    log_err_msg(msg);
+};
+if let Ok(msg) = x {
+    log_err_msg(format_msg(msg));
+};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/result_unit_err.txt b/src/tools/clippy/src/docs/result_unit_err.txt
new file mode 100644 (file)
index 0000000..7c8ec2f
--- /dev/null
@@ -0,0 +1,40 @@
+### What it does
+Checks for public functions that return a `Result`
+with an `Err` type of `()`. It suggests using a custom type that
+implements `std::error::Error`.
+
+### Why is this bad?
+Unit does not implement `Error` and carries no
+further information about what went wrong.
+
+### Known problems
+Of course, this lint assumes that `Result` is used
+for a fallible operation (which is after all the intended use). However
+code may opt to (mis)use it as a basic two-variant-enum. In that case,
+the suggestion is misguided, and the code should use a custom enum
+instead.
+
+### Examples
+```
+pub fn read_u8() -> Result<u8, ()> { Err(()) }
+```
+should become
+```
+use std::fmt;
+
+#[derive(Debug)]
+pub struct EndOfStream;
+
+impl fmt::Display for EndOfStream {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "End of Stream")
+    }
+}
+
+impl std::error::Error for EndOfStream { }
+
+pub fn read_u8() -> Result<u8, EndOfStream> { Err(EndOfStream) }
+```
+
+Note that there are crates that simplify creating the error type, e.g.
+[`thiserror`](https://docs.rs/thiserror).
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/return_self_not_must_use.txt b/src/tools/clippy/src/docs/return_self_not_must_use.txt
new file mode 100644 (file)
index 0000000..4a4fd2c
--- /dev/null
@@ -0,0 +1,46 @@
+### What it does
+This lint warns when a method returning `Self` doesn't have the `#[must_use]` attribute.
+
+### Why is this bad?
+Methods returning `Self` often create new values, having the `#[must_use]` attribute
+prevents users from "forgetting" to use the newly created value.
+
+The `#[must_use]` attribute can be added to the type itself to ensure that instances
+are never forgotten. Functions returning a type marked with `#[must_use]` will not be
+linted, as the usage is already enforced by the type attribute.
+
+### Limitations
+This lint is only applied on methods taking a `self` argument. It would be mostly noise
+if it was added on constructors for example.
+
+### Example
+```
+pub struct Bar;
+impl Bar {
+    // Missing attribute
+    pub fn bar(&self) -> Self {
+        Self
+    }
+}
+```
+
+Use instead:
+```
+// It's better to have the `#[must_use]` attribute on the method like this:
+pub struct Bar;
+impl Bar {
+    #[must_use]
+    pub fn bar(&self) -> Self {
+        Self
+    }
+}
+
+// Or on the type definition like this:
+#[must_use]
+pub struct Bar;
+impl Bar {
+    pub fn bar(&self) -> Self {
+        Self
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/reversed_empty_ranges.txt b/src/tools/clippy/src/docs/reversed_empty_ranges.txt
new file mode 100644 (file)
index 0000000..39f4811
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for range expressions `x..y` where both `x` and `y`
+are constant and `x` is greater or equal to `y`.
+
+### Why is this bad?
+Empty ranges yield no values so iterating them is a no-op.
+Moreover, trying to use a reversed range to index a slice will panic at run-time.
+
+### Example
+```
+fn main() {
+    (10..=0).for_each(|x| println!("{}", x));
+
+    let arr = [1, 2, 3, 4, 5];
+    let sub = &arr[3..1];
+}
+```
+Use instead:
+```
+fn main() {
+    (0..=10).rev().for_each(|x| println!("{}", x));
+
+    let arr = [1, 2, 3, 4, 5];
+    let sub = &arr[1..3];
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/same_functions_in_if_condition.txt b/src/tools/clippy/src/docs/same_functions_in_if_condition.txt
new file mode 100644 (file)
index 0000000..a0a90ee
--- /dev/null
@@ -0,0 +1,41 @@
+### What it does
+Checks for consecutive `if`s with the same function call.
+
+### Why is this bad?
+This is probably a copy & paste error.
+Despite the fact that function can have side effects and `if` works as
+intended, such an approach is implicit and can be considered a "code smell".
+
+### Example
+```
+if foo() == bar {
+    …
+} else if foo() == bar {
+    …
+}
+```
+
+This probably should be:
+```
+if foo() == bar {
+    …
+} else if foo() == baz {
+    …
+}
+```
+
+or if the original code was not a typo and called function mutates a state,
+consider move the mutation out of the `if` condition to avoid similarity to
+a copy & paste error:
+
+```
+let first = foo();
+if first == bar {
+    …
+} else {
+    let second = foo();
+    if second == bar {
+    …
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/same_item_push.txt b/src/tools/clippy/src/docs/same_item_push.txt
new file mode 100644 (file)
index 0000000..7e72407
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks whether a for loop is being used to push a constant
+value into a Vec.
+
+### Why is this bad?
+This kind of operation can be expressed more succinctly with
+`vec![item; SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also
+have better performance.
+
+### Example
+```
+let item1 = 2;
+let item2 = 3;
+let mut vec: Vec<u8> = Vec::new();
+for _ in 0..20 {
+   vec.push(item1);
+}
+for _ in 0..30 {
+    vec.push(item2);
+}
+```
+
+Use instead:
+```
+let item1 = 2;
+let item2 = 3;
+let mut vec: Vec<u8> = vec![item1; 20];
+vec.resize(20 + 30, item2);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/same_name_method.txt b/src/tools/clippy/src/docs/same_name_method.txt
new file mode 100644 (file)
index 0000000..792dd71
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+It lints if a struct has two methods with the same name:
+one from a trait, another not from trait.
+
+### Why is this bad?
+Confusing.
+
+### Example
+```
+trait T {
+    fn foo(&self) {}
+}
+
+struct S;
+
+impl T for S {
+    fn foo(&self) {}
+}
+
+impl S {
+    fn foo(&self) {}
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/search_is_some.txt b/src/tools/clippy/src/docs/search_is_some.txt
new file mode 100644 (file)
index 0000000..67292d5
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for an iterator or string search (such as `find()`,
+`position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`.
+
+### Why is this bad?
+Readability, this can be written more concisely as:
+* `_.any(_)`, or `_.contains(_)` for `is_some()`,
+* `!_.any(_)`, or `!_.contains(_)` for `is_none()`.
+
+### Example
+```
+let vec = vec![1];
+vec.iter().find(|x| **x == 0).is_some();
+
+"hello world".find("world").is_none();
+```
+
+Use instead:
+```
+let vec = vec![1];
+vec.iter().any(|x| *x == 0);
+
+!"hello world".contains("world");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/self_assignment.txt b/src/tools/clippy/src/docs/self_assignment.txt
new file mode 100644 (file)
index 0000000..ea60ea0
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Checks for explicit self-assignments.
+
+### Why is this bad?
+Self-assignments are redundant and unlikely to be
+intentional.
+
+### Known problems
+If expression contains any deref coercions or
+indexing operations they are assumed not to have any side effects.
+
+### Example
+```
+struct Event {
+    x: i32,
+}
+
+fn copy_position(a: &mut Event, b: &Event) {
+    a.x = a.x;
+}
+```
+
+Should be:
+```
+struct Event {
+    x: i32,
+}
+
+fn copy_position(a: &mut Event, b: &Event) {
+    a.x = b.x;
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/self_named_constructors.txt b/src/tools/clippy/src/docs/self_named_constructors.txt
new file mode 100644 (file)
index 0000000..a01669a
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Warns when constructors have the same name as their types.
+
+### Why is this bad?
+Repeating the name of the type is redundant.
+
+### Example
+```
+struct Foo {}
+
+impl Foo {
+    pub fn foo() -> Foo {
+        Foo {}
+    }
+}
+```
+Use instead:
+```
+struct Foo {}
+
+impl Foo {
+    pub fn new() -> Foo {
+        Foo {}
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/self_named_module_files.txt b/src/tools/clippy/src/docs/self_named_module_files.txt
new file mode 100644 (file)
index 0000000..73e8051
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks that module layout uses only `mod.rs` files.
+
+### Why is this bad?
+Having multiple module layout styles in a project can be confusing.
+
+### Example
+```
+src/
+  stuff/
+    stuff_files.rs
+  stuff.rs
+  lib.rs
+```
+Use instead:
+```
+src/
+  stuff/
+    stuff_files.rs
+    mod.rs
+  lib.rs
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/semicolon_if_nothing_returned.txt b/src/tools/clippy/src/docs/semicolon_if_nothing_returned.txt
new file mode 100644 (file)
index 0000000..30c963c
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Looks for blocks of expressions and fires if the last expression returns
+`()` but is not followed by a semicolon.
+
+### Why is this bad?
+The semicolon might be optional but when extending the block with new
+code, it doesn't require a change in previous last line.
+
+### Example
+```
+fn main() {
+    println!("Hello world")
+}
+```
+Use instead:
+```
+fn main() {
+    println!("Hello world");
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/separated_literal_suffix.txt b/src/tools/clippy/src/docs/separated_literal_suffix.txt
new file mode 100644 (file)
index 0000000..226a6b8
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Warns if literal suffixes are separated by an underscore.
+To enforce separated literal suffix style,
+see the `unseparated_literal_suffix` lint.
+
+### Why is this bad?
+Suffix style should be consistent.
+
+### Example
+```
+123832_i32
+```
+
+Use instead:
+```
+123832i32
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/serde_api_misuse.txt b/src/tools/clippy/src/docs/serde_api_misuse.txt
new file mode 100644 (file)
index 0000000..8a3c89a
--- /dev/null
@@ -0,0 +1,10 @@
+### What it does
+Checks for mis-uses of the serde API.
+
+### Why is this bad?
+Serde is very finnicky about how its API should be
+used, but the type system can't be used to enforce it (yet?).
+
+### Example
+Implementing `Visitor::visit_string` but not
+`Visitor::visit_str`.
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/shadow_reuse.txt b/src/tools/clippy/src/docs/shadow_reuse.txt
new file mode 100644 (file)
index 0000000..9eb8e7a
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for bindings that shadow other bindings already in
+scope, while reusing the original value.
+
+### Why is this bad?
+Not too much, in fact it's a common pattern in Rust
+code. Still, some argue that name shadowing like this hurts readability,
+because a value may be bound to different things depending on position in
+the code.
+
+### Example
+```
+let x = 2;
+let x = x + 1;
+```
+use different variable name:
+```
+let x = 2;
+let y = x + 1;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/shadow_same.txt b/src/tools/clippy/src/docs/shadow_same.txt
new file mode 100644 (file)
index 0000000..3cd96f5
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for bindings that shadow other bindings already in
+scope, while just changing reference level or mutability.
+
+### Why is this bad?
+Not much, in fact it's a very common pattern in Rust
+code. Still, some may opt to avoid it in their code base, they can set this
+lint to `Warn`.
+
+### Example
+```
+let x = &x;
+```
+
+Use instead:
+```
+let y = &x; // use different variable name
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/shadow_unrelated.txt b/src/tools/clippy/src/docs/shadow_unrelated.txt
new file mode 100644 (file)
index 0000000..436251c
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for bindings that shadow other bindings already in
+scope, either without an initialization or with one that does not even use
+the original value.
+
+### Why is this bad?
+Name shadowing can hurt readability, especially in
+large code bases, because it is easy to lose track of the active binding at
+any place in the code. This can be alleviated by either giving more specific
+names to bindings or introducing more scopes to contain the bindings.
+
+### Example
+```
+let x = y;
+let x = z; // shadows the earlier binding
+```
+
+Use instead:
+```
+let x = y;
+let w = z; // use different variable name
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/short_circuit_statement.txt b/src/tools/clippy/src/docs/short_circuit_statement.txt
new file mode 100644 (file)
index 0000000..31492be
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for the use of short circuit boolean conditions as
+a
+statement.
+
+### Why is this bad?
+Using a short circuit boolean condition as a statement
+may hide the fact that the second part is executed or not depending on the
+outcome of the first part.
+
+### Example
+```
+f() && g(); // We should write `if f() { g(); }`.
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/should_implement_trait.txt b/src/tools/clippy/src/docs/should_implement_trait.txt
new file mode 100644 (file)
index 0000000..02e7475
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for methods that should live in a trait
+implementation of a `std` trait (see [llogiq's blog
+post](http://llogiq.github.io/2015/07/30/traits.html) for further
+information) instead of an inherent implementation.
+
+### Why is this bad?
+Implementing the traits improve ergonomics for users of
+the code, often with very little cost. Also people seeing a `mul(...)`
+method
+may expect `*` to work equally, so you should have good reason to disappoint
+them.
+
+### Example
+```
+struct X;
+impl X {
+    fn add(&self, other: &X) -> X {
+        // ..
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/significant_drop_in_scrutinee.txt b/src/tools/clippy/src/docs/significant_drop_in_scrutinee.txt
new file mode 100644 (file)
index 0000000..f869def
--- /dev/null
@@ -0,0 +1,43 @@
+### What it does
+Check for temporaries returned from function calls in a match scrutinee that have the
+`clippy::has_significant_drop` attribute.
+
+### Why is this bad?
+The `clippy::has_significant_drop` attribute can be added to types whose Drop impls have
+an important side-effect, such as unlocking a mutex, making it important for users to be
+able to accurately understand their lifetimes. When a temporary is returned in a function
+call in a match scrutinee, its lifetime lasts until the end of the match block, which may
+be surprising.
+
+For `Mutex`es this can lead to a deadlock. This happens when the match scrutinee uses a
+function call that returns a `MutexGuard` and then tries to lock again in one of the match
+arms. In that case the `MutexGuard` in the scrutinee will not be dropped until the end of
+the match block and thus will not unlock.
+
+### Example
+```
+let mutex = Mutex::new(State {});
+
+match mutex.lock().unwrap().foo() {
+    true => {
+        mutex.lock().unwrap().bar(); // Deadlock!
+    }
+    false => {}
+};
+
+println!("All done!");
+```
+Use instead:
+```
+let mutex = Mutex::new(State {});
+
+let is_foo = mutex.lock().unwrap().foo();
+match is_foo {
+    true => {
+        mutex.lock().unwrap().bar();
+    }
+    false => {}
+};
+
+println!("All done!");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/similar_names.txt b/src/tools/clippy/src/docs/similar_names.txt
new file mode 100644 (file)
index 0000000..13aca9c
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for names that are very similar and thus confusing.
+
+### Why is this bad?
+It's hard to distinguish between names that differ only
+by a single character.
+
+### Example
+```
+let checked_exp = something;
+let checked_expr = something_else;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_char_add_str.txt b/src/tools/clippy/src/docs/single_char_add_str.txt
new file mode 100644 (file)
index 0000000..cf23dc0
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Warns when using `push_str`/`insert_str` with a single-character string literal
+where `push`/`insert` with a `char` would work fine.
+
+### Why is this bad?
+It's less clear that we are pushing a single character.
+
+### Example
+```
+string.insert_str(0, "R");
+string.push_str("R");
+```
+
+Use instead:
+```
+string.insert(0, 'R');
+string.push('R');
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_char_lifetime_names.txt b/src/tools/clippy/src/docs/single_char_lifetime_names.txt
new file mode 100644 (file)
index 0000000..92dd24b
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+Checks for lifetimes with names which are one character
+long.
+
+### Why is this bad?
+A single character is likely not enough to express the
+purpose of a lifetime. Using a longer name can make code
+easier to understand, especially for those who are new to
+Rust.
+
+### Known problems
+Rust programmers and learning resources tend to use single
+character lifetimes, so this lint is at odds with the
+ecosystem at large. In addition, the lifetime's purpose may
+be obvious or, rarely, expressible in one character.
+
+### Example
+```
+struct DiagnosticCtx<'a> {
+    source: &'a str,
+}
+```
+Use instead:
+```
+struct DiagnosticCtx<'src> {
+    source: &'src str,
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_char_pattern.txt b/src/tools/clippy/src/docs/single_char_pattern.txt
new file mode 100644 (file)
index 0000000..9e5ad1e
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for string methods that receive a single-character
+`str` as an argument, e.g., `_.split("x")`.
+
+### Why is this bad?
+Performing these methods using a `char` is faster than
+using a `str`.
+
+### Known problems
+Does not catch multi-byte unicode characters.
+
+### Example
+```
+_.split("x");
+```
+
+Use instead:
+```
+_.split('x');
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_component_path_imports.txt b/src/tools/clippy/src/docs/single_component_path_imports.txt
new file mode 100644 (file)
index 0000000..3a02638
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checking for imports with single component use path.
+
+### Why is this bad?
+Import with single component use path such as `use cratename;`
+is not necessary, and thus should be removed.
+
+### Example
+```
+use regex;
+
+fn main() {
+    regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
+}
+```
+Better as
+```
+fn main() {
+    regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_element_loop.txt b/src/tools/clippy/src/docs/single_element_loop.txt
new file mode 100644 (file)
index 0000000..6f0c15a
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks whether a for loop has a single element.
+
+### Why is this bad?
+There is no reason to have a loop of a
+single element.
+
+### Example
+```
+let item1 = 2;
+for item in &[item1] {
+    println!("{}", item);
+}
+```
+
+Use instead:
+```
+let item1 = 2;
+let item = &item1;
+println!("{}", item);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_match.txt b/src/tools/clippy/src/docs/single_match.txt
new file mode 100644 (file)
index 0000000..31dde4d
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for matches with a single arm where an `if let`
+will usually suffice.
+
+### Why is this bad?
+Just readability – `if let` nests less than a `match`.
+
+### Example
+```
+match x {
+    Some(ref foo) => bar(foo),
+    _ => (),
+}
+```
+
+Use instead:
+```
+if let Some(ref foo) = x {
+    bar(foo);
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_match_else.txt b/src/tools/clippy/src/docs/single_match_else.txt
new file mode 100644 (file)
index 0000000..29a447a
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for matches with two arms where an `if let else` will
+usually suffice.
+
+### Why is this bad?
+Just readability – `if let` nests less than a `match`.
+
+### Known problems
+Personal style preferences may differ.
+
+### Example
+Using `match`:
+
+```
+match x {
+    Some(ref foo) => bar(foo),
+    _ => bar(&other_ref),
+}
+```
+
+Using `if let` with `else`:
+
+```
+if let Some(ref foo) = x {
+    bar(foo);
+} else {
+    bar(&other_ref);
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/size_of_in_element_count.txt b/src/tools/clippy/src/docs/size_of_in_element_count.txt
new file mode 100644 (file)
index 0000000..d893ec6
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Detects expressions where
+`size_of::<T>` or `size_of_val::<T>` is used as a
+count of elements of type `T`
+
+### Why is this bad?
+These functions expect a count
+of `T` and not a number of bytes
+
+### Example
+```
+const SIZE: usize = 128;
+let x = [2u8; SIZE];
+let mut y = [2u8; SIZE];
+unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/skip_while_next.txt b/src/tools/clippy/src/docs/skip_while_next.txt
new file mode 100644 (file)
index 0000000..1ec8a3a
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `_.skip_while(condition).next()`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.find(!condition)`.
+
+### Example
+```
+vec.iter().skip_while(|x| **x == 0).next();
+```
+
+Use instead:
+```
+vec.iter().find(|x| **x != 0);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/slow_vector_initialization.txt b/src/tools/clippy/src/docs/slow_vector_initialization.txt
new file mode 100644 (file)
index 0000000..53442e1
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks slow zero-filled vector initialization
+
+### Why is this bad?
+These structures are non-idiomatic and less efficient than simply using
+`vec![0; len]`.
+
+### Example
+```
+let mut vec1 = Vec::with_capacity(len);
+vec1.resize(len, 0);
+
+let mut vec1 = Vec::with_capacity(len);
+vec1.resize(vec1.capacity(), 0);
+
+let mut vec2 = Vec::with_capacity(len);
+vec2.extend(repeat(0).take(len));
+```
+
+Use instead:
+```
+let mut vec1 = vec![0; len];
+let mut vec2 = vec![0; len];
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/stable_sort_primitive.txt b/src/tools/clippy/src/docs/stable_sort_primitive.txt
new file mode 100644 (file)
index 0000000..6465dbe
--- /dev/null
@@ -0,0 +1,31 @@
+### What it does
+When sorting primitive values (integers, bools, chars, as well
+as arrays, slices, and tuples of such items), it is typically better to
+use an unstable sort than a stable sort.
+
+### Why is this bad?
+Typically, using a stable sort consumes more memory and cpu cycles.
+Because values which compare equal are identical, preserving their
+relative order (the guarantee that a stable sort provides) means
+nothing, while the extra costs still apply.
+
+### Known problems
+
+As pointed out in
+[issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241),
+a stable sort can instead be significantly faster for certain scenarios
+(eg. when a sorted vector is extended with new data and resorted).
+
+For more information and benchmarking results, please refer to the
+issue linked above.
+
+### Example
+```
+let mut vec = vec![2, 1, 3];
+vec.sort();
+```
+Use instead:
+```
+let mut vec = vec![2, 1, 3];
+vec.sort_unstable();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/std_instead_of_alloc.txt b/src/tools/clippy/src/docs/std_instead_of_alloc.txt
new file mode 100644 (file)
index 0000000..c2d3270
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+
+Finds items imported through `std` when available through `alloc`.
+
+### Why is this bad?
+
+Crates which have `no_std` compatibility and require alloc may wish to ensure types are imported from
+alloc to ensure disabling `std` does not cause the crate to fail to compile. This lint is also useful
+for crates migrating to become `no_std` compatible.
+
+### Example
+```
+use std::vec::Vec;
+```
+Use instead:
+```
+use alloc::vec::Vec;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/std_instead_of_core.txt b/src/tools/clippy/src/docs/std_instead_of_core.txt
new file mode 100644 (file)
index 0000000..f1e1518
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+
+Finds items imported through `std` when available through `core`.
+
+### Why is this bad?
+
+Crates which have `no_std` compatibility may wish to ensure types are imported from core to ensure
+disabling `std` does not cause the crate to fail to compile. This lint is also useful for crates
+migrating to become `no_std` compatible.
+
+### Example
+```
+use std::hash::Hasher;
+```
+Use instead:
+```
+use core::hash::Hasher;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/str_to_string.txt b/src/tools/clippy/src/docs/str_to_string.txt
new file mode 100644 (file)
index 0000000..a247552
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+This lint checks for `.to_string()` method calls on values of type `&str`.
+
+### Why is this bad?
+The `to_string` method is also used on other types to convert them to a string.
+When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better
+expressed with `.to_owned()`.
+
+### Example
+```
+// example code where clippy issues a warning
+let _ = "str".to_string();
+```
+Use instead:
+```
+// example code which does not raise clippy warning
+let _ = "str".to_owned();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_add.txt b/src/tools/clippy/src/docs/string_add.txt
new file mode 100644 (file)
index 0000000..23dafd0
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for all instances of `x + _` where `x` is of type
+`String`, but only if [`string_add_assign`](#string_add_assign) does *not*
+match.
+
+### Why is this bad?
+It's not bad in and of itself. However, this particular
+`Add` implementation is asymmetric (the other operand need not be `String`,
+but `x` does), while addition as mathematically defined is symmetric, also
+the `String::push_str(_)` function is a perfectly good replacement.
+Therefore, some dislike it and wish not to have it in their code.
+
+That said, other people think that string addition, having a long tradition
+in other languages is actually fine, which is why we decided to make this
+particular lint `allow` by default.
+
+### Example
+```
+let x = "Hello".to_owned();
+x + ", World";
+```
+
+Use instead:
+```
+let mut x = "Hello".to_owned();
+x.push_str(", World");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_add_assign.txt b/src/tools/clippy/src/docs/string_add_assign.txt
new file mode 100644 (file)
index 0000000..7438be8
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for string appends of the form `x = x + y` (without
+`let`!).
+
+### Why is this bad?
+It's not really bad, but some people think that the
+`.push_str(_)` method is more readable.
+
+### Example
+```
+let mut x = "Hello".to_owned();
+x = x + ", World";
+
+// More readable
+x += ", World";
+x.push_str(", World");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_extend_chars.txt b/src/tools/clippy/src/docs/string_extend_chars.txt
new file mode 100644 (file)
index 0000000..619ea3e
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for the use of `.extend(s.chars())` where s is a
+`&str` or `String`.
+
+### Why is this bad?
+`.push_str(s)` is clearer
+
+### Example
+```
+let abc = "abc";
+let def = String::from("def");
+let mut s = String::new();
+s.extend(abc.chars());
+s.extend(def.chars());
+```
+The correct use would be:
+```
+let abc = "abc";
+let def = String::from("def");
+let mut s = String::new();
+s.push_str(abc);
+s.push_str(&def);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_from_utf8_as_bytes.txt b/src/tools/clippy/src/docs/string_from_utf8_as_bytes.txt
new file mode 100644 (file)
index 0000000..9102d73
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Check if the string is transformed to byte array and casted back to string.
+
+### Why is this bad?
+It's unnecessary, the string can be used directly.
+
+### Example
+```
+std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap();
+```
+
+Use instead:
+```
+&"Hello World!"[6..11];
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_lit_as_bytes.txt b/src/tools/clippy/src/docs/string_lit_as_bytes.txt
new file mode 100644 (file)
index 0000000..a125b97
--- /dev/null
@@ -0,0 +1,39 @@
+### What it does
+Checks for the `as_bytes` method called on string literals
+that contain only ASCII characters.
+
+### Why is this bad?
+Byte string literals (e.g., `b"foo"`) can be used
+instead. They are shorter but less discoverable than `as_bytes()`.
+
+### Known problems
+`"str".as_bytes()` and the suggested replacement of `b"str"` are not
+equivalent because they have different types. The former is `&[u8]`
+while the latter is `&[u8; 3]`. That means in general they will have a
+different set of methods and different trait implementations.
+
+```
+fn f(v: Vec<u8>) {}
+
+f("...".as_bytes().to_owned()); // works
+f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec<u8>
+
+fn g(r: impl std::io::Read) {}
+
+g("...".as_bytes()); // works
+g(b"..."); // does not work
+```
+
+The actual equivalent of `"str".as_bytes()` with the same type is not
+`b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not
+more readable than a function call.
+
+### Example
+```
+let bstr = "a byte string".as_bytes();
+```
+
+Use instead:
+```
+let bstr = b"a byte string";
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_slice.txt b/src/tools/clippy/src/docs/string_slice.txt
new file mode 100644 (file)
index 0000000..3d9e49d
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for slice operations on strings
+
+### Why is this bad?
+UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character
+counts and string indices. This may lead to panics, and should warrant some test cases
+containing wide UTF-8 characters. This lint is most useful in code that should avoid
+panics at all costs.
+
+### Known problems
+Probably lots of false positives. If an index comes from a known valid position (e.g.
+obtained via `char_indices` over the same string), it is totally OK.
+
+# Example
+```
+&"Ölkanne"[1..];
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_to_string.txt b/src/tools/clippy/src/docs/string_to_string.txt
new file mode 100644 (file)
index 0000000..deb7eeb
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+This lint checks for `.to_string()` method calls on values of type `String`.
+
+### Why is this bad?
+The `to_string` method is also used on other types to convert them to a string.
+When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`.
+
+### Example
+```
+// example code where clippy issues a warning
+let msg = String::from("Hello World");
+let _ = msg.to_string();
+```
+Use instead:
+```
+// example code which does not raise clippy warning
+let msg = String::from("Hello World");
+let _ = msg.clone();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/strlen_on_c_strings.txt b/src/tools/clippy/src/docs/strlen_on_c_strings.txt
new file mode 100644 (file)
index 0000000..0454abf
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for usage of `libc::strlen` on a `CString` or `CStr` value,
+and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead.
+
+### Why is this bad?
+This avoids calling an unsafe `libc` function.
+Currently, it also avoids calculating the length.
+
+### Example
+```
+use std::ffi::CString;
+let cstring = CString::new("foo").expect("CString::new failed");
+let len = unsafe { libc::strlen(cstring.as_ptr()) };
+```
+Use instead:
+```
+use std::ffi::CString;
+let cstring = CString::new("foo").expect("CString::new failed");
+let len = cstring.as_bytes().len();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/struct_excessive_bools.txt b/src/tools/clippy/src/docs/struct_excessive_bools.txt
new file mode 100644 (file)
index 0000000..9e197c7
--- /dev/null
@@ -0,0 +1,29 @@
+### What it does
+Checks for excessive
+use of bools in structs.
+
+### Why is this bad?
+Excessive bools in a struct
+is often a sign that it's used as a state machine,
+which is much better implemented as an enum.
+If it's not the case, excessive bools usually benefit
+from refactoring into two-variant enums for better
+readability and API.
+
+### Example
+```
+struct S {
+    is_pending: bool,
+    is_processing: bool,
+    is_finished: bool,
+}
+```
+
+Use instead:
+```
+enum S {
+    Pending,
+    Processing,
+    Finished,
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suboptimal_flops.txt b/src/tools/clippy/src/docs/suboptimal_flops.txt
new file mode 100644 (file)
index 0000000..f1c9c66
--- /dev/null
@@ -0,0 +1,50 @@
+### What it does
+Looks for floating-point expressions that
+can be expressed using built-in methods to improve both
+accuracy and performance.
+
+### Why is this bad?
+Negatively impacts accuracy and performance.
+
+### Example
+```
+use std::f32::consts::E;
+
+let a = 3f32;
+let _ = (2f32).powf(a);
+let _ = E.powf(a);
+let _ = a.powf(1.0 / 2.0);
+let _ = a.log(2.0);
+let _ = a.log(10.0);
+let _ = a.log(E);
+let _ = a.powf(2.0);
+let _ = a * 2.0 + 4.0;
+let _ = if a < 0.0 {
+    -a
+} else {
+    a
+};
+let _ = if a < 0.0 {
+    a
+} else {
+    -a
+};
+```
+
+is better expressed as
+
+```
+use std::f32::consts::E;
+
+let a = 3f32;
+let _ = a.exp2();
+let _ = a.exp();
+let _ = a.sqrt();
+let _ = a.log2();
+let _ = a.log10();
+let _ = a.ln();
+let _ = a.powi(2);
+let _ = a.mul_add(2.0, 4.0);
+let _ = a.abs();
+let _ = -a.abs();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_arithmetic_impl.txt b/src/tools/clippy/src/docs/suspicious_arithmetic_impl.txt
new file mode 100644 (file)
index 0000000..d67ff27
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Lints for suspicious operations in impls of arithmetic operators, e.g.
+subtracting elements in an Add impl.
+
+### Why is this bad?
+This is probably a typo or copy-and-paste error and not intended.
+
+### Example
+```
+impl Add for Foo {
+    type Output = Foo;
+
+    fn add(self, other: Foo) -> Foo {
+        Foo(self.0 - other.0)
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_assignment_formatting.txt b/src/tools/clippy/src/docs/suspicious_assignment_formatting.txt
new file mode 100644 (file)
index 0000000..b889827
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for use of the non-existent `=*`, `=!` and `=-`
+operators.
+
+### Why is this bad?
+This is either a typo of `*=`, `!=` or `-=` or
+confusing.
+
+### Example
+```
+a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_else_formatting.txt b/src/tools/clippy/src/docs/suspicious_else_formatting.txt
new file mode 100644 (file)
index 0000000..3cf2f74
--- /dev/null
@@ -0,0 +1,30 @@
+### What it does
+Checks for formatting of `else`. It lints if the `else`
+is followed immediately by a newline or the `else` seems to be missing.
+
+### Why is this bad?
+This is probably some refactoring remnant, even if the
+code is correct, it might look confusing.
+
+### Example
+```
+if foo {
+} { // looks like an `else` is missing here
+}
+
+if foo {
+} if bar { // looks like an `else` is missing here
+}
+
+if foo {
+} else
+
+{ // this is the `else` block of the previous `if`, but should it be?
+}
+
+if foo {
+} else
+
+if bar { // this is the `else` block of the previous `if`, but should it be?
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_map.txt b/src/tools/clippy/src/docs/suspicious_map.txt
new file mode 100644 (file)
index 0000000..d8fa52c
--- /dev/null
@@ -0,0 +1,13 @@
+### What it does
+Checks for calls to `map` followed by a `count`.
+
+### Why is this bad?
+It looks suspicious. Maybe `map` was confused with `filter`.
+If the `map` call is intentional, this should be rewritten
+using `inspect`. Or, if you intend to drive the iterator to
+completion, you can just use `for_each` instead.
+
+### Example
+```
+let _ = (0..3).map(|x| x + 2).count();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_op_assign_impl.txt b/src/tools/clippy/src/docs/suspicious_op_assign_impl.txt
new file mode 100644 (file)
index 0000000..81abfbe
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Lints for suspicious operations in impls of OpAssign, e.g.
+subtracting elements in an AddAssign impl.
+
+### Why is this bad?
+This is probably a typo or copy-and-paste error and not intended.
+
+### Example
+```
+impl AddAssign for Foo {
+    fn add_assign(&mut self, other: Foo) {
+        *self = *self - other;
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_operation_groupings.txt b/src/tools/clippy/src/docs/suspicious_operation_groupings.txt
new file mode 100644 (file)
index 0000000..81ede5d
--- /dev/null
@@ -0,0 +1,41 @@
+### What it does
+Checks for unlikely usages of binary operators that are almost
+certainly typos and/or copy/paste errors, given the other usages
+of binary operators nearby.
+
+### Why is this bad?
+They are probably bugs and if they aren't then they look like bugs
+and you should add a comment explaining why you are doing such an
+odd set of operations.
+
+### Known problems
+There may be some false positives if you are trying to do something
+unusual that happens to look like a typo.
+
+### Example
+```
+struct Vec3 {
+    x: f64,
+    y: f64,
+    z: f64,
+}
+
+impl Eq for Vec3 {}
+
+impl PartialEq for Vec3 {
+    fn eq(&self, other: &Self) -> bool {
+        // This should trigger the lint because `self.x` is compared to `other.y`
+        self.x == other.y && self.y == other.y && self.z == other.z
+    }
+}
+```
+Use instead:
+```
+// same as above except:
+impl PartialEq for Vec3 {
+    fn eq(&self, other: &Self) -> bool {
+        // Note we now compare other.x to self.x
+        self.x == other.x && self.y == other.y && self.z == other.z
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_splitn.txt b/src/tools/clippy/src/docs/suspicious_splitn.txt
new file mode 100644 (file)
index 0000000..79a3dbf
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for calls to [`splitn`]
+(https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
+related functions with either zero or one splits.
+
+### Why is this bad?
+These calls don't actually split the value and are
+likely to be intended as a different number.
+
+### Example
+```
+for x in s.splitn(1, ":") {
+    // ..
+}
+```
+
+Use instead:
+```
+for x in s.splitn(2, ":") {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_to_owned.txt b/src/tools/clippy/src/docs/suspicious_to_owned.txt
new file mode 100644 (file)
index 0000000..8cbf61d
--- /dev/null
@@ -0,0 +1,39 @@
+### What it does
+Checks for the usage of `_.to_owned()`, on a `Cow<'_, _>`.
+
+### Why is this bad?
+Calling `to_owned()` on a `Cow` creates a clone of the `Cow`
+itself, without taking ownership of the `Cow` contents (i.e.
+it's equivalent to calling `Cow::clone`).
+The similarly named `into_owned` method, on the other hand,
+clones the `Cow` contents, effectively turning any `Cow::Borrowed`
+into a `Cow::Owned`.
+
+Given the potential ambiguity, consider replacing `to_owned`
+with `clone` for better readability or, if getting a `Cow::Owned`
+was the original intent, using `into_owned` instead.
+
+### Example
+```
+let s = "Hello world!";
+let cow = Cow::Borrowed(s);
+
+let data = cow.to_owned();
+assert!(matches!(data, Cow::Borrowed(_)))
+```
+Use instead:
+```
+let s = "Hello world!";
+let cow = Cow::Borrowed(s);
+
+let data = cow.clone();
+assert!(matches!(data, Cow::Borrowed(_)))
+```
+or
+```
+let s = "Hello world!";
+let cow = Cow::Borrowed(s);
+
+let data = cow.into_owned();
+assert!(matches!(data, String))
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_unary_op_formatting.txt b/src/tools/clippy/src/docs/suspicious_unary_op_formatting.txt
new file mode 100644 (file)
index 0000000..06fb09d
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks the formatting of a unary operator on the right hand side
+of a binary operator. It lints if there is no space between the binary and unary operators,
+but there is a space between the unary and its operand.
+
+### Why is this bad?
+This is either a typo in the binary operator or confusing.
+
+### Example
+```
+// &&! looks like a different operator
+if foo &&! bar {}
+```
+
+Use instead:
+```
+if foo && !bar {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/swap_ptr_to_ref.txt b/src/tools/clippy/src/docs/swap_ptr_to_ref.txt
new file mode 100644 (file)
index 0000000..0215d1e
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for calls to `core::mem::swap` where either parameter is derived from a pointer
+
+### Why is this bad?
+When at least one parameter to `swap` is derived from a pointer it may overlap with the
+other. This would then lead to undefined behavior.
+
+### Example
+```
+unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) {
+    for (&x, &y) in x.iter().zip(y) {
+        core::mem::swap(&mut *x, &mut *y);
+    }
+}
+```
+Use instead:
+```
+unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) {
+    for (&x, &y) in x.iter().zip(y) {
+        core::ptr::swap(x, y);
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/tabs_in_doc_comments.txt b/src/tools/clippy/src/docs/tabs_in_doc_comments.txt
new file mode 100644 (file)
index 0000000..f83dbe2
--- /dev/null
@@ -0,0 +1,44 @@
+### What it does
+Checks doc comments for usage of tab characters.
+
+### Why is this bad?
+The rust style-guide promotes spaces instead of tabs for indentation.
+To keep a consistent view on the source, also doc comments should not have tabs.
+Also, explaining ascii-diagrams containing tabs can get displayed incorrectly when the
+display settings of the author and reader differ.
+
+### Example
+```
+///
+/// Struct to hold two strings:
+///    - first         one
+///    - second        one
+pub struct DoubleString {
+   ///
+   ///         - First String:
+   ///                 - needs to be inside here
+   first_string: String,
+   ///
+   ///         - Second String:
+   ///                 - needs to be inside here
+   second_string: String,
+}
+```
+
+Will be converted to:
+```
+///
+/// Struct to hold two strings:
+///     - first        one
+///     - second    one
+pub struct DoubleString {
+   ///
+   ///     - First String:
+   ///         - needs to be inside here
+   first_string: String,
+   ///
+   ///     - Second String:
+   ///         - needs to be inside here
+   second_string: String,
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/temporary_assignment.txt b/src/tools/clippy/src/docs/temporary_assignment.txt
new file mode 100644 (file)
index 0000000..195b42c
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for construction of a structure or tuple just to
+assign a value in it.
+
+### Why is this bad?
+Readability. If the structure is only created to be
+updated, why not write the structure you want in the first place?
+
+### Example
+```
+(0, 0).0 = 1
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/to_digit_is_some.txt b/src/tools/clippy/src/docs/to_digit_is_some.txt
new file mode 100644 (file)
index 0000000..eee8375
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for `.to_digit(..).is_some()` on `char`s.
+
+### Why is this bad?
+This is a convoluted way of checking if a `char` is a digit. It's
+more straight forward to use the dedicated `is_digit` method.
+
+### Example
+```
+let is_digit = c.to_digit(radix).is_some();
+```
+can be written as:
+```
+let is_digit = c.is_digit(radix);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/to_string_in_format_args.txt b/src/tools/clippy/src/docs/to_string_in_format_args.txt
new file mode 100644 (file)
index 0000000..34b2058
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string)
+applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html)
+in a macro that does formatting.
+
+### Why is this bad?
+Since the type implements `Display`, the use of `to_string` is
+unnecessary.
+
+### Example
+```
+println!("error: something failed at {}", Location::caller().to_string());
+```
+Use instead:
+```
+println!("error: something failed at {}", Location::caller());
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/todo.txt b/src/tools/clippy/src/docs/todo.txt
new file mode 100644 (file)
index 0000000..661eb1a
--- /dev/null
@@ -0,0 +1,10 @@
+### What it does
+Checks for usage of `todo!`.
+
+### Why is this bad?
+This macro should not be present in production code
+
+### Example
+```
+todo!();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/too_many_arguments.txt b/src/tools/clippy/src/docs/too_many_arguments.txt
new file mode 100644 (file)
index 0000000..4669f9f
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for functions with too many parameters.
+
+### Why is this bad?
+Functions with lots of parameters are considered bad
+style and reduce readability (“what does the 5th parameter mean?”). Consider
+grouping some parameters into a new type.
+
+### Example
+```
+fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/too_many_lines.txt b/src/tools/clippy/src/docs/too_many_lines.txt
new file mode 100644 (file)
index 0000000..425db34
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for functions with a large amount of lines.
+
+### Why is this bad?
+Functions with a lot of lines are harder to understand
+due to having to look at a larger amount of code to understand what the
+function is doing. Consider splitting the body of the function into
+multiple functions.
+
+### Example
+```
+fn im_too_long() {
+    println!("");
+    // ... 100 more LoC
+    println!("");
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/toplevel_ref_arg.txt b/src/tools/clippy/src/docs/toplevel_ref_arg.txt
new file mode 100644 (file)
index 0000000..96a9e2d
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+Checks for function arguments and let bindings denoted as
+`ref`.
+
+### Why is this bad?
+The `ref` declaration makes the function take an owned
+value, but turns the argument into a reference (which means that the value
+is destroyed when exiting the function). This adds not much value: either
+take a reference type, or take an owned value and create references in the
+body.
+
+For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The
+type of `x` is more obvious with the former.
+
+### Known problems
+If the argument is dereferenced within the function,
+removing the `ref` will lead to errors. This can be fixed by removing the
+dereferences, e.g., changing `*x` to `x` within the function.
+
+### Example
+```
+fn foo(ref _x: u8) {}
+```
+
+Use instead:
+```
+fn foo(_x: &u8) {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/trailing_empty_array.txt b/src/tools/clippy/src/docs/trailing_empty_array.txt
new file mode 100644 (file)
index 0000000..db1908c
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute.
+
+### Why is this bad?
+Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjunction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed.
+
+### Example
+```
+struct RarelyUseful {
+    some_field: u32,
+    last: [u32; 0],
+}
+```
+
+Use instead:
+```
+#[repr(C)]
+struct MoreOftenUseful {
+    some_field: usize,
+    last: [u32; 0],
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/trait_duplication_in_bounds.txt b/src/tools/clippy/src/docs/trait_duplication_in_bounds.txt
new file mode 100644 (file)
index 0000000..509736b
--- /dev/null
@@ -0,0 +1,37 @@
+### What it does
+Checks for cases where generics are being used and multiple
+syntax specifications for trait bounds are used simultaneously.
+
+### Why is this bad?
+Duplicate bounds makes the code
+less readable than specifying them only once.
+
+### Example
+```
+fn func<T: Clone + Default>(arg: T) where T: Clone + Default {}
+```
+
+Use instead:
+```
+fn func<T: Clone + Default>(arg: T) {}
+
+// or
+
+fn func<T>(arg: T) where T: Clone + Default {}
+```
+
+```
+fn foo<T: Default + Default>(bar: T) {}
+```
+Use instead:
+```
+fn foo<T: Default>(bar: T) {}
+```
+
+```
+fn foo<T>(bar: T) where T: Default + Default {}
+```
+Use instead:
+```
+fn foo<T>(bar: T) where T: Default {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_bytes_to_str.txt b/src/tools/clippy/src/docs/transmute_bytes_to_str.txt
new file mode 100644 (file)
index 0000000..75889b9
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for transmutes from a `&[u8]` to a `&str`.
+
+### Why is this bad?
+Not every byte slice is a valid UTF-8 string.
+
+### Known problems
+- [`from_utf8`] which this lint suggests using is slower than `transmute`
+as it needs to validate the input.
+If you are certain that the input is always a valid UTF-8,
+use [`from_utf8_unchecked`] which is as fast as `transmute`
+but has a semantically meaningful name.
+- You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`.
+
+[`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html
+[`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html
+
+### Example
+```
+let b: &[u8] = &[1_u8, 2_u8];
+unsafe {
+    let _: &str = std::mem::transmute(b); // where b: &[u8]
+}
+
+// should be:
+let _ = std::str::from_utf8(b).unwrap();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_float_to_int.txt b/src/tools/clippy/src/docs/transmute_float_to_int.txt
new file mode 100644 (file)
index 0000000..1877e5a
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes from a float to an integer.
+
+### Why is this bad?
+Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive
+and safe.
+
+### Example
+```
+unsafe {
+    let _: u32 = std::mem::transmute(1f32);
+}
+
+// should be:
+let _: u32 = 1f32.to_bits();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_int_to_bool.txt b/src/tools/clippy/src/docs/transmute_int_to_bool.txt
new file mode 100644 (file)
index 0000000..07c10f8
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes from an integer to a `bool`.
+
+### Why is this bad?
+This might result in an invalid in-memory representation of a `bool`.
+
+### Example
+```
+let x = 1_u8;
+unsafe {
+    let _: bool = std::mem::transmute(x); // where x: u8
+}
+
+// should be:
+let _: bool = x != 0;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_int_to_char.txt b/src/tools/clippy/src/docs/transmute_int_to_char.txt
new file mode 100644 (file)
index 0000000..836d22d
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for transmutes from an integer to a `char`.
+
+### Why is this bad?
+Not every integer is a Unicode scalar value.
+
+### Known problems
+- [`from_u32`] which this lint suggests using is slower than `transmute`
+as it needs to validate the input.
+If you are certain that the input is always a valid Unicode scalar value,
+use [`from_u32_unchecked`] which is as fast as `transmute`
+but has a semantically meaningful name.
+- You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`.
+
+[`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html
+[`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
+
+### Example
+```
+let x = 1_u32;
+unsafe {
+    let _: char = std::mem::transmute(x); // where x: u32
+}
+
+// should be:
+let _ = std::char::from_u32(x).unwrap();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_int_to_float.txt b/src/tools/clippy/src/docs/transmute_int_to_float.txt
new file mode 100644 (file)
index 0000000..75cdc62
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes from an integer to a float.
+
+### Why is this bad?
+Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive
+and safe.
+
+### Example
+```
+unsafe {
+    let _: f32 = std::mem::transmute(1_u32); // where x: u32
+}
+
+// should be:
+let _: f32 = f32::from_bits(1_u32);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_num_to_bytes.txt b/src/tools/clippy/src/docs/transmute_num_to_bytes.txt
new file mode 100644 (file)
index 0000000..a2c39a1
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes from a number to an array of `u8`
+
+### Why this is bad?
+Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
+is intuitive and safe.
+
+### Example
+```
+unsafe {
+    let x: [u8; 8] = std::mem::transmute(1i64);
+}
+
+// should be
+let x: [u8; 8] = 0i64.to_ne_bytes();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_ptr_to_ptr.txt b/src/tools/clippy/src/docs/transmute_ptr_to_ptr.txt
new file mode 100644 (file)
index 0000000..65777db
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for transmutes from a pointer to a pointer, or
+from a reference to a reference.
+
+### Why is this bad?
+Transmutes are dangerous, and these can instead be
+written as casts.
+
+### Example
+```
+let ptr = &1u32 as *const u32;
+unsafe {
+    // pointer-to-pointer transmute
+    let _: *const f32 = std::mem::transmute(ptr);
+    // ref-ref transmute
+    let _: &f32 = std::mem::transmute(&1u32);
+}
+// These can be respectively written:
+let _ = ptr as *const f32;
+let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) };
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_ptr_to_ref.txt b/src/tools/clippy/src/docs/transmute_ptr_to_ref.txt
new file mode 100644 (file)
index 0000000..aca550f
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Checks for transmutes from a pointer to a reference.
+
+### Why is this bad?
+This can always be rewritten with `&` and `*`.
+
+### Known problems
+- `mem::transmute` in statics and constants is stable from Rust 1.46.0,
+while dereferencing raw pointer is not stable yet.
+If you need to do this in those places,
+you would have to use `transmute` instead.
+
+### Example
+```
+unsafe {
+    let _: &T = std::mem::transmute(p); // where p: *const T
+}
+
+// can be written:
+let _: &T = &*p;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_undefined_repr.txt b/src/tools/clippy/src/docs/transmute_undefined_repr.txt
new file mode 100644 (file)
index 0000000..5ee6aaf
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for transmutes between types which do not have a representation defined relative to
+each other.
+
+### Why is this bad?
+The results of such a transmute are not defined.
+
+### Known problems
+This lint has had multiple problems in the past and was moved to `nursery`. See issue
+[#8496](https://github.com/rust-lang/rust-clippy/issues/8496) for more details.
+
+### Example
+```
+struct Foo<T>(u32, T);
+let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
+```
+Use instead:
+```
+#[repr(C)]
+struct Foo<T>(u32, T);
+let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmutes_expressible_as_ptr_casts.txt b/src/tools/clippy/src/docs/transmutes_expressible_as_ptr_casts.txt
new file mode 100644 (file)
index 0000000..b68a8cd
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes that could be a pointer cast.
+
+### Why is this bad?
+Readability. The code tricks people into thinking that
+something complex is going on.
+
+### Example
+
+```
+unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) };
+```
+Use instead:
+```
+p as *const [u16];
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmuting_null.txt b/src/tools/clippy/src/docs/transmuting_null.txt
new file mode 100644 (file)
index 0000000..f8bacfc
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for transmute calls which would receive a null pointer.
+
+### Why is this bad?
+Transmuting a null pointer is undefined behavior.
+
+### Known problems
+Not all cases can be detected at the moment of this writing.
+For example, variables which hold a null pointer and are then fed to a `transmute`
+call, aren't detectable yet.
+
+### Example
+```
+let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/trim_split_whitespace.txt b/src/tools/clippy/src/docs/trim_split_whitespace.txt
new file mode 100644 (file)
index 0000000..f7e3e78
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Warns about calling `str::trim` (or variants) before `str::split_whitespace`.
+
+### Why is this bad?
+`split_whitespace` already ignores leading and trailing whitespace.
+
+### Example
+```
+" A B C ".trim().split_whitespace();
+```
+Use instead:
+```
+" A B C ".split_whitespace();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/trivial_regex.txt b/src/tools/clippy/src/docs/trivial_regex.txt
new file mode 100644 (file)
index 0000000..f71d667
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for trivial [regex](https://crates.io/crates/regex)
+creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`).
+
+### Why is this bad?
+Matching the regex can likely be replaced by `==` or
+`str::starts_with`, `str::ends_with` or `std::contains` or other `str`
+methods.
+
+### Known problems
+If the same regex is going to be applied to multiple
+inputs, the precomputations done by `Regex` construction can give
+significantly better performance than any of the `str`-based methods.
+
+### Example
+```
+Regex::new("^foobar")
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/trivially_copy_pass_by_ref.txt b/src/tools/clippy/src/docs/trivially_copy_pass_by_ref.txt
new file mode 100644 (file)
index 0000000..f54cce5
--- /dev/null
@@ -0,0 +1,43 @@
+### What it does
+Checks for functions taking arguments by reference, where
+the argument type is `Copy` and small enough to be more efficient to always
+pass by value.
+
+### Why is this bad?
+In many calling conventions instances of structs will
+be passed through registers if they fit into two or less general purpose
+registers.
+
+### Known problems
+This lint is target register size dependent, it is
+limited to 32-bit to try and reduce portability problems between 32 and
+64-bit, but if you are compiling for 8 or 16-bit targets then the limit
+will be different.
+
+The configuration option `trivial_copy_size_limit` can be set to override
+this limit for a project.
+
+This lint attempts to allow passing arguments by reference if a reference
+to that argument is returned. This is implemented by comparing the lifetime
+of the argument and return value for equality. However, this can cause
+false positives in cases involving multiple lifetimes that are bounded by
+each other.
+
+Also, it does not take account of other similar cases where getting memory addresses
+matters; namely, returning the pointer to the argument in question,
+and passing the argument, as both references and pointers,
+to a function that needs the memory address. For further details, refer to
+[this issue](https://github.com/rust-lang/rust-clippy/issues/5953)
+that explains a real case in which this false positive
+led to an **undefined behavior** introduced with unsafe code.
+
+### Example
+
+```
+fn foo(v: &u32) {}
+```
+
+Use instead:
+```
+fn foo(v: u32) {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/try_err.txt b/src/tools/clippy/src/docs/try_err.txt
new file mode 100644 (file)
index 0000000..e3d4ef3
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+Checks for usages of `Err(x)?`.
+
+### Why is this bad?
+The `?` operator is designed to allow calls that
+can fail to be easily chained. For example, `foo()?.bar()` or
+`foo(bar()?)`. Because `Err(x)?` can't be used that way (it will
+always return), it is more clear to write `return Err(x)`.
+
+### Example
+```
+fn foo(fail: bool) -> Result<i32, String> {
+    if fail {
+      Err("failed")?;
+    }
+    Ok(0)
+}
+```
+Could be written:
+
+```
+fn foo(fail: bool) -> Result<i32, String> {
+    if fail {
+      return Err("failed".into());
+    }
+    Ok(0)
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/type_complexity.txt b/src/tools/clippy/src/docs/type_complexity.txt
new file mode 100644 (file)
index 0000000..69cd875
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for types used in structs, parameters and `let`
+declarations above a certain complexity threshold.
+
+### Why is this bad?
+Too complex types make the code less readable. Consider
+using a `type` definition to simplify them.
+
+### Example
+```
+struct Foo {
+    inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/type_repetition_in_bounds.txt b/src/tools/clippy/src/docs/type_repetition_in_bounds.txt
new file mode 100644 (file)
index 0000000..18ed372
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+This lint warns about unnecessary type repetitions in trait bounds
+
+### Why is this bad?
+Repeating the type for every bound makes the code
+less readable than combining the bounds
+
+### Example
+```
+pub fn foo<T>(t: T) where T: Copy, T: Clone {}
+```
+
+Use instead:
+```
+pub fn foo<T>(t: T) where T: Copy + Clone {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/undocumented_unsafe_blocks.txt b/src/tools/clippy/src/docs/undocumented_unsafe_blocks.txt
new file mode 100644 (file)
index 0000000..f3af475
--- /dev/null
@@ -0,0 +1,43 @@
+### What it does
+Checks for `unsafe` blocks and impls without a `// SAFETY: ` comment
+explaining why the unsafe operations performed inside
+the block are safe.
+
+Note the comment must appear on the line(s) preceding the unsafe block
+with nothing appearing in between. The following is ok:
+```
+foo(
+    // SAFETY:
+    // This is a valid safety comment
+    unsafe { *x }
+)
+```
+But neither of these are:
+```
+// SAFETY:
+// This is not a valid safety comment
+foo(
+    /* SAFETY: Neither is this */ unsafe { *x },
+);
+```
+
+### Why is this bad?
+Undocumented unsafe blocks and impls can make it difficult to
+read and maintain code, as well as uncover unsoundness
+and bugs.
+
+### Example
+```
+use std::ptr::NonNull;
+let a = &mut 42;
+
+let ptr = unsafe { NonNull::new_unchecked(a) };
+```
+Use instead:
+```
+use std::ptr::NonNull;
+let a = &mut 42;
+
+// SAFETY: references are guaranteed to be non-null.
+let ptr = unsafe { NonNull::new_unchecked(a) };
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/undropped_manually_drops.txt b/src/tools/clippy/src/docs/undropped_manually_drops.txt
new file mode 100644 (file)
index 0000000..85e3ec5
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`.
+
+### Why is this bad?
+The safe `drop` function does not drop the inner value of a `ManuallyDrop`.
+
+### Known problems
+Does not catch cases if the user binds `std::mem::drop`
+to a different name and calls it that way.
+
+### Example
+```
+struct S;
+drop(std::mem::ManuallyDrop::new(S));
+```
+Use instead:
+```
+struct S;
+unsafe {
+    std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S));
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unicode_not_nfc.txt b/src/tools/clippy/src/docs/unicode_not_nfc.txt
new file mode 100644 (file)
index 0000000..c660c51
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for string literals that contain Unicode in a form
+that is not equal to its
+[NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms).
+
+### Why is this bad?
+If such a string is compared to another, the results
+may be surprising.
+
+### Example
+You may not see it, but "à"" and "à"" aren't the same string. The
+former when escaped is actually `"a\u{300}"` while the latter is `"\u{e0}"`.
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unimplemented.txt b/src/tools/clippy/src/docs/unimplemented.txt
new file mode 100644 (file)
index 0000000..7095594
--- /dev/null
@@ -0,0 +1,10 @@
+### What it does
+Checks for usage of `unimplemented!`.
+
+### Why is this bad?
+This macro should not be present in production code
+
+### Example
+```
+unimplemented!();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/uninit_assumed_init.txt b/src/tools/clippy/src/docs/uninit_assumed_init.txt
new file mode 100644 (file)
index 0000000..cca2409
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+Checks for `MaybeUninit::uninit().assume_init()`.
+
+### Why is this bad?
+For most types, this is undefined behavior.
+
+### Known problems
+For now, we accept empty tuples and tuples / arrays
+of `MaybeUninit`. There may be other types that allow uninitialized
+data, but those are not yet rigorously defined.
+
+### Example
+```
+// Beware the UB
+use std::mem::MaybeUninit;
+
+let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
+```
+
+Note that the following is OK:
+
+```
+use std::mem::MaybeUninit;
+
+let _: [MaybeUninit<bool>; 5] = unsafe {
+    MaybeUninit::uninit().assume_init()
+};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/uninit_vec.txt b/src/tools/clippy/src/docs/uninit_vec.txt
new file mode 100644 (file)
index 0000000..cd50afe
--- /dev/null
@@ -0,0 +1,41 @@
+### What it does
+Checks for `set_len()` call that creates `Vec` with uninitialized elements.
+This is commonly caused by calling `set_len()` right after allocating or
+reserving a buffer with `new()`, `default()`, `with_capacity()`, or `reserve()`.
+
+### Why is this bad?
+It creates a `Vec` with uninitialized data, which leads to
+undefined behavior with most safe operations. Notably, uninitialized
+`Vec<u8>` must not be used with generic `Read`.
+
+Moreover, calling `set_len()` on a `Vec` created with `new()` or `default()`
+creates out-of-bound values that lead to heap memory corruption when used.
+
+### Known Problems
+This lint only checks directly adjacent statements.
+
+### Example
+```
+let mut vec: Vec<u8> = Vec::with_capacity(1000);
+unsafe { vec.set_len(1000); }
+reader.read(&mut vec); // undefined behavior!
+```
+
+### How to fix?
+1. Use an initialized buffer:
+   ```rust,ignore
+   let mut vec: Vec<u8> = vec![0; 1000];
+   reader.read(&mut vec);
+   ```
+2. Wrap the content in `MaybeUninit`:
+   ```rust,ignore
+   let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
+   vec.set_len(1000);  // `MaybeUninit` can be uninitialized
+   ```
+3. If you are on 1.60.0 or later, `Vec::spare_capacity_mut()` is available:
+   ```rust,ignore
+   let mut vec: Vec<u8> = Vec::with_capacity(1000);
+   let remaining = vec.spare_capacity_mut();  // `&mut [MaybeUninit<u8>]`
+   // perform initialization with `remaining`
+   vec.set_len(...);  // Safe to call `set_len()` on initialized part
+   ```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unit_arg.txt b/src/tools/clippy/src/docs/unit_arg.txt
new file mode 100644 (file)
index 0000000..eb83403
--- /dev/null
@@ -0,0 +1,14 @@
+### What it does
+Checks for passing a unit value as an argument to a function without using a
+unit literal (`()`).
+
+### Why is this bad?
+This is likely the result of an accidental semicolon.
+
+### Example
+```
+foo({
+    let a = bar();
+    baz(a);
+})
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unit_cmp.txt b/src/tools/clippy/src/docs/unit_cmp.txt
new file mode 100644 (file)
index 0000000..6f3d620
--- /dev/null
@@ -0,0 +1,33 @@
+### What it does
+Checks for comparisons to unit. This includes all binary
+comparisons (like `==` and `<`) and asserts.
+
+### Why is this bad?
+Unit is always equal to itself, and thus is just a
+clumsily written constant. Mostly this happens when someone accidentally
+adds semicolons at the end of the operands.
+
+### Example
+```
+if {
+    foo();
+} == {
+    bar();
+} {
+    baz();
+}
+```
+is equal to
+```
+{
+    foo();
+    bar();
+    baz();
+}
+```
+
+For asserts:
+```
+assert_eq!({ foo(); }, { bar(); });
+```
+will always succeed
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unit_hash.txt b/src/tools/clippy/src/docs/unit_hash.txt
new file mode 100644 (file)
index 0000000..a22d299
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Detects `().hash(_)`.
+
+### Why is this bad?
+Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
+
+### Example
+```
+match my_enum {
+       Empty => ().hash(&mut state),
+       WithValue(x) => x.hash(&mut state),
+}
+```
+Use instead:
+```
+match my_enum {
+       Empty => 0_u8.hash(&mut state),
+       WithValue(x) => x.hash(&mut state),
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unit_return_expecting_ord.txt b/src/tools/clippy/src/docs/unit_return_expecting_ord.txt
new file mode 100644 (file)
index 0000000..781feac
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for functions that expect closures of type
+Fn(...) -> Ord where the implemented closure returns the unit type.
+The lint also suggests to remove the semi-colon at the end of the statement if present.
+
+### Why is this bad?
+Likely, returning the unit type is unintentional, and
+could simply be caused by an extra semi-colon. Since () implements Ord
+it doesn't cause a compilation error.
+This is the same reasoning behind the unit_cmp lint.
+
+### Known problems
+If returning unit is intentional, then there is no
+way of specifying this without triggering needless_return lint
+
+### Example
+```
+let mut twins = vec!((1, 1), (2, 2));
+twins.sort_by_key(|x| { x.1; });
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_cast.txt b/src/tools/clippy/src/docs/unnecessary_cast.txt
new file mode 100644 (file)
index 0000000..603f260
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for casts to the same type, casts of int literals to integer types
+and casts of float literals to float types.
+
+### Why is this bad?
+It's just unnecessary.
+
+### Example
+```
+let _ = 2i32 as i32;
+let _ = 0.5 as f32;
+```
+
+Better:
+
+```
+let _ = 2_i32;
+let _ = 0.5_f32;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_filter_map.txt b/src/tools/clippy/src/docs/unnecessary_filter_map.txt
new file mode 100644 (file)
index 0000000..b19341e
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for `filter_map` calls that could be replaced by `filter` or `map`.
+More specifically it checks if the closure provided is only performing one of the
+filter or map operations and suggests the appropriate option.
+
+### Why is this bad?
+Complexity. The intent is also clearer if only a single
+operation is being performed.
+
+### Example
+```
+let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
+
+// As there is no transformation of the argument this could be written as:
+let _ = (0..3).filter(|&x| x > 2);
+```
+
+```
+let _ = (0..4).filter_map(|x| Some(x + 1));
+
+// As there is no conditional check on the argument this could be written as:
+let _ = (0..4).map(|x| x + 1);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_find_map.txt b/src/tools/clippy/src/docs/unnecessary_find_map.txt
new file mode 100644 (file)
index 0000000..f9444dc
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for `find_map` calls that could be replaced by `find` or `map`. More
+specifically it checks if the closure provided is only performing one of the
+find or map operations and suggests the appropriate option.
+
+### Why is this bad?
+Complexity. The intent is also clearer if only a single
+operation is being performed.
+
+### Example
+```
+let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None });
+
+// As there is no transformation of the argument this could be written as:
+let _ = (0..3).find(|&x| x > 2);
+```
+
+```
+let _ = (0..4).find_map(|x| Some(x + 1));
+
+// As there is no conditional check on the argument this could be written as:
+let _ = (0..4).map(|x| x + 1).next();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_fold.txt b/src/tools/clippy/src/docs/unnecessary_fold.txt
new file mode 100644 (file)
index 0000000..e1b0e65
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for using `fold` when a more succinct alternative exists.
+Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
+`sum` or `product`.
+
+### Why is this bad?
+Readability.
+
+### Example
+```
+(0..3).fold(false, |acc, x| acc || x > 2);
+```
+
+Use instead:
+```
+(0..3).any(|x| x > 2);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_join.txt b/src/tools/clippy/src/docs/unnecessary_join.txt
new file mode 100644 (file)
index 0000000..ee4e786
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for use of `.collect::<Vec<String>>().join("")` on iterators.
+
+### Why is this bad?
+`.collect::<String>()` is more concise and might be more performant
+
+### Example
+```
+let vector = vec!["hello",  "world"];
+let output = vector.iter().map(|item| item.to_uppercase()).collect::<Vec<String>>().join("");
+println!("{}", output);
+```
+The correct use would be:
+```
+let vector = vec!["hello",  "world"];
+let output = vector.iter().map(|item| item.to_uppercase()).collect::<String>();
+println!("{}", output);
+```
+### Known problems
+While `.collect::<String>()` is sometimes more performant, there are cases where
+using `.collect::<String>()` over `.collect::<Vec<String>>().join("")`
+will prevent loop unrolling and will result in a negative performance impact.
+
+Additionally, differences have been observed between aarch64 and x86_64 assembly output,
+with aarch64 tending to producing faster assembly in more cases when using `.collect::<String>()`
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_lazy_evaluations.txt b/src/tools/clippy/src/docs/unnecessary_lazy_evaluations.txt
new file mode 100644 (file)
index 0000000..208188c
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+As the counterpart to `or_fun_call`, this lint looks for unnecessary
+lazily evaluated closures on `Option` and `Result`.
+
+This lint suggests changing the following functions, when eager evaluation results in
+simpler code:
+ - `unwrap_or_else` to `unwrap_or`
+ - `and_then` to `and`
+ - `or_else` to `or`
+ - `get_or_insert_with` to `get_or_insert`
+ - `ok_or_else` to `ok_or`
+
+### Why is this bad?
+Using eager evaluation is shorter and simpler in some cases.
+
+### Known problems
+It is possible, but not recommended for `Deref` and `Index` to have
+side effects. Eagerly evaluating them can change the semantics of the program.
+
+### Example
+```
+// example code where clippy issues a warning
+let opt: Option<u32> = None;
+
+opt.unwrap_or_else(|| 42);
+```
+Use instead:
+```
+let opt: Option<u32> = None;
+
+opt.unwrap_or(42);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_mut_passed.txt b/src/tools/clippy/src/docs/unnecessary_mut_passed.txt
new file mode 100644 (file)
index 0000000..2f8bdd1
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Detects passing a mutable reference to a function that only
+requires an immutable reference.
+
+### Why is this bad?
+The mutable reference rules out all other references to
+the value. Also the code misleads about the intent of the call site.
+
+### Example
+```
+vec.push(&mut value);
+```
+
+Use instead:
+```
+vec.push(&value);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_operation.txt b/src/tools/clippy/src/docs/unnecessary_operation.txt
new file mode 100644 (file)
index 0000000..7f455e2
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for expression statements that can be reduced to a
+sub-expression.
+
+### Why is this bad?
+Expressions by themselves often have no side-effects.
+Having such expressions reduces readability.
+
+### Example
+```
+compute_array()[0];
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_owned_empty_strings.txt b/src/tools/clippy/src/docs/unnecessary_owned_empty_strings.txt
new file mode 100644 (file)
index 0000000..8cd9fba
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+
+Detects cases of owned empty strings being passed as an argument to a function expecting `&str`
+
+### Why is this bad?
+
+This results in longer and less readable code
+
+### Example
+```
+vec!["1", "2", "3"].join(&String::new());
+```
+Use instead:
+```
+vec!["1", "2", "3"].join("");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_self_imports.txt b/src/tools/clippy/src/docs/unnecessary_self_imports.txt
new file mode 100644 (file)
index 0000000..b909cd5
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for imports ending in `::{self}`.
+
+### Why is this bad?
+In most cases, this can be written much more cleanly by omitting `::{self}`.
+
+### Known problems
+Removing `::{self}` will cause any non-module items at the same path to also be imported.
+This might cause a naming conflict (https://github.com/rust-lang/rustfmt/issues/3568). This lint makes no attempt
+to detect this scenario and that is why it is a restriction lint.
+
+### Example
+```
+use std::io::{self};
+```
+Use instead:
+```
+use std::io;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_sort_by.txt b/src/tools/clippy/src/docs/unnecessary_sort_by.txt
new file mode 100644 (file)
index 0000000..6913b62
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+Detects uses of `Vec::sort_by` passing in a closure
+which compares the two arguments, either directly or indirectly.
+
+### Why is this bad?
+It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
+possible) than to use `Vec::sort_by` and a more complicated
+closure.
+
+### Known problems
+If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
+imported by a use statement, then it will need to be added manually.
+
+### Example
+```
+vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
+```
+Use instead:
+```
+vec.sort_by_key(|a| a.foo());
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_to_owned.txt b/src/tools/clippy/src/docs/unnecessary_to_owned.txt
new file mode 100644 (file)
index 0000000..5d4213b
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for unnecessary calls to [`ToOwned::to_owned`](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned)
+and other `to_owned`-like functions.
+
+### Why is this bad?
+The unnecessary calls result in useless allocations.
+
+### Known problems
+`unnecessary_to_owned` can falsely trigger if `IntoIterator::into_iter` is applied to an
+owned copy of a resource and the resource is later used mutably. See
+[#8148](https://github.com/rust-lang/rust-clippy/issues/8148).
+
+### Example
+```
+let path = std::path::Path::new("x");
+foo(&path.to_string_lossy().to_string());
+fn foo(s: &str) {}
+```
+Use instead:
+```
+let path = std::path::Path::new("x");
+foo(&path.to_string_lossy());
+fn foo(s: &str) {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_unwrap.txt b/src/tools/clippy/src/docs/unnecessary_unwrap.txt
new file mode 100644 (file)
index 0000000..50ae845
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for calls of `unwrap[_err]()` that cannot fail.
+
+### Why is this bad?
+Using `if let` or `match` is more idiomatic.
+
+### Example
+```
+if option.is_some() {
+    do_something_with(option.unwrap())
+}
+```
+
+Could be written:
+
+```
+if let Some(value) = option {
+    do_something_with(value)
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_wraps.txt b/src/tools/clippy/src/docs/unnecessary_wraps.txt
new file mode 100644 (file)
index 0000000..c0a23d4
--- /dev/null
@@ -0,0 +1,36 @@
+### What it does
+Checks for private functions that only return `Ok` or `Some`.
+
+### Why is this bad?
+It is not meaningful to wrap values when no `None` or `Err` is returned.
+
+### Known problems
+There can be false positives if the function signature is designed to
+fit some external requirement.
+
+### Example
+```
+fn get_cool_number(a: bool, b: bool) -> Option<i32> {
+    if a && b {
+        return Some(50);
+    }
+    if a {
+        Some(0)
+    } else {
+        Some(10)
+    }
+}
+```
+Use instead:
+```
+fn get_cool_number(a: bool, b: bool) -> i32 {
+    if a && b {
+        return 50;
+    }
+    if a {
+        0
+    } else {
+        10
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unneeded_field_pattern.txt b/src/tools/clippy/src/docs/unneeded_field_pattern.txt
new file mode 100644 (file)
index 0000000..3cd00a0
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for structure field patterns bound to wildcards.
+
+### Why is this bad?
+Using `..` instead is shorter and leaves the focus on
+the fields that are actually bound.
+
+### Example
+```
+let f = Foo { a: 0, b: 0, c: 0 };
+
+match f {
+    Foo { a: _, b: 0, .. } => {},
+    Foo { a: _, b: _, c: _ } => {},
+}
+```
+
+Use instead:
+```
+let f = Foo { a: 0, b: 0, c: 0 };
+
+match f {
+    Foo { b: 0, .. } => {},
+    Foo { .. } => {},
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unneeded_wildcard_pattern.txt b/src/tools/clippy/src/docs/unneeded_wildcard_pattern.txt
new file mode 100644 (file)
index 0000000..817061e
--- /dev/null
@@ -0,0 +1,28 @@
+### What it does
+Checks for tuple patterns with a wildcard
+pattern (`_`) is next to a rest pattern (`..`).
+
+_NOTE_: While `_, ..` means there is at least one element left, `..`
+means there are 0 or more elements left. This can make a difference
+when refactoring, but shouldn't result in errors in the refactored code,
+since the wildcard pattern isn't used anyway.
+
+### Why is this bad?
+The wildcard pattern is unneeded as the rest pattern
+can match that element as well.
+
+### Example
+```
+match t {
+    TupleStruct(0, .., _) => (),
+    _ => (),
+}
+```
+
+Use instead:
+```
+match t {
+    TupleStruct(0, ..) => (),
+    _ => (),
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnested_or_patterns.txt b/src/tools/clippy/src/docs/unnested_or_patterns.txt
new file mode 100644 (file)
index 0000000..49c45d4
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for unnested or-patterns, e.g., `Some(0) | Some(2)` and
+suggests replacing the pattern with a nested one, `Some(0 | 2)`.
+
+Another way to think of this is that it rewrites patterns in
+*disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*.
+
+### Why is this bad?
+In the example above, `Some` is repeated, which unnecessarily complicates the pattern.
+
+### Example
+```
+fn main() {
+    if let Some(0) | Some(2) = Some(0) {}
+}
+```
+Use instead:
+```
+fn main() {
+    if let Some(0 | 2) = Some(0) {}
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unreachable.txt b/src/tools/clippy/src/docs/unreachable.txt
new file mode 100644 (file)
index 0000000..10469ca
--- /dev/null
@@ -0,0 +1,10 @@
+### What it does
+Checks for usage of `unreachable!`.
+
+### Why is this bad?
+This macro can cause code to panic
+
+### Example
+```
+unreachable!();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unreadable_literal.txt b/src/tools/clippy/src/docs/unreadable_literal.txt
new file mode 100644 (file)
index 0000000..e168f90
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Warns if a long integral or floating-point constant does
+not contain underscores.
+
+### Why is this bad?
+Reading long numbers is difficult without separators.
+
+### Example
+```
+61864918973511
+```
+
+Use instead:
+```
+61_864_918_973_511
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unsafe_derive_deserialize.txt b/src/tools/clippy/src/docs/unsafe_derive_deserialize.txt
new file mode 100644 (file)
index 0000000..f56c480
--- /dev/null
@@ -0,0 +1,27 @@
+### What it does
+Checks for deriving `serde::Deserialize` on a type that
+has methods using `unsafe`.
+
+### Why is this bad?
+Deriving `serde::Deserialize` will create a constructor
+that may violate invariants hold by another constructor.
+
+### Example
+```
+use serde::Deserialize;
+
+#[derive(Deserialize)]
+pub struct Foo {
+    // ..
+}
+
+impl Foo {
+    pub fn new() -> Self {
+        // setup here ..
+    }
+
+    pub unsafe fn parts() -> (&str, &str) {
+        // assumes invariants hold
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unsafe_removed_from_name.txt b/src/tools/clippy/src/docs/unsafe_removed_from_name.txt
new file mode 100644 (file)
index 0000000..6f55c18
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for imports that remove "unsafe" from an item's
+name.
+
+### Why is this bad?
+Renaming makes it less clear which traits and
+structures are unsafe.
+
+### Example
+```
+use std::cell::{UnsafeCell as TotallySafeCell};
+
+extern crate crossbeam;
+use crossbeam::{spawn_unsafe as spawn};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unseparated_literal_suffix.txt b/src/tools/clippy/src/docs/unseparated_literal_suffix.txt
new file mode 100644 (file)
index 0000000..d80248e
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Warns if literal suffixes are not separated by an
+underscore.
+To enforce unseparated literal suffix style,
+see the `separated_literal_suffix` lint.
+
+### Why is this bad?
+Suffix style should be consistent.
+
+### Example
+```
+123832i32
+```
+
+Use instead:
+```
+123832_i32
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unsound_collection_transmute.txt b/src/tools/clippy/src/docs/unsound_collection_transmute.txt
new file mode 100644 (file)
index 0000000..29db925
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for transmutes between collections whose
+types have different ABI, size or alignment.
+
+### Why is this bad?
+This is undefined behavior.
+
+### Known problems
+Currently, we cannot know whether a type is a
+collection, so we just lint the ones that come with `std`.
+
+### Example
+```
+// different size, therefore likely out-of-bounds memory access
+// You absolutely do not want this in your code!
+unsafe {
+    std::mem::transmute::<_, Vec<u32>>(vec![2_u16])
+};
+```
+
+You must always iterate, map and collect the values:
+
+```
+vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_async.txt b/src/tools/clippy/src/docs/unused_async.txt
new file mode 100644 (file)
index 0000000..26def11
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for functions that are declared `async` but have no `.await`s inside of them.
+
+### Why is this bad?
+Async functions with no async code create overhead, both mentally and computationally.
+Callers of async methods either need to be calling from an async function themselves or run it on an executor, both of which
+causes runtime overhead and hassle for the caller.
+
+### Example
+```
+async fn get_random_number() -> i64 {
+    4 // Chosen by fair dice roll. Guaranteed to be random.
+}
+let number_future = get_random_number();
+```
+
+Use instead:
+```
+fn get_random_number_improved() -> i64 {
+    4 // Chosen by fair dice roll. Guaranteed to be random.
+}
+let number_future = async { get_random_number_improved() };
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_io_amount.txt b/src/tools/clippy/src/docs/unused_io_amount.txt
new file mode 100644 (file)
index 0000000..fbc4c29
--- /dev/null
@@ -0,0 +1,31 @@
+### What it does
+Checks for unused written/read amount.
+
+### Why is this bad?
+`io::Write::write(_vectored)` and
+`io::Read::read(_vectored)` are not guaranteed to
+process the entire buffer. They return how many bytes were processed, which
+might be smaller
+than a given buffer's length. If you don't need to deal with
+partial-write/read, use
+`write_all`/`read_exact` instead.
+
+When working with asynchronous code (either with the `futures`
+crate or with `tokio`), a similar issue exists for
+`AsyncWriteExt::write()` and `AsyncReadExt::read()` : these
+functions are also not guaranteed to process the entire
+buffer.  Your code should either handle partial-writes/reads, or
+call the `write_all`/`read_exact` methods on those traits instead.
+
+### Known problems
+Detects only common patterns.
+
+### Examples
+```
+use std::io;
+fn foo<W: io::Write>(w: &mut W) -> io::Result<()> {
+    // must be `w.write_all(b"foo")?;`
+    w.write(b"foo")?;
+    Ok(())
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_peekable.txt b/src/tools/clippy/src/docs/unused_peekable.txt
new file mode 100644 (file)
index 0000000..268de1c
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for the creation of a `peekable` iterator that is never `.peek()`ed
+
+### Why is this bad?
+Creating a peekable iterator without using any of its methods is likely a mistake,
+or just a leftover after a refactor.
+
+### Example
+```
+let collection = vec![1, 2, 3];
+let iter = collection.iter().peekable();
+
+for item in iter {
+    // ...
+}
+```
+
+Use instead:
+```
+let collection = vec![1, 2, 3];
+let iter = collection.iter();
+
+for item in iter {
+    // ...
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_rounding.txt b/src/tools/clippy/src/docs/unused_rounding.txt
new file mode 100644 (file)
index 0000000..70947ac
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+
+Detects cases where a whole-number literal float is being rounded, using
+the `floor`, `ceil`, or `round` methods.
+
+### Why is this bad?
+
+This is unnecessary and confusing to the reader. Doing this is probably a mistake.
+
+### Example
+```
+let x = 1f32.ceil();
+```
+Use instead:
+```
+let x = 1f32;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_self.txt b/src/tools/clippy/src/docs/unused_self.txt
new file mode 100644 (file)
index 0000000..a8d0fc7
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks methods that contain a `self` argument but don't use it
+
+### Why is this bad?
+It may be clearer to define the method as an associated function instead
+of an instance method if it doesn't require `self`.
+
+### Example
+```
+struct A;
+impl A {
+    fn method(&self) {}
+}
+```
+
+Could be written:
+
+```
+struct A;
+impl A {
+    fn method() {}
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_unit.txt b/src/tools/clippy/src/docs/unused_unit.txt
new file mode 100644 (file)
index 0000000..48d16ca
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for unit (`()`) expressions that can be removed.
+
+### Why is this bad?
+Such expressions add no value, but can make the code
+less readable. Depending on formatting they can make a `break` or `return`
+statement look like a function call.
+
+### Example
+```
+fn return_unit() -> () {
+    ()
+}
+```
+is equivalent to
+```
+fn return_unit() {}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unusual_byte_groupings.txt b/src/tools/clippy/src/docs/unusual_byte_groupings.txt
new file mode 100644 (file)
index 0000000..9a1f132
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Warns if hexadecimal or binary literals are not grouped
+by nibble or byte.
+
+### Why is this bad?
+Negatively impacts readability.
+
+### Example
+```
+let x: u32 = 0xFFF_FFF;
+let y: u8 = 0b01_011_101;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unwrap_in_result.txt b/src/tools/clippy/src/docs/unwrap_in_result.txt
new file mode 100644 (file)
index 0000000..7497dd8
--- /dev/null
@@ -0,0 +1,39 @@
+### What it does
+Checks for functions of type `Result` that contain `expect()` or `unwrap()`
+
+### Why is this bad?
+These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics.
+
+### Known problems
+This can cause false positives in functions that handle both recoverable and non recoverable errors.
+
+### Example
+Before:
+```
+fn divisible_by_3(i_str: String) -> Result<(), String> {
+    let i = i_str
+        .parse::<i32>()
+        .expect("cannot divide the input by three");
+
+    if i % 3 != 0 {
+        Err("Number is not divisible by 3")?
+    }
+
+    Ok(())
+}
+```
+
+After:
+```
+fn divisible_by_3(i_str: String) -> Result<(), String> {
+    let i = i_str
+        .parse::<i32>()
+        .map_err(|e| format!("cannot divide the input by three: {}", e))?;
+
+    if i % 3 != 0 {
+        Err("Number is not divisible by 3")?
+    }
+
+    Ok(())
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unwrap_or_else_default.txt b/src/tools/clippy/src/docs/unwrap_or_else_default.txt
new file mode 100644 (file)
index 0000000..34b4cf0
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and
+`Result` values.
+
+### Why is this bad?
+Readability, these can be written as `_.unwrap_or_default`, which is
+simpler and more concise.
+
+### Examples
+```
+x.unwrap_or_else(Default::default);
+x.unwrap_or_else(u32::default);
+```
+
+Use instead:
+```
+x.unwrap_or_default();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unwrap_used.txt b/src/tools/clippy/src/docs/unwrap_used.txt
new file mode 100644 (file)
index 0000000..9b4713d
--- /dev/null
@@ -0,0 +1,37 @@
+### What it does
+Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s.
+
+### Why is this bad?
+It is better to handle the `None` or `Err` case,
+or at least call `.expect(_)` with a more helpful message. Still, for a lot of
+quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
+`Allow` by default.
+
+`result.unwrap()` will let the thread panic on `Err` values.
+Normally, you want to implement more sophisticated error handling,
+and propagate errors upwards with `?` operator.
+
+Even if you want to panic on errors, not all `Error`s implement good
+messages on display. Therefore, it may be beneficial to look at the places
+where they may get displayed. Activate this lint to do just that.
+
+### Examples
+```
+option.unwrap();
+result.unwrap();
+```
+
+Use instead:
+```
+option.expect("more helpful message");
+result.expect("more helpful message");
+```
+
+If [expect_used](#expect_used) is enabled, instead:
+```
+option?;
+
+// or
+
+result?;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/upper_case_acronyms.txt b/src/tools/clippy/src/docs/upper_case_acronyms.txt
new file mode 100644 (file)
index 0000000..a1e39c7
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for fully capitalized names and optionally names containing a capitalized acronym.
+
+### Why is this bad?
+In CamelCase, acronyms count as one word.
+See [naming conventions](https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case)
+for more.
+
+By default, the lint only triggers on fully-capitalized names.
+You can use the `upper-case-acronyms-aggressive: true` config option to enable linting
+on all camel case names
+
+### Known problems
+When two acronyms are contiguous, the lint can't tell where
+the first acronym ends and the second starts, so it suggests to lowercase all of
+the letters in the second acronym.
+
+### Example
+```
+struct HTTPResponse;
+```
+Use instead:
+```
+struct HttpResponse;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/use_debug.txt b/src/tools/clippy/src/docs/use_debug.txt
new file mode 100644 (file)
index 0000000..94d4a6f
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for use of `Debug` formatting. The purpose of this
+lint is to catch debugging remnants.
+
+### Why is this bad?
+The purpose of the `Debug` trait is to facilitate
+debugging Rust code. It should not be used in user-facing output.
+
+### Example
+```
+println!("{:?}", foo);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/use_self.txt b/src/tools/clippy/src/docs/use_self.txt
new file mode 100644 (file)
index 0000000..bd37ed1
--- /dev/null
@@ -0,0 +1,31 @@
+### What it does
+Checks for unnecessary repetition of structure name when a
+replacement with `Self` is applicable.
+
+### Why is this bad?
+Unnecessary repetition. Mixed use of `Self` and struct
+name
+feels inconsistent.
+
+### Known problems
+- Unaddressed false negative in fn bodies of trait implementations
+- False positive with associated types in traits (#4140)
+
+### Example
+```
+struct Foo;
+impl Foo {
+    fn new() -> Foo {
+        Foo {}
+    }
+}
+```
+could be
+```
+struct Foo;
+impl Foo {
+    fn new() -> Self {
+        Self {}
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/used_underscore_binding.txt b/src/tools/clippy/src/docs/used_underscore_binding.txt
new file mode 100644 (file)
index 0000000..ed67c41
--- /dev/null
@@ -0,0 +1,19 @@
+### What it does
+Checks for the use of bindings with a single leading
+underscore.
+
+### Why is this bad?
+A single leading underscore is usually used to indicate
+that a binding will not be used. Using such a binding breaks this
+expectation.
+
+### Known problems
+The lint does not work properly with desugaring and
+macro, it has been allowed in the mean time.
+
+### Example
+```
+let _x = 0;
+let y = _x + 1; // Here we are using `_x`, even though it has a leading
+                // underscore. We should rename `_x` to `x`
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_asref.txt b/src/tools/clippy/src/docs/useless_asref.txt
new file mode 100644 (file)
index 0000000..f777cd3
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for usage of `.as_ref()` or `.as_mut()` where the
+types before and after the call are the same.
+
+### Why is this bad?
+The call is unnecessary.
+
+### Example
+```
+let x: &[i32] = &[1, 2, 3, 4, 5];
+do_stuff(x.as_ref());
+```
+The correct use would be:
+```
+let x: &[i32] = &[1, 2, 3, 4, 5];
+do_stuff(x);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_attribute.txt b/src/tools/clippy/src/docs/useless_attribute.txt
new file mode 100644 (file)
index 0000000..e02d4c9
--- /dev/null
@@ -0,0 +1,36 @@
+### What it does
+Checks for `extern crate` and `use` items annotated with
+lint attributes.
+
+This lint permits lint attributes for lints emitted on the items themself.
+For `use` items these lints are:
+* deprecated
+* unreachable_pub
+* unused_imports
+* clippy::enum_glob_use
+* clippy::macro_use_imports
+* clippy::wildcard_imports
+
+For `extern crate` items these lints are:
+* `unused_imports` on items with `#[macro_use]`
+
+### Why is this bad?
+Lint attributes have no effect on crate imports. Most
+likely a `!` was forgotten.
+
+### Example
+```
+#[deny(dead_code)]
+extern crate foo;
+#[forbid(dead_code)]
+use foo::bar;
+```
+
+Use instead:
+```
+#[allow(unused_imports)]
+use foo::baz;
+#[allow(unused_imports)]
+#[macro_use]
+extern crate baz;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_conversion.txt b/src/tools/clippy/src/docs/useless_conversion.txt
new file mode 100644 (file)
index 0000000..06000a7
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls
+which uselessly convert to the same type.
+
+### Why is this bad?
+Redundant code.
+
+### Example
+```
+// format!() returns a `String`
+let s: String = format!("hello").into();
+```
+
+Use instead:
+```
+let s: String = format!("hello");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_format.txt b/src/tools/clippy/src/docs/useless_format.txt
new file mode 100644 (file)
index 0000000..eb4819d
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for the use of `format!("string literal with no
+argument")` and `format!("{}", foo)` where `foo` is a string.
+
+### Why is this bad?
+There is no point of doing that. `format!("foo")` can
+be replaced by `"foo".to_owned()` if you really need a `String`. The even
+worse `&format!("foo")` is often encountered in the wild. `format!("{}",
+foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()`
+if `foo: &str`.
+
+### Examples
+```
+let foo = "foo";
+format!("{}", foo);
+```
+
+Use instead:
+```
+let foo = "foo";
+foo.to_owned();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_let_if_seq.txt b/src/tools/clippy/src/docs/useless_let_if_seq.txt
new file mode 100644 (file)
index 0000000..c6dcd57
--- /dev/null
@@ -0,0 +1,39 @@
+### What it does
+Checks for variable declarations immediately followed by a
+conditional affectation.
+
+### Why is this bad?
+This is not idiomatic Rust.
+
+### Example
+```
+let foo;
+
+if bar() {
+    foo = 42;
+} else {
+    foo = 0;
+}
+
+let mut baz = None;
+
+if bar() {
+    baz = Some(42);
+}
+```
+
+should be written
+
+```
+let foo = if bar() {
+    42
+} else {
+    0
+};
+
+let baz = if bar() {
+    Some(42)
+} else {
+    None
+};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_transmute.txt b/src/tools/clippy/src/docs/useless_transmute.txt
new file mode 100644 (file)
index 0000000..1d3a175
--- /dev/null
@@ -0,0 +1,12 @@
+### What it does
+Checks for transmutes to the original type of the object
+and transmutes that could be a cast.
+
+### Why is this bad?
+Readability. The code tricks people into thinking that
+something complex is going on.
+
+### Example
+```
+core::intrinsics::transmute(t); // where the result type is the same as `t`'s
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_vec.txt b/src/tools/clippy/src/docs/useless_vec.txt
new file mode 100644 (file)
index 0000000..ee5afc9
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+Checks for usage of `&vec![..]` when using `&[..]` would
+be possible.
+
+### Why is this bad?
+This is less efficient.
+
+### Example
+```
+fn foo(_x: &[u8]) {}
+
+foo(&vec![1, 2]);
+```
+
+Use instead:
+```
+foo(&[1, 2]);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/vec_box.txt b/src/tools/clippy/src/docs/vec_box.txt
new file mode 100644 (file)
index 0000000..701b1c9
--- /dev/null
@@ -0,0 +1,26 @@
+### What it does
+Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code.
+Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
+
+### Why is this bad?
+`Vec` already keeps its contents in a separate area on
+the heap. So if you `Box` its contents, you just add another level of indirection.
+
+### Known problems
+Vec<Box<T: Sized>> makes sense if T is a large type (see [#3530](https://github.com/rust-lang/rust-clippy/issues/3530),
+1st comment).
+
+### Example
+```
+struct X {
+    values: Vec<Box<i32>>,
+}
+```
+
+Better:
+
+```
+struct X {
+    values: Vec<i32>,
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/vec_init_then_push.txt b/src/tools/clippy/src/docs/vec_init_then_push.txt
new file mode 100644 (file)
index 0000000..445f287
--- /dev/null
@@ -0,0 +1,23 @@
+### What it does
+Checks for calls to `push` immediately after creating a new `Vec`.
+
+If the `Vec` is created using `with_capacity` this will only lint if the capacity is a
+constant and the number of pushes is greater than or equal to the initial capacity.
+
+If the `Vec` is extended after the initial sequence of pushes and it was default initialized
+then this will only lint after there were at least four pushes. This number may change in
+the future.
+
+### Why is this bad?
+The `vec![]` macro is both more performant and easier to read than
+multiple `push` calls.
+
+### Example
+```
+let mut v = Vec::new();
+v.push(0);
+```
+Use instead:
+```
+let v = vec![0];
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/vec_resize_to_zero.txt b/src/tools/clippy/src/docs/vec_resize_to_zero.txt
new file mode 100644 (file)
index 0000000..0b92686
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Finds occurrences of `Vec::resize(0, an_int)`
+
+### Why is this bad?
+This is probably an argument inversion mistake.
+
+### Example
+```
+vec!(1, 2, 3, 4, 5).resize(0, 5)
+```
+
+Use instead:
+```
+vec!(1, 2, 3, 4, 5).clear()
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/verbose_bit_mask.txt b/src/tools/clippy/src/docs/verbose_bit_mask.txt
new file mode 100644 (file)
index 0000000..87a8470
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for bit masks that can be replaced by a call
+to `trailing_zeros`
+
+### Why is this bad?
+`x.trailing_zeros() > 4` is much clearer than `x & 15
+== 0`
+
+### Known problems
+llvm generates better code for `x & 15 == 0` on x86
+
+### Example
+```
+if x & 0b1111 == 0 { }
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/verbose_file_reads.txt b/src/tools/clippy/src/docs/verbose_file_reads.txt
new file mode 100644 (file)
index 0000000..9703df4
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for use of File::read_to_end and File::read_to_string.
+
+### Why is this bad?
+`fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values.
+See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html)
+
+### Example
+```
+let mut f = File::open("foo.txt").unwrap();
+let mut bytes = Vec::new();
+f.read_to_end(&mut bytes).unwrap();
+```
+Can be written more concisely as
+```
+let mut bytes = fs::read("foo.txt").unwrap();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/vtable_address_comparisons.txt b/src/tools/clippy/src/docs/vtable_address_comparisons.txt
new file mode 100644 (file)
index 0000000..4a34e4b
--- /dev/null
@@ -0,0 +1,17 @@
+### What it does
+Checks for comparisons with an address of a trait vtable.
+
+### Why is this bad?
+Comparing trait objects pointers compares an vtable addresses which
+are not guaranteed to be unique and could vary between different code generation units.
+Furthermore vtables for different types could have the same address after being merged
+together.
+
+### Example
+```
+let a: Rc<dyn Trait> = ...
+let b: Rc<dyn Trait> = ...
+if Rc::ptr_eq(&a, &b) {
+    ...
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/while_immutable_condition.txt b/src/tools/clippy/src/docs/while_immutable_condition.txt
new file mode 100644 (file)
index 0000000..7180070
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks whether variables used within while loop condition
+can be (and are) mutated in the body.
+
+### Why is this bad?
+If the condition is unchanged, entering the body of the loop
+will lead to an infinite loop.
+
+### Known problems
+If the `while`-loop is in a closure, the check for mutation of the
+condition variables in the body can cause false negatives. For example when only `Upvar` `a` is
+in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger.
+
+### Example
+```
+let i = 0;
+while i > 10 {
+    println!("let me loop forever!");
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/while_let_loop.txt b/src/tools/clippy/src/docs/while_let_loop.txt
new file mode 100644 (file)
index 0000000..ab7bf60
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Detects `loop + match` combinations that are easier
+written as a `while let` loop.
+
+### Why is this bad?
+The `while let` loop is usually shorter and more
+readable.
+
+### Known problems
+Sometimes the wrong binding is displayed ([#383](https://github.com/rust-lang/rust-clippy/issues/383)).
+
+### Example
+```
+loop {
+    let x = match y {
+        Some(x) => x,
+        None => break,
+    };
+    // .. do something with x
+}
+// is easier written as
+while let Some(x) = y {
+    // .. do something with x
+};
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/while_let_on_iterator.txt b/src/tools/clippy/src/docs/while_let_on_iterator.txt
new file mode 100644 (file)
index 0000000..af053c5
--- /dev/null
@@ -0,0 +1,20 @@
+### What it does
+Checks for `while let` expressions on iterators.
+
+### Why is this bad?
+Readability. A simple `for` loop is shorter and conveys
+the intent better.
+
+### Example
+```
+while let Some(val) = iter.next() {
+    ..
+}
+```
+
+Use instead:
+```
+for val in &mut iter {
+    ..
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/wildcard_dependencies.txt b/src/tools/clippy/src/docs/wildcard_dependencies.txt
new file mode 100644 (file)
index 0000000..2affaf9
--- /dev/null
@@ -0,0 +1,13 @@
+### What it does
+Checks for wildcard dependencies in the `Cargo.toml`.
+
+### Why is this bad?
+[As the edition guide says](https://rust-lang-nursery.github.io/edition-guide/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.html),
+it is highly unlikely that you work with any possible version of your dependency,
+and wildcard dependencies would cause unnecessary breakage in the ecosystem.
+
+### Example
+```
+[dependencies]
+regex = "*"
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/wildcard_enum_match_arm.txt b/src/tools/clippy/src/docs/wildcard_enum_match_arm.txt
new file mode 100644 (file)
index 0000000..09807c0
--- /dev/null
@@ -0,0 +1,25 @@
+### What it does
+Checks for wildcard enum matches using `_`.
+
+### Why is this bad?
+New enum variants added by library updates can be missed.
+
+### Known problems
+Suggested replacements may be incorrect if guards exhaustively cover some
+variants, and also may not use correct path to enum if it's not present in the current scope.
+
+### Example
+```
+match x {
+    Foo::A(_) => {},
+    _ => {},
+}
+```
+
+Use instead:
+```
+match x {
+    Foo::A(_) => {},
+    Foo::B(_) => {},
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/wildcard_imports.txt b/src/tools/clippy/src/docs/wildcard_imports.txt
new file mode 100644 (file)
index 0000000..bd56aa5
--- /dev/null
@@ -0,0 +1,45 @@
+### What it does
+Checks for wildcard imports `use _::*`.
+
+### Why is this bad?
+wildcard imports can pollute the namespace. This is especially bad if
+you try to import something through a wildcard, that already has been imported by name from
+a different source:
+
+```
+use crate1::foo; // Imports a function named foo
+use crate2::*; // Has a function named foo
+
+foo(); // Calls crate1::foo
+```
+
+This can lead to confusing error messages at best and to unexpected behavior at worst.
+
+### Exceptions
+Wildcard imports are allowed from modules named `prelude`. Many crates (including the standard library)
+provide modules named "prelude" specifically designed for wildcard import.
+
+`use super::*` is allowed in test modules. This is defined as any module with "test" in the name.
+
+These exceptions can be disabled using the `warn-on-all-wildcard-imports` configuration flag.
+
+### Known problems
+If macros are imported through the wildcard, this macro is not included
+by the suggestion and has to be added by hand.
+
+Applying the suggestion when explicit imports of the things imported with a glob import
+exist, may result in `unused_imports` warnings.
+
+### Example
+```
+use crate1::*;
+
+foo();
+```
+
+Use instead:
+```
+use crate1::foo;
+
+foo();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/wildcard_in_or_patterns.txt b/src/tools/clippy/src/docs/wildcard_in_or_patterns.txt
new file mode 100644 (file)
index 0000000..70468ca
--- /dev/null
@@ -0,0 +1,22 @@
+### What it does
+Checks for wildcard pattern used with others patterns in same match arm.
+
+### Why is this bad?
+Wildcard pattern already covers any other pattern as it will match anyway.
+It makes the code less readable, especially to spot wildcard pattern use in match arm.
+
+### Example
+```
+match s {
+    "a" => {},
+    "bar" | _ => {},
+}
+```
+
+Use instead:
+```
+match s {
+    "a" => {},
+    _ => {},
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/write_literal.txt b/src/tools/clippy/src/docs/write_literal.txt
new file mode 100644 (file)
index 0000000..9c41a48
--- /dev/null
@@ -0,0 +1,21 @@
+### What it does
+This lint warns about the use of literals as `write!`/`writeln!` args.
+
+### Why is this bad?
+Using literals as `writeln!` args is inefficient
+(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
+(i.e., just put the literal in the format string)
+
+### Known problems
+Will also warn with macro calls as arguments that expand to literals
+-- e.g., `writeln!(buf, "{}", env!("FOO"))`.
+
+### Example
+```
+writeln!(buf, "{}", "foo");
+```
+
+Use instead:
+```
+writeln!(buf, "foo");
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/write_with_newline.txt b/src/tools/clippy/src/docs/write_with_newline.txt
new file mode 100644 (file)
index 0000000..22845fd
--- /dev/null
@@ -0,0 +1,18 @@
+### What it does
+This lint warns when you use `write!()` with a format
+string that
+ends in a newline.
+
+### Why is this bad?
+You should use `writeln!()` instead, which appends the
+newline.
+
+### Example
+```
+write!(buf, "Hello {}!\n", name);
+```
+
+Use instead:
+```
+writeln!(buf, "Hello {}!", name);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/writeln_empty_string.txt b/src/tools/clippy/src/docs/writeln_empty_string.txt
new file mode 100644 (file)
index 0000000..3b3aeb7
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+This lint warns when you use `writeln!(buf, "")` to
+print a newline.
+
+### Why is this bad?
+You should use `writeln!(buf)`, which is simpler.
+
+### Example
+```
+writeln!(buf, "");
+```
+
+Use instead:
+```
+writeln!(buf);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/wrong_self_convention.txt b/src/tools/clippy/src/docs/wrong_self_convention.txt
new file mode 100644 (file)
index 0000000..d6b69ab
--- /dev/null
@@ -0,0 +1,39 @@
+### What it does
+Checks for methods with certain name prefixes and which
+doesn't match how self is taken. The actual rules are:
+
+|Prefix |Postfix     |`self` taken                   | `self` type  |
+|-------|------------|-------------------------------|--------------|
+|`as_`  | none       |`&self` or `&mut self`         | any          |
+|`from_`| none       | none                          | any          |
+|`into_`| none       |`self`                         | any          |
+|`is_`  | none       |`&mut self` or `&self` or none | any          |
+|`to_`  | `_mut`     |`&mut self`                    | any          |
+|`to_`  | not `_mut` |`self`                         | `Copy`       |
+|`to_`  | not `_mut` |`&self`                        | not `Copy`   |
+
+Note: Clippy doesn't trigger methods with `to_` prefix in:
+- Traits definition.
+Clippy can not tell if a type that implements a trait is `Copy` or not.
+- Traits implementation, when `&self` is taken.
+The method signature is controlled by the trait and often `&self` is required for all types that implement the trait
+(see e.g. the `std::string::ToString` trait).
+
+Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required.
+
+Please find more info here:
+https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
+
+### Why is this bad?
+Consistency breeds readability. If you follow the
+conventions, your users won't be surprised that they, e.g., need to supply a
+mutable reference to a `as_..` function.
+
+### Example
+```
+impl X {
+    fn as_str(self) -> &'static str {
+        // ..
+    }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/wrong_transmute.txt b/src/tools/clippy/src/docs/wrong_transmute.txt
new file mode 100644 (file)
index 0000000..9fc71e0
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for transmutes that can't ever be correct on any
+architecture.
+
+### Why is this bad?
+It's basically guaranteed to be undefined behavior.
+
+### Known problems
+When accessing C, users might want to store pointer
+sized objects in `extradata` arguments to save an allocation.
+
+### Example
+```
+let ptr: *const T = core::intrinsics::transmute('x')
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/zero_divided_by_zero.txt b/src/tools/clippy/src/docs/zero_divided_by_zero.txt
new file mode 100644 (file)
index 0000000..394de20
--- /dev/null
@@ -0,0 +1,15 @@
+### What it does
+Checks for `0.0 / 0.0`.
+
+### Why is this bad?
+It's less readable than `f32::NAN` or `f64::NAN`.
+
+### Example
+```
+let nan = 0.0f32 / 0.0;
+```
+
+Use instead:
+```
+let nan = f32::NAN;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/zero_prefixed_literal.txt b/src/tools/clippy/src/docs/zero_prefixed_literal.txt
new file mode 100644 (file)
index 0000000..5c55887
--- /dev/null
@@ -0,0 +1,32 @@
+### What it does
+Warns if an integral constant literal starts with `0`.
+
+### Why is this bad?
+In some languages (including the infamous C language
+and most of its
+family), this marks an octal constant. In Rust however, this is a decimal
+constant. This could
+be confusing for both the writer and a reader of the constant.
+
+### Example
+
+In Rust:
+```
+fn main() {
+    let a = 0123;
+    println!("{}", a);
+}
+```
+
+prints `123`, while in C:
+
+```
+#include <stdio.h>
+
+int main() {
+    int a = 0123;
+    printf("%d\n", a);
+}
+```
+
+prints `83` (as `83 == 0o123` while `123 == 0o173`).
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/zero_ptr.txt b/src/tools/clippy/src/docs/zero_ptr.txt
new file mode 100644 (file)
index 0000000..e768a02
--- /dev/null
@@ -0,0 +1,16 @@
+### What it does
+Catch casts from `0` to some pointer type
+
+### Why is this bad?
+This generally means `null` and is better expressed as
+{`std`, `core`}`::ptr::`{`null`, `null_mut`}.
+
+### Example
+```
+let a = 0 as *const u32;
+```
+
+Use instead:
+```
+let a = std::ptr::null::<u32>();
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/zero_sized_map_values.txt b/src/tools/clippy/src/docs/zero_sized_map_values.txt
new file mode 100644 (file)
index 0000000..0502bdb
--- /dev/null
@@ -0,0 +1,24 @@
+### What it does
+Checks for maps with zero-sized value types anywhere in the code.
+
+### Why is this bad?
+Since there is only a single value for a zero-sized type, a map
+containing zero sized values is effectively a set. Using a set in that case improves
+readability and communicates intent more clearly.
+
+### Known problems
+* A zero-sized type cannot be recovered later if it contains private fields.
+* This lints the signature of public items
+
+### Example
+```
+fn unique_words(text: &str) -> HashMap<&str, ()> {
+    todo!();
+}
+```
+Use instead:
+```
+fn unique_words(text: &str) -> HashSet<&str> {
+    todo!();
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/zst_offset.txt b/src/tools/clippy/src/docs/zst_offset.txt
new file mode 100644 (file)
index 0000000..5810455
--- /dev/null
@@ -0,0 +1,11 @@
+### What it does
+Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to
+zero-sized types
+
+### Why is this bad?
+This is a no-op, and likely unintended
+
+### Example
+```
+unsafe { (&() as *const ()).offset(1) };
+```
\ No newline at end of file
index 9ee4a40cbf2424715733eeab4e156055f52932e5..4a32e0e54a81b3fdbe579249771fb0c5123e14a2 100644 (file)
@@ -7,6 +7,8 @@
 use std::path::PathBuf;
 use std::process::{self, Command};
 
+mod docs;
+
 const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.
 
 Usage:
@@ -17,6 +19,7 @@
     --fix                    Automatically apply lint suggestions. This flag implies `--no-deps`
     -h, --help               Print this message
     -V, --version            Print version info and exit
+    --explain LINT           Print the documentation for a given lint
 
 Other options are the same as `cargo check`.
 
@@ -54,6 +57,16 @@ pub fn main() {
         return;
     }
 
+    if let Some(pos) = env::args().position(|a| a == "--explain") {
+        if let Some(mut lint) = env::args().nth(pos + 1) {
+            lint.make_ascii_lowercase();
+            docs::explain(&lint.strip_prefix("clippy::").unwrap_or(&lint).replace('-', "_"));
+        } else {
+            show_help();
+        }
+        return;
+    }
+
     if let Err(code) = process(env::args().skip(2)) {
         process::exit(code);
     }
diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs b/src/tools/clippy/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs
deleted file mode 100644 (file)
index 195fabd..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#![warn(clippy::arithmetic)]
-
-use core::ops::Add;
-
-#[derive(Clone, Copy)]
-struct Point {
-    x: i32,
-    y: i32,
-}
-
-impl Add for Point {
-    type Output = Self;
-
-    fn add(self, other: Self) -> Self {
-        todo!()
-    }
-}
-
-fn main() {
-    let _ = Point { x: 1, y: 0 } + Point { x: 2, y: 3 };
-
-    let point: Point = Point { x: 1, y: 0 };
-    let _ = point + point;
-}
diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_allowed/clippy.toml b/src/tools/clippy/tests/ui-toml/arithmetic_allowed/clippy.toml
deleted file mode 100644 (file)
index cc40570..0000000
+++ /dev/null
@@ -1 +0,0 @@
-arithmetic-allowed = ["Point"]
diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
new file mode 100644 (file)
index 0000000..1aed09b
--- /dev/null
@@ -0,0 +1,24 @@
+#![warn(clippy::arithmetic_side_effects)]
+
+use core::ops::Add;
+
+#[derive(Clone, Copy)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+impl Add for Point {
+    type Output = Self;
+
+    fn add(self, other: Self) -> Self {
+        todo!()
+    }
+}
+
+fn main() {
+    let _ = Point { x: 1, y: 0 } + Point { x: 2, y: 3 };
+
+    let point: Point = Point { x: 1, y: 0 };
+    let _ = point + point;
+}
diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml
new file mode 100644 (file)
index 0000000..e736256
--- /dev/null
@@ -0,0 +1 @@
+arithmetic-side-effects-allowed = ["Point"]
index a52a0b5289fe4839f22bc68f9ec1bbfb206fc6e2..f27f78d15d3a04d2d8f17dec0061f8154c2e8477 100644 (file)
@@ -3,7 +3,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            allow-expect-in-tests
            allow-unwrap-in-tests
            allowed-scripts
-           arithmetic-allowed
+           arithmetic-side-effects-allowed
            array-size-threshold
            avoid-breaking-exported-api
            await-holding-invalid-types
diff --git a/src/tools/clippy/tests/ui/arithmetic.fixed b/src/tools/clippy/tests/ui/arithmetic.fixed
deleted file mode 100644 (file)
index a2a1c43..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// run-rustfix
-
-#![allow(clippy::unnecessary_owned_empty_strings)]
-#![feature(saturating_int_impl)]
-#![warn(clippy::arithmetic)]
-
-use core::num::{Saturating, Wrapping};
-
-pub fn hard_coded_allowed() {
-    let _ = Saturating(0u32) + Saturating(0u32);
-    let _ = String::new() + "";
-    let _ = Wrapping(0u32) + Wrapping(0u32);
-
-    let saturating: Saturating<u32> = Saturating(0u32);
-    let string: String = String::new();
-    let wrapping: Wrapping<u32> = Wrapping(0u32);
-
-    let inferred_saturating = saturating + saturating;
-    let inferred_string = string + "";
-    let inferred_wrapping = wrapping + wrapping;
-
-    let _ = inferred_saturating + inferred_saturating;
-    let _ = inferred_string + "";
-    let _ = inferred_wrapping + inferred_wrapping;
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/arithmetic.rs b/src/tools/clippy/tests/ui/arithmetic.rs
deleted file mode 100644 (file)
index a2a1c43..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// run-rustfix
-
-#![allow(clippy::unnecessary_owned_empty_strings)]
-#![feature(saturating_int_impl)]
-#![warn(clippy::arithmetic)]
-
-use core::num::{Saturating, Wrapping};
-
-pub fn hard_coded_allowed() {
-    let _ = Saturating(0u32) + Saturating(0u32);
-    let _ = String::new() + "";
-    let _ = Wrapping(0u32) + Wrapping(0u32);
-
-    let saturating: Saturating<u32> = Saturating(0u32);
-    let string: String = String::new();
-    let wrapping: Wrapping<u32> = Wrapping(0u32);
-
-    let inferred_saturating = saturating + saturating;
-    let inferred_string = string + "";
-    let inferred_wrapping = wrapping + wrapping;
-
-    let _ = inferred_saturating + inferred_saturating;
-    let _ = inferred_string + "";
-    let _ = inferred_wrapping + inferred_wrapping;
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
new file mode 100644 (file)
index 0000000..f5390c7
--- /dev/null
@@ -0,0 +1,57 @@
+#![allow(clippy::assign_op_pattern, clippy::unnecessary_owned_empty_strings)]
+#![feature(inline_const, saturating_int_impl)]
+#![warn(clippy::arithmetic_side_effects)]
+
+use core::num::{Saturating, Wrapping};
+
+pub fn hard_coded_allowed() {
+    let _ = 1f32 + 1f32;
+    let _ = 1f64 + 1f64;
+
+    let _ = Saturating(0u32) + Saturating(0u32);
+    let _ = String::new() + "";
+    let _ = Wrapping(0u32) + Wrapping(0u32);
+
+    let saturating: Saturating<u32> = Saturating(0u32);
+    let string: String = String::new();
+    let wrapping: Wrapping<u32> = Wrapping(0u32);
+
+    let inferred_saturating = saturating + saturating;
+    let inferred_string = string + "";
+    let inferred_wrapping = wrapping + wrapping;
+
+    let _ = inferred_saturating + inferred_saturating;
+    let _ = inferred_string + "";
+    let _ = inferred_wrapping + inferred_wrapping;
+}
+
+#[rustfmt::skip]
+pub fn non_overflowing_ops() {
+    const _: i32 = { let mut n = 1; n += 1; n };
+    let _ = const { let mut n = 1; n += 1; n };
+
+    const _: i32 = { let mut n = 1; n = n + 1; n };
+    let _ = const { let mut n = 1; n = n + 1; n };
+
+    const _: i32 = { let mut n = 1; n = 1 + n; n };
+    let _ = const { let mut n = 1; n = 1 + n; n };
+
+    const _: i32 = 1 + 1;
+    let _ = 1 + 1;
+    let _ = const { 1 + 1 };
+
+    let mut _a = 1;
+    _a *= 1;
+    _a /= 1;
+}
+
+#[rustfmt::skip]
+pub fn overflowing_ops() {
+    let mut _a = 1; _a += 1;
+
+    let mut _b = 1; _b = _b + 1;
+
+    let mut _c = 1; _c = 1 + _c;
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
new file mode 100644 (file)
index 0000000..6c4c8bd
--- /dev/null
@@ -0,0 +1,22 @@
+error: arithmetic detected
+  --> $DIR/arithmetic_side_effects.rs:50:21
+   |
+LL |     let mut _a = 1; _a += 1;
+   |                     ^^^^^^^
+   |
+   = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
+
+error: arithmetic detected
+  --> $DIR/arithmetic_side_effects.rs:52:26
+   |
+LL |     let mut _b = 1; _b = _b + 1;
+   |                          ^^^^^^
+
+error: arithmetic detected
+  --> $DIR/arithmetic_side_effects.rs:54:26
+   |
+LL |     let mut _c = 1; _c = 1 + _c;
+   |                          ^^^^^^
+
+error: aborting due to 3 previous errors
+
index 5fdf3433a3702de7b324580e6fd4b8f386403914..a99bdfc1313792999485940405d71c418a1aa2bd 100644 (file)
@@ -1,4 +1,9 @@
-#[allow(clippy::unnecessary_operation, clippy::single_match)]
+#![allow(
+    clippy::unnecessary_operation,
+    clippy::single_match,
+    clippy::no_effect,
+    clippy::bool_to_int_with_if
+)]
 fn main() {
     struct Test {
         field: u32,
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
new file mode 100644 (file)
index 0000000..9c1098d
--- /dev/null
@@ -0,0 +1,85 @@
+// run-rustfix
+
+#![warn(clippy::bool_to_int_with_if)]
+#![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
+
+fn main() {
+    let a = true;
+    let b = false;
+
+    let x = 1;
+    let y = 2;
+
+    // Should lint
+    // precedence
+    i32::from(a);
+    i32::from(!a);
+    i32::from(a || b);
+    i32::from(cond(a, b));
+    i32::from(x + y < 4);
+
+    // if else if
+    if a {
+        123
+    } else {i32::from(b)};
+
+    // Shouldn't lint
+
+    if a {
+        1
+    } else if b {
+        0
+    } else {
+        3
+    };
+
+    if a {
+        3
+    } else if b {
+        1
+    } else {
+        -2
+    };
+
+    if a {
+        3
+    } else {
+        0
+    };
+    if a {
+        side_effect();
+        1
+    } else {
+        0
+    };
+    if a {
+        1
+    } else {
+        side_effect();
+        0
+    };
+
+    // multiple else ifs
+    if a {
+        123
+    } else if b {
+        1
+    } else if a | b {
+        0
+    } else {
+        123
+    };
+
+    some_fn(a);
+}
+
+// Lint returns and type inference
+fn some_fn(a: bool) -> u8 {
+    u8::from(a)
+}
+
+fn side_effect() {}
+
+fn cond(a: bool, b: bool) -> bool {
+    a || b
+}
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
new file mode 100644 (file)
index 0000000..0c967da
--- /dev/null
@@ -0,0 +1,109 @@
+// run-rustfix
+
+#![warn(clippy::bool_to_int_with_if)]
+#![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
+
+fn main() {
+    let a = true;
+    let b = false;
+
+    let x = 1;
+    let y = 2;
+
+    // Should lint
+    // precedence
+    if a {
+        1
+    } else {
+        0
+    };
+    if !a {
+        1
+    } else {
+        0
+    };
+    if a || b {
+        1
+    } else {
+        0
+    };
+    if cond(a, b) {
+        1
+    } else {
+        0
+    };
+    if x + y < 4 {
+        1
+    } else {
+        0
+    };
+
+    // if else if
+    if a {
+        123
+    } else if b {
+        1
+    } else {
+        0
+    };
+
+    // Shouldn't lint
+
+    if a {
+        1
+    } else if b {
+        0
+    } else {
+        3
+    };
+
+    if a {
+        3
+    } else if b {
+        1
+    } else {
+        -2
+    };
+
+    if a {
+        3
+    } else {
+        0
+    };
+    if a {
+        side_effect();
+        1
+    } else {
+        0
+    };
+    if a {
+        1
+    } else {
+        side_effect();
+        0
+    };
+
+    // multiple else ifs
+    if a {
+        123
+    } else if b {
+        1
+    } else if a | b {
+        0
+    } else {
+        123
+    };
+
+    some_fn(a);
+}
+
+// Lint returns and type inference
+fn some_fn(a: bool) -> u8 {
+    if a { 1 } else { 0 }
+}
+
+fn side_effect() {}
+
+fn cond(a: bool, b: bool) -> bool {
+    a || b
+}
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
new file mode 100644 (file)
index 0000000..8647a9c
--- /dev/null
@@ -0,0 +1,84 @@
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:15:5
+   |
+LL | /     if a {
+LL | |         1
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^ help: replace with from: `i32::from(a)`
+   |
+   = note: `-D clippy::bool-to-int-with-if` implied by `-D warnings`
+   = note: `a as i32` or `a.into()` can also be valid options
+
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:20:5
+   |
+LL | /     if !a {
+LL | |         1
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^ help: replace with from: `i32::from(!a)`
+   |
+   = note: `!a as i32` or `!a.into()` can also be valid options
+
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:25:5
+   |
+LL | /     if a || b {
+LL | |         1
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^ help: replace with from: `i32::from(a || b)`
+   |
+   = note: `(a || b) as i32` or `(a || b).into()` can also be valid options
+
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:30:5
+   |
+LL | /     if cond(a, b) {
+LL | |         1
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^ help: replace with from: `i32::from(cond(a, b))`
+   |
+   = note: `cond(a, b) as i32` or `cond(a, b).into()` can also be valid options
+
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:35:5
+   |
+LL | /     if x + y < 4 {
+LL | |         1
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^ help: replace with from: `i32::from(x + y < 4)`
+   |
+   = note: `(x + y < 4) as i32` or `(x + y < 4).into()` can also be valid options
+
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:44:12
+   |
+LL |       } else if b {
+   |  ____________^
+LL | |         1
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^ help: replace with from: `{i32::from(b)}`
+   |
+   = note: `b as i32` or `b.into()` can also be valid options
+
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:102:5
+   |
+LL |     if a { 1 } else { 0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)`
+   |
+   = note: `a as u8` or `a.into()` can also be valid options
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9405.rs b/src/tools/clippy/tests/ui/crashes/ice-9405.rs
new file mode 100644 (file)
index 0000000..e2d274a
--- /dev/null
@@ -0,0 +1,11 @@
+#![warn(clippy::useless_format)]
+#![allow(clippy::print_literal)]
+
+fn main() {
+    println!(
+        "\
+
+            {}",
+        "multiple skipped lines"
+    );
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9405.stderr b/src/tools/clippy/tests/ui/crashes/ice-9405.stderr
new file mode 100644 (file)
index 0000000..9a6e410
--- /dev/null
@@ -0,0 +1,11 @@
+warning: multiple lines skipped by escaped newline
+  --> $DIR/ice-9405.rs:6:10
+   |
+LL |           "/
+   |  __________^
+LL | |
+LL | |             {}",
+   | |____________^ skipping everything up to and including this point
+
+warning: 1 warning emitted
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9414.rs b/src/tools/clippy/tests/ui/crashes/ice-9414.rs
new file mode 100644 (file)
index 0000000..02cf5d5
--- /dev/null
@@ -0,0 +1,8 @@
+#![warn(clippy::result_large_err)]
+
+trait T {}
+fn f(_: &u32) -> Result<(), *const (dyn '_ + T)> {
+    Ok(())
+}
+
+fn main() {}
index 7efe10a10f9e9809db283ef8bf73378a16bbe31a..e7ef45634dff4e0bd4e2d7d17915b8bcc0f64b6b 100644 (file)
@@ -18,6 +18,11 @@ fn main() {
     let _ = x.powi(-16_777_215);
     let _ = (x as f32).powi(-16_777_215);
     let _ = (x as f32).powi(3);
+    let _ = (1.5_f32 + 1.0).cbrt();
+    let _ = 1.5_f64.cbrt();
+    let _ = 1.5_f64.sqrt();
+    let _ = 1.5_f64.powi(3);
+
     // Cases where the lint shouldn't be applied
     let _ = x.powf(2.1);
     let _ = x.powf(-2.1);
index 445080417f2ed8c2a0e5b7f1f1a799286077c2f8..d749aa2d48a418d79552a77eb44f403738217d0a 100644 (file)
@@ -18,6 +18,11 @@ fn main() {
     let _ = x.powf(-16_777_215.0);
     let _ = (x as f32).powf(-16_777_215.0);
     let _ = (x as f32).powf(3.0);
+    let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0);
+    let _ = 1.5_f64.powf(1.0 / 3.0);
+    let _ = 1.5_f64.powf(1.0 / 2.0);
+    let _ = 1.5_f64.powf(3.0);
+
     // Cases where the lint shouldn't be applied
     let _ = x.powf(2.1);
     let _ = x.powf(-2.1);
index 6ee696e6ada5ffda8d5580258d2ec7074bcfee3a..e9693de8fc9090f47802fd465fd5aa5f66c91b07 100644 (file)
@@ -92,77 +92,101 @@ error: exponentiation with integer powers can be computed more efficiently
 LL |     let _ = (x as f32).powf(3.0);
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(3)`
 
+error: cube-root of a number can be computed more accurately
+  --> $DIR/floating_point_powf.rs:21:13
+   |
+LL |     let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(1.5_f32 + 1.0).cbrt()`
+
+error: cube-root of a number can be computed more accurately
+  --> $DIR/floating_point_powf.rs:22:13
+   |
+LL |     let _ = 1.5_f64.powf(1.0 / 3.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.cbrt()`
+
+error: square-root of a number can be computed more efficiently and accurately
+  --> $DIR/floating_point_powf.rs:23:13
+   |
+LL |     let _ = 1.5_f64.powf(1.0 / 2.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.sqrt()`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:24:13
+   |
+LL |     let _ = 1.5_f64.powf(3.0);
+   |             ^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.powi(3)`
+
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:28:13
+  --> $DIR/floating_point_powf.rs:33:13
    |
 LL |     let _ = 2f64.powf(x);
    |             ^^^^^^^^^^^^ help: consider using: `x.exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:29:13
+  --> $DIR/floating_point_powf.rs:34:13
    |
 LL |     let _ = 2f64.powf(3.1);
    |             ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:30:13
+  --> $DIR/floating_point_powf.rs:35:13
    |
 LL |     let _ = 2f64.powf(-3.1);
    |             ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:31:13
+  --> $DIR/floating_point_powf.rs:36:13
    |
 LL |     let _ = std::f64::consts::E.powf(x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:32:13
+  --> $DIR/floating_point_powf.rs:37:13
    |
 LL |     let _ = std::f64::consts::E.powf(3.1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:33:13
+  --> $DIR/floating_point_powf.rs:38:13
    |
 LL |     let _ = std::f64::consts::E.powf(-3.1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()`
 
 error: square-root of a number can be computed more efficiently and accurately
-  --> $DIR/floating_point_powf.rs:34:13
+  --> $DIR/floating_point_powf.rs:39:13
    |
 LL |     let _ = x.powf(1.0 / 2.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()`
 
 error: cube-root of a number can be computed more accurately
-  --> $DIR/floating_point_powf.rs:35:13
+  --> $DIR/floating_point_powf.rs:40:13
    |
 LL |     let _ = x.powf(1.0 / 3.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:36:13
+  --> $DIR/floating_point_powf.rs:41:13
    |
 LL |     let _ = x.powf(3.0);
    |             ^^^^^^^^^^^ help: consider using: `x.powi(3)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:37:13
+  --> $DIR/floating_point_powf.rs:42:13
    |
 LL |     let _ = x.powf(-2.0);
    |             ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:38:13
+  --> $DIR/floating_point_powf.rs:43:13
    |
 LL |     let _ = x.powf(-2_147_483_648.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:39:13
+  --> $DIR/floating_point_powf.rs:44:13
    |
 LL |     let _ = x.powf(2_147_483_647.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)`
 
-error: aborting due to 27 previous errors
+error: aborting due to 31 previous errors
 
index 23152a13322e82ab3b73d7bb4481db22cc1f9668..717009e4c4ccadce5a5c5c93aa1607435c906edd 100644 (file)
@@ -130,6 +130,30 @@ fn clone(&self) -> Self {
 
 impl<T: Copy> Copy for SomeGenericPossiblyCopyEnum<T> {}
 
+enum LargeEnumWithGenerics<T> {
+    Small,
+    Large((T, [u8; 512])),
+}
+
+struct Foo<T> {
+    foo: T,
+}
+
+enum WithGenerics {
+    Large([Foo<u64>; 64]),
+    Small(u8),
+}
+
+enum PossiblyLargeEnumWithConst<const U: usize> {
+    SmallBuffer([u8; 4]),
+    MightyBuffer([u16; U]),
+}
+
+enum LargeEnumOfConst {
+    Ok,
+    Error(PossiblyLargeEnumWithConst<256>),
+}
+
 fn main() {
     large_enum_variant!();
 }
index 0248327262da0f63852ecfa684f6b38c058670f7..c6ed97487c0e3a27aab80d8e6564b57bf00c8561 100644 (file)
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:12:5
+  --> $DIR/large_enum_variant.rs:10:1
    |
-LL |     B([i32; 8000]),
-   |     ^^^^^^^^^^^^^^ this variant is 32000 bytes
+LL | / enum LargeEnum {
+LL | |     A(i32),
+   | |     ------ the second-largest variant contains at least 4 bytes
+LL | |     B([i32; 8000]),
+   | |     -------------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
    |
    = note: `-D clippy::large-enum-variant` implied by `-D warnings`
-note: and the second-largest variant is 4 bytes:
-  --> $DIR/large_enum_variant.rs:11:5
-   |
-LL |     A(i32),
-   |     ^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     B(Box<[i32; 8000]>),
    |       ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:36:5
-   |
-LL |     ContainingLargeEnum(LargeEnum),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
+  --> $DIR/large_enum_variant.rs:34:1
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:35:5
+LL | / enum LargeEnum2 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     ContainingLargeEnum(LargeEnum),
+   | |     ------------------------------ the largest variant contains at least 32004 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
    |
-LL |     VariantOk(i32, u32),
-   |     ^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     ContainingLargeEnum(Box<LargeEnum>),
    |                         ~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:40:5
-   |
-LL |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70004 bytes
+  --> $DIR/large_enum_variant.rs:39:1
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:42:5
+LL | / enum LargeEnum3 {
+LL | |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
+   | |     --------------------------------------------------------- the largest variant contains at least 70004 bytes
+LL | |     VoidVariant,
+LL | |     StructLikeLittle { x: i32, y: i32 },
+   | |     ----------------------------------- the second-largest variant contains at least 8 bytes
+LL | | }
+   | |_^ the entire enum is at least 70008 bytes
    |
-LL |     StructLikeLittle { x: i32, y: i32 },
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>),
    |                                     ~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:47:5
+  --> $DIR/large_enum_variant.rs:45:1
    |
-LL |     StructLikeLarge { x: [i32; 8000], y: i32 },
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
+LL | / enum LargeEnum4 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     StructLikeLarge { x: [i32; 8000], y: i32 },
+   | |     ------------------------------------------ the largest variant contains at least 32004 bytes
+LL | | }
+   | |_^ the entire enum is at least 32008 bytes
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:46:5
-   |
-LL |     VariantOk(i32, u32),
-   |     ^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     StructLikeLarge { x: Box<[i32; 8000]>, y: i32 },
    |                          ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:52:5
-   |
-LL |     StructLikeLarge2 { x: [i32; 8000] },
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32000 bytes
+  --> $DIR/large_enum_variant.rs:50:1
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:51:5
+LL | / enum LargeEnum5 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     StructLikeLarge2 { x: [i32; 8000] },
+   | |     ----------------------------------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
    |
-LL |     VariantOk(i32, u32),
-   |     ^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     StructLikeLarge2 { x: Box<[i32; 8000]> },
    |                           ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:68:5
-   |
-LL |     B([u8; 1255]),
-   |     ^^^^^^^^^^^^^ this variant is 1255 bytes
+  --> $DIR/large_enum_variant.rs:66:1
    |
-note: and the second-largest variant is 200 bytes:
-  --> $DIR/large_enum_variant.rs:69:5
+LL | / enum LargeEnum7 {
+LL | |     A,
+LL | |     B([u8; 1255]),
+   | |     ------------- the largest variant contains at least 1255 bytes
+LL | |     C([u8; 200]),
+   | |     ------------ the second-largest variant contains at least 200 bytes
+LL | | }
+   | |_^ the entire enum is at least 1256 bytes
    |
-LL |     C([u8; 200]),
-   |     ^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     B(Box<[u8; 1255]>),
    |       ~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:74:5
+  --> $DIR/large_enum_variant.rs:72:1
    |
-LL |     ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70128 bytes
+LL | / enum LargeEnum8 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
+   | |     ------------------------------------------------------------------------- the largest variant contains at least 70128 bytes
+LL | | }
+   | |_^ the entire enum is at least 70132 bytes
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:73:5
-   |
-LL |     VariantOk(i32, u32),
-   |     ^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]),
    |                                ~~~~~~~~~~~~~~~~            ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:79:5
+  --> $DIR/large_enum_variant.rs:77:1
+   |
+LL | / enum LargeEnum9 {
+LL | |     A(Struct<()>),
+   | |     ------------- the second-largest variant contains at least 4 bytes
+LL | |     B(Struct2),
+   | |     ---------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
    |
-LL |     B(Struct2),
-   |     ^^^^^^^^^^ this variant is 32000 bytes
+LL |     B(Box<Struct2>),
+   |       ~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:82:1
    |
-note: and the second-largest variant is 4 bytes:
-  --> $DIR/large_enum_variant.rs:78:5
+LL | / enum LargeEnumOk2<T> {
+LL | |     A(T),
+   | |     ---- the second-largest variant contains at least 0 bytes
+LL | |     B(Struct2),
+   | |     ---------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32000 bytes
    |
-LL |     A(Struct<()>),
-   |     ^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     B(Box<Struct2>),
    |       ~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:104:5
+  --> $DIR/large_enum_variant.rs:87:1
    |
-LL |     B([u128; 4000]),
-   |     ^^^^^^^^^^^^^^^ this variant is 64000 bytes
+LL | / enum LargeEnumOk3<T> {
+LL | |     A(Struct<T>),
+   | |     ------------ the second-largest variant contains at least 4 bytes
+LL | |     B(Struct2),
+   | |     ---------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32000 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
    |
-note: and the second-largest variant is 1 bytes:
-  --> $DIR/large_enum_variant.rs:103:5
+LL |     B(Box<Struct2>),
+   |       ~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:102:1
+   |
+LL | / enum CopyableLargeEnum {
+LL | |     A(bool),
+   | |     ------- the second-largest variant contains at least 1 bytes
+LL | |     B([u128; 4000]),
+   | |     --------------- the largest variant contains at least 64000 bytes
+LL | | }
+   | |_^ the entire enum is at least 64008 bytes
    |
-LL |     A(bool),
-   |     ^^^^^^^
 note: boxing a variant would require the type no longer be `Copy`
   --> $DIR/large_enum_variant.rs:102:6
    |
@@ -150,16 +184,16 @@ LL |     B([u128; 4000]),
    |     ^^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:109:5
+  --> $DIR/large_enum_variant.rs:107:1
    |
-LL |     B([u128; 4000]),
-   |     ^^^^^^^^^^^^^^^ this variant is 64000 bytes
-   |
-note: and the second-largest variant is 1 bytes:
-  --> $DIR/large_enum_variant.rs:108:5
+LL | / enum ManuallyCopyLargeEnum {
+LL | |     A(bool),
+   | |     ------- the second-largest variant contains at least 1 bytes
+LL | |     B([u128; 4000]),
+   | |     --------------- the largest variant contains at least 64000 bytes
+LL | | }
+   | |_^ the entire enum is at least 64008 bytes
    |
-LL |     A(bool),
-   |     ^^^^^^^
 note: boxing a variant would require the type no longer be `Copy`
   --> $DIR/large_enum_variant.rs:107:6
    |
@@ -172,16 +206,16 @@ LL |     B([u128; 4000]),
    |     ^^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:122:5
+  --> $DIR/large_enum_variant.rs:120:1
    |
-LL |     B([u64; 4000]),
-   |     ^^^^^^^^^^^^^^ this variant is 32000 bytes
-   |
-note: and the second-largest variant is 1 bytes:
-  --> $DIR/large_enum_variant.rs:121:5
+LL | / enum SomeGenericPossiblyCopyEnum<T> {
+LL | |     A(bool, std::marker::PhantomData<T>),
+   | |     ------------------------------------ the second-largest variant contains at least 1 bytes
+LL | |     B([u64; 4000]),
+   | |     -------------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32008 bytes
    |
-LL |     A(bool, std::marker::PhantomData<T>),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: boxing a variant would require the type no longer be `Copy`
   --> $DIR/large_enum_variant.rs:120:6
    |
@@ -193,5 +227,53 @@ help: consider boxing the large fields to reduce the total size of the enum
 LL |     B([u64; 4000]),
    |     ^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:133:1
+   |
+LL | / enum LargeEnumWithGenerics<T> {
+LL | |     Small,
+   | |     ----- the second-largest variant carries no data at all
+LL | |     Large((T, [u8; 512])),
+   | |     --------------------- the largest variant contains at least 512 bytes
+LL | | }
+   | |_^ the entire enum is at least 512 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Large(Box<(T, [u8; 512])>),
+   |           ~~~~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:142:1
+   |
+LL | / enum WithGenerics {
+LL | |     Large([Foo<u64>; 64]),
+   | |     --------------------- the largest variant contains at least 512 bytes
+LL | |     Small(u8),
+   | |     --------- the second-largest variant contains at least 1 bytes
+LL | | }
+   | |_^ the entire enum is at least 520 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Large(Box<[Foo<u64>; 64]>),
+   |           ~~~~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:152:1
+   |
+LL | / enum LargeEnumOfConst {
+LL | |     Ok,
+   | |     -- the second-largest variant carries no data at all
+LL | |     Error(PossiblyLargeEnumWithConst<256>),
+   | |     -------------------------------------- the largest variant contains at least 514 bytes
+LL | | }
+   | |_^ the entire enum is at least 514 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Error(Box<PossiblyLargeEnumWithConst<256>>),
+   |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 16 previous errors
 
index 2a4012039ba97a62b993f0234906695186293e7f..2d66daea8046e15c67bb4a3d2d4b7ea00c19eb21 100644 (file)
@@ -5,7 +5,7 @@ LL |         Err(_) => panic!("err"),
    |         ^^^^^^
    |
    = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_)` matches all errors
   --> $DIR/match_wild_err_arm.rs:20:9
@@ -13,7 +13,7 @@ error: `Err(_)` matches all errors
 LL |         Err(_) => panic!(),
    |         ^^^^^^
    |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_)` matches all errors
   --> $DIR/match_wild_err_arm.rs:26:9
@@ -21,7 +21,7 @@ error: `Err(_)` matches all errors
 LL |         Err(_) => {
    |         ^^^^^^
    |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_e)` matches all errors
   --> $DIR/match_wild_err_arm.rs:34:9
@@ -29,7 +29,7 @@ error: `Err(_e)` matches all errors
 LL |         Err(_e) => panic!(),
    |         ^^^^^^^
    |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: aborting due to 4 previous errors
 
index 2a4012039ba97a62b993f0234906695186293e7f..2d66daea8046e15c67bb4a3d2d4b7ea00c19eb21 100644 (file)
@@ -5,7 +5,7 @@ LL |         Err(_) => panic!("err"),
    |         ^^^^^^
    |
    = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_)` matches all errors
   --> $DIR/match_wild_err_arm.rs:20:9
@@ -13,7 +13,7 @@ error: `Err(_)` matches all errors
 LL |         Err(_) => panic!(),
    |         ^^^^^^
    |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_)` matches all errors
   --> $DIR/match_wild_err_arm.rs:26:9
@@ -21,7 +21,7 @@ error: `Err(_)` matches all errors
 LL |         Err(_) => {
    |         ^^^^^^
    |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_e)` matches all errors
   --> $DIR/match_wild_err_arm.rs:34:9
@@ -29,7 +29,7 @@ error: `Err(_e)` matches all errors
 LL |         Err(_e) => panic!(),
    |         ^^^^^^^
    |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: aborting due to 4 previous errors
 
index 36bc52e3374e1a9747ddfdcad7da7306963bb092..ecad10a82903884a182a13a46df9922e4a9896b0 100644 (file)
@@ -18,4 +18,11 @@ fn no_owned_mutex_lock() {
     *value += 1;
 }
 
+fn issue9415() {
+    let mut arc_mutex = Arc::new(Mutex::new(42_u8));
+    let arc_mutex: &mut Arc<Mutex<u8>> = &mut arc_mutex;
+    let mut guard = arc_mutex.lock().unwrap();
+    *guard += 1;
+}
+
 fn main() {}
index ea60df5ae1bbc92cda19453e4756aefea50833b3..f2b1d6fbfbc3e1f4ca237404f4106a5fd2d8f5e7 100644 (file)
@@ -18,4 +18,11 @@ fn no_owned_mutex_lock() {
     *value += 1;
 }
 
+fn issue9415() {
+    let mut arc_mutex = Arc::new(Mutex::new(42_u8));
+    let arc_mutex: &mut Arc<Mutex<u8>> = &mut arc_mutex;
+    let mut guard = arc_mutex.lock().unwrap();
+    *guard += 1;
+}
+
 fn main() {}
index 18ea4e550292a4b3ddd5a729f4ba946afe2f4d13..5991188ab6372389d50ed92e46c479aa0a6a3274 100644 (file)
@@ -79,16 +79,16 @@ fn or_fun_call() {
     without_default.unwrap_or_else(Foo::new);
 
     let mut map = HashMap::<u64, String>::new();
-    map.entry(42).or_insert(String::new());
+    map.entry(42).or_default();
 
     let mut map_vec = HashMap::<u64, Vec<i32>>::new();
-    map_vec.entry(42).or_insert(vec![]);
+    map_vec.entry(42).or_default();
 
     let mut btree = BTreeMap::<u64, String>::new();
-    btree.entry(42).or_insert(String::new());
+    btree.entry(42).or_default();
 
     let mut btree_vec = BTreeMap::<u64, Vec<i32>>::new();
-    btree_vec.entry(42).or_insert(vec![]);
+    btree_vec.entry(42).or_default();
 
     let stringy = Some(String::new());
     let _ = stringy.unwrap_or_default();
index 887f23ac9761dfd7167f44f269d3224cb6d75e75..e3dab4cb14778c06579fe88223a0ee5d8c7d2c12 100644 (file)
@@ -66,6 +66,30 @@ error: use of `unwrap_or` followed by a function call
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
 
+error: use of `or_insert` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:82:19
+   |
+LL |     map.entry(42).or_insert(String::new());
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+
+error: use of `or_insert` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:85:23
+   |
+LL |     map_vec.entry(42).or_insert(vec![]);
+   |                       ^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+
+error: use of `or_insert` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:88:21
+   |
+LL |     btree.entry(42).or_insert(String::new());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+
+error: use of `or_insert` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:91:25
+   |
+LL |     btree_vec.entry(42).or_insert(vec![]);
+   |                         ^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+
 error: use of `unwrap_or` followed by a call to `new`
   --> $DIR/or_fun_call.rs:94:21
    |
@@ -132,5 +156,5 @@ error: use of `unwrap_or` followed by a call to `new`
 LL |         .unwrap_or(String::new());
    |          ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
 
-error: aborting due to 22 previous errors
+error: aborting due to 26 previous errors
 
index 40d7791df281a67f7700871529ed5d0aa96e8b16..a16a3e54d45eadaaf8025b6eadb94b4a2847076d 100644 (file)
@@ -6,6 +6,22 @@ fn f() -> usize {
     42
 }
 
+macro_rules! macro_plus_one {
+    ($m: literal) => {
+        for i in 0..$m + 1 {
+            println!("{}", i);
+        }
+    };
+}
+
+macro_rules! macro_minus_one {
+    ($m: literal) => {
+        for i in 0..=$m - 1 {
+            println!("{}", i);
+        }
+    };
+}
+
 #[warn(clippy::range_plus_one)]
 #[warn(clippy::range_minus_one)]
 fn main() {
@@ -39,4 +55,7 @@ fn main() {
 
     let mut vec: Vec<()> = std::vec::Vec::new();
     vec.drain(..);
+
+    macro_plus_one!(5);
+    macro_minus_one!(5);
 }
index a8ddd9b5f751b36ccb2fb065bd291ee0b2956328..bd6cb4d21be51b653e54e6c42eb2148688175729 100644 (file)
@@ -6,6 +6,22 @@ fn f() -> usize {
     42
 }
 
+macro_rules! macro_plus_one {
+    ($m: literal) => {
+        for i in 0..$m + 1 {
+            println!("{}", i);
+        }
+    };
+}
+
+macro_rules! macro_minus_one {
+    ($m: literal) => {
+        for i in 0..=$m - 1 {
+            println!("{}", i);
+        }
+    };
+}
+
 #[warn(clippy::range_plus_one)]
 #[warn(clippy::range_minus_one)]
 fn main() {
@@ -39,4 +55,7 @@ fn main() {
 
     let mut vec: Vec<()> = std::vec::Vec::new();
     vec.drain(..);
+
+    macro_plus_one!(5);
+    macro_minus_one!(5);
 }
index fb4f1658597a585de8f220e9255e0f5c57388ad5..0223696243b20c75e41e68840d3e05be1f3a83c7 100644 (file)
@@ -1,5 +1,5 @@
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:15:14
+  --> $DIR/range_plus_minus_one.rs:31:14
    |
 LL |     for _ in 0..3 + 1 {}
    |              ^^^^^^^^ help: use: `0..=3`
@@ -7,25 +7,25 @@ LL |     for _ in 0..3 + 1 {}
    = note: `-D clippy::range-plus-one` implied by `-D warnings`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:18:14
+  --> $DIR/range_plus_minus_one.rs:34:14
    |
 LL |     for _ in 0..1 + 5 {}
    |              ^^^^^^^^ help: use: `0..=5`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:21:14
+  --> $DIR/range_plus_minus_one.rs:37:14
    |
 LL |     for _ in 1..1 + 1 {}
    |              ^^^^^^^^ help: use: `1..=1`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:27:14
+  --> $DIR/range_plus_minus_one.rs:43:14
    |
 LL |     for _ in 0..(1 + f()) {}
    |              ^^^^^^^^^^^^ help: use: `0..=f()`
 
 error: an exclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:31:13
+  --> $DIR/range_plus_minus_one.rs:47:13
    |
 LL |     let _ = ..=11 - 1;
    |             ^^^^^^^^^ help: use: `..11`
@@ -33,25 +33,25 @@ LL |     let _ = ..=11 - 1;
    = note: `-D clippy::range-minus-one` implied by `-D warnings`
 
 error: an exclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:32:13
+  --> $DIR/range_plus_minus_one.rs:48:13
    |
 LL |     let _ = ..=(11 - 1);
    |             ^^^^^^^^^^^ help: use: `..11`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:33:13
+  --> $DIR/range_plus_minus_one.rs:49:13
    |
 LL |     let _ = (1..11 + 1);
    |             ^^^^^^^^^^^ help: use: `(1..=11)`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:34:13
+  --> $DIR/range_plus_minus_one.rs:50:13
    |
 LL |     let _ = (f() + 1)..(f() + 1);
    |             ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:38:14
+  --> $DIR/range_plus_minus_one.rs:54:14
    |
 LL |     for _ in 1..ONE + ONE {}
    |              ^^^^^^^^^^^^ help: use: `1..=ONE`
index 78d8f76fe669fb32926d4459252735166997062d..f7df3b85655013f4b02e712354355cf7abbae0d5 100644 (file)
@@ -1,4 +1,5 @@
 #![warn(clippy::result_large_err)]
+#![allow(clippy::large_enum_variant)]
 
 pub fn small_err() -> Result<(), u128> {
     Ok(())
index 0f1f39d72cba187cff97f89762840cc32023c90c..ef19f2854ab12e731663126183c1d8f0795e48bb 100644 (file)
@@ -1,5 +1,5 @@
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:7:23
+  --> $DIR/result_large_err.rs:8:23
    |
 LL | pub fn large_err() -> Result<(), [u8; 512]> {
    |                       ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -8,7 +8,7 @@ LL | pub fn large_err() -> Result<(), [u8; 512]> {
    = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:18:21
+  --> $DIR/result_large_err.rs:19:21
    |
 LL |     pub fn ret() -> Result<(), Self> {
    |                     ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
@@ -16,7 +16,7 @@ LL |     pub fn ret() -> Result<(), Self> {
    = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:23:26
+  --> $DIR/result_large_err.rs:24:26
    |
 LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
@@ -24,7 +24,7 @@ LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
    = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:28:45
+  --> $DIR/result_large_err.rs:29:45
    |
 LL | pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
    |                                             ^^^^^^^ the `Err`-variant is at least 240 bytes
@@ -32,7 +32,7 @@ LL | pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
    = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:36:34
+  --> $DIR/result_large_err.rs:37:34
    |
 LL | pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeError)> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 256 bytes
@@ -40,7 +40,7 @@ LL | pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeErro
    = help: try reducing the size of `(u128, R, FullyDefinedLargeError)`, for example by boxing large elements or replacing it with `Box<(u128, R, FullyDefinedLargeError)>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:47:34
+  --> $DIR/result_large_err.rs:48:34
    |
 LL |     pub fn large_enum_error() -> Result<(), Self> {
    |                                  ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 513 bytes
@@ -48,7 +48,7 @@ LL |     pub fn large_enum_error() -> Result<(), Self> {
    = help: try reducing the size of `LargeErrorVariants<()>`, for example by boxing large elements or replacing it with `Box<LargeErrorVariants<()>>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:53:25
+  --> $DIR/result_large_err.rs:54:25
    |
 LL |     fn large_error() -> Result<(), [u8; 512]> {
    |                         ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -56,7 +56,7 @@ LL |     fn large_error() -> Result<(), [u8; 512]> {
    = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:72:29
+  --> $DIR/result_large_err.rs:73:29
    |
 LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -64,7 +64,7 @@ LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
    = help: try reducing the size of `FullyDefinedUnionError`, for example by boxing large elements or replacing it with `Box<FullyDefinedUnionError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:81:40
+  --> $DIR/result_large_err.rs:82:40
    |
 LL | pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -72,7 +72,7 @@ LL | pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
    = help: try reducing the size of `UnionError<T>`, for example by boxing large elements or replacing it with `Box<UnionError<T>>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:90:34
+  --> $DIR/result_large_err.rs:91:34
    |
 LL | pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes
@@ -80,7 +80,7 @@ LL | pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
    = help: try reducing the size of `ArrayError<i32, U>`, for example by boxing large elements or replacing it with `Box<ArrayError<i32, U>>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:94:31
+  --> $DIR/result_large_err.rs:95:31
    |
 LL | pub fn array_error<T, U>() -> Result<(), ArrayError<(i32, T), U>> {
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes
index 9cd5bc73b1ec51852af3c2bbeae84cb5ddf05594..a920c63b199c1e194697c33066be47f19c88e78c 100644 (file)
@@ -357,3 +357,63 @@ mod issue_9317 {
         consume(b.to_string());
     }
 }
+
+mod issue_9351 {
+    #![allow(dead_code)]
+
+    use std::ops::Deref;
+    use std::path::{Path, PathBuf};
+
+    fn require_deref_path<T: Deref<Target = std::path::Path>>(x: T) -> T {
+        x
+    }
+
+    fn generic_arg_used_elsewhere<T: AsRef<Path>>(_x: T, _y: T) {}
+
+    fn id<T: AsRef<str>>(x: T) -> T {
+        x
+    }
+
+    fn predicates_are_satisfied(_x: impl std::fmt::Write) {}
+
+    // Should lint
+    fn single_return() -> impl AsRef<str> {
+        id("abc")
+    }
+
+    // Should not lint
+    fn multiple_returns(b: bool) -> impl AsRef<str> {
+        if b {
+            return String::new();
+        }
+
+        id("abc".to_string())
+    }
+
+    struct S1(String);
+
+    // Should not lint
+    fn fields1() -> S1 {
+        S1(id("abc".to_string()))
+    }
+
+    struct S2 {
+        s: String,
+    }
+
+    // Should not lint
+    fn fields2() {
+        let mut s = S2 { s: "abc".into() };
+        s.s = id("abc".to_string());
+    }
+
+    pub fn main() {
+        let path = std::path::Path::new("x");
+        let path_buf = path.to_owned();
+
+        // Should not lint.
+        let _x: PathBuf = require_deref_path(path.to_owned());
+        generic_arg_used_elsewhere(path.to_owned(), path_buf);
+        predicates_are_satisfied(id("abc".to_string()));
+    }
+}
index 7f62ba3ab5d559ea0d8a60da23f977389044f054..2128bdacddadf03fa7736e020583e5912b00a6e7 100644 (file)
@@ -357,3 +357,63 @@ pub fn main() {
         consume(b.to_string());
     }
 }
+
+mod issue_9351 {
+    #![allow(dead_code)]
+
+    use std::ops::Deref;
+    use std::path::{Path, PathBuf};
+
+    fn require_deref_path<T: Deref<Target = std::path::Path>>(x: T) -> T {
+        x
+    }
+
+    fn generic_arg_used_elsewhere<T: AsRef<Path>>(_x: T, _y: T) {}
+
+    fn id<T: AsRef<str>>(x: T) -> T {
+        x
+    }
+
+    fn predicates_are_satisfied(_x: impl std::fmt::Write) {}
+
+    // Should lint
+    fn single_return() -> impl AsRef<str> {
+        id("abc".to_string())
+    }
+
+    // Should not lint
+    fn multiple_returns(b: bool) -> impl AsRef<str> {
+        if b {
+            return String::new();
+        }
+
+        id("abc".to_string())
+    }
+
+    struct S1(String);
+
+    // Should not lint
+    fn fields1() -> S1 {
+        S1(id("abc".to_string()))
+    }
+
+    struct S2 {
+        s: String,
+    }
+
+    // Should not lint
+    fn fields2() {
+        let mut s = S2 { s: "abc".into() };
+        s.s = id("abc".to_string());
+    }
+
+    pub fn main() {
+        let path = std::path::Path::new("x");
+        let path_buf = path.to_owned();
+
+        // Should not lint.
+        let _x: PathBuf = require_deref_path(path.to_owned());
+        generic_arg_used_elsewhere(path.to_owned(), path_buf);
+        predicates_are_satisfied(id("abc".to_string()));
+    }
+}
index 243b4599dba427ccc2c657014b473aef7a4ed750..7deb90b06f3b7bd6e73cfed25eef9481e69e3c05 100644 (file)
@@ -509,5 +509,11 @@ error: unnecessary use of `to_string`
 LL |         Box::new(build(y.to_string()))
    |                        ^^^^^^^^^^^^^ help: use: `y`
 
-error: aborting due to 78 previous errors
+error: unnecessary use of `to_string`
+  --> $DIR/unnecessary_to_owned.rs:381:12
+   |
+LL |         id("abc".to_string())
+   |            ^^^^^^^^^^^^^^^^^ help: use: `"abc"`
+
+error: aborting due to 79 previous errors
 
index c2b9bd2c881fe916b8e2f789dcf3bce7de18b1ee..84f779569ff9dd7e863d37e33411a608e05e9196 100644 (file)
@@ -69,6 +69,9 @@ fn unwrap_or_else_default() {
 
     let with_default_type: Option<Vec<u64>> = None;
     with_default_type.unwrap_or_default();
+
+    let empty_string = None::<String>;
+    empty_string.unwrap_or_default();
 }
 
 fn main() {}
index d55664990aeb96f6dbbcf30869fc602538604329..1735bd5808e5a94713e2593874ff8305a73f6cb1 100644 (file)
@@ -69,6 +69,9 @@ fn make<T, V>(_: V) -> T {
 
     let with_default_type: Option<Vec<u64>> = None;
     with_default_type.unwrap_or_else(Vec::new);
+
+    let empty_string = None::<String>;
+    empty_string.unwrap_or_else(|| "".to_string());
 }
 
 fn main() {}
index 53e31d85edfca277bab0061c7815eb5c18199c6d..d2b9212223f7795957c33f5549a84e9af0a74f53 100644 (file)
@@ -30,5 +30,11 @@ error: use of `.unwrap_or_else(..)` to construct default value
 LL |     with_default_type.unwrap_or_else(Vec::new);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
 
-error: aborting due to 5 previous errors
+error: use of `.unwrap_or_else(..)` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:74:5
+   |
+LL |     empty_string.unwrap_or_else(|| "".to_string());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()`
+
+error: aborting due to 6 previous errors
 
index 531745424a7d02b77c8503480b81eb9b72ad2103..8dd098a5b5405ab33c57d72c7a5c339f838b4a21 100644 (file)
@@ -104,3 +104,9 @@ fn _cond_push_with_large_start(x: bool) -> Vec<u32> {
 
     v2
 }
+
+fn f() {
+    let mut v = Vec::new();
+    v.push((0i32, 0i32));
+    let y = v[0].0.abs();
+}
index 50b029fc33727a2a23351099f8beb60ac88271f1..a9da1c520197d3af1705e30e2371d29ba44d7f47 100644 (file)
@@ -62,5 +62,12 @@ LL | |     v2.push(1);
 LL | |     v2.push(0);
    | |_______________^ help: consider using the `vec![]` macro: `let mut v2 = vec![..];`
 
-error: aborting due to 7 previous errors
+error: calls to `push` immediately after creation
+  --> $DIR/vec_init_then_push.rs:109:5
+   |
+LL | /     let mut v = Vec::new();
+LL | |     v.push((0i32, 0i32));
+   | |_________________________^ help: consider using the `vec![]` macro: `let v = vec![..];`
+
+error: aborting due to 8 previous errors
 
index 8f097f47b451aae68113a00274340398adf109c0..3ff1cbf20cd26cc84009f42df3998f2b48222649 100644 (file)
@@ -897,15 +897,27 @@ pub fn make_test_description<R: Read>(
     let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_shadow_call_stack = util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(&&*config.target);
-    // for `-Z gcc-ld=lld`
+
+    // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find
+    // whether `rust-lld` is present in the compiler under test.
+    //
+    // The --compile-lib-path is the path to host shared libraries, but depends on the OS. For
+    // example:
+    // - on linux, it can be <sysroot>/lib
+    // - on windows, it can be <sysroot>/bin
+    //
+    // However, `rust-lld` is only located under the lib path, so we look for it there.
     let has_rust_lld = config
         .compile_lib_path
+        .parent()
+        .expect("couldn't traverse to the parent of the specified --compile-lib-path")
+        .join("lib")
         .join("rustlib")
         .join(&config.target)
         .join("bin")
-        .join("gcc-ld")
-        .join(if config.host.contains("windows") { "ld.exe" } else { "ld" })
+        .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" })
         .exists();
+
     iter_header(path, src, &mut |revision, ln| {
         if revision.is_some() && revision != cfg {
             return;
index 1795f3d7fe5bc5a3a0a9b908f333681274971dbb..b5e977b2637d8075fc6d51682e1a6e204187d715 100644 (file)
 //! obtained from the wrapper's name as the first two arguments.
 //! On Windows it spawns a `..\rust-lld.exe` child process.
 
+use std::env::{self, consts::EXE_SUFFIX};
 use std::fmt::Display;
 use std::path::{Path, PathBuf};
-use std::{env, process};
+use std::process;
 
 trait UnwrapOrExitWith<T> {
     fn unwrap_or_exit_with(self, context: &str) -> T;
@@ -42,7 +43,7 @@ fn unwrap_or_exit_with(self, context: &str) -> T {
 /// Exits if the parent directory cannot be determined.
 fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf {
     let mut rust_lld_exe_name = "rust-lld".to_owned();
-    rust_lld_exe_name.push_str(env::consts::EXE_SUFFIX);
+    rust_lld_exe_name.push_str(EXE_SUFFIX);
     let mut rust_lld_path = current_exe_path
         .parent()
         .unwrap_or_exit_with("directory containing current executable could not be determined")
@@ -55,13 +56,14 @@ fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf {
 
 /// Extract LLD flavor name from the lld-wrapper executable name.
 fn get_lld_flavor(current_exe_path: &Path) -> Result<&'static str, String> {
-    let stem = current_exe_path.file_stem();
-    Ok(match stem.and_then(|s| s.to_str()) {
+    let file = current_exe_path.file_name();
+    let stem = file.and_then(|s| s.to_str()).map(|s| s.trim_end_matches(EXE_SUFFIX));
+    Ok(match stem {
         Some("ld.lld") => "gnu",
         Some("ld64.lld") => "darwin",
         Some("lld-link") => "link",
         Some("wasm-ld") => "wasm",
-        _ => return Err(format!("{:?}", stem)),
+        _ => return Err(format!("{:?}", file)),
     })
 }
 
index dba35d2be72f4b78343d1a0f0b4737306f310672..ef3f649e49607a1fad64eb0a5139110df3efa2a7 160000 (submodule)
@@ -1 +1 @@
-Subproject commit dba35d2be72f4b78343d1a0f0b4737306f310672
+Subproject commit ef3f649e49607a1fad64eb0a5139110df3efa2a7
index a70252fa65a5d41dc9a26355ca5849c32a59474b..1563ee0b143851435a28597c8c088621e5c4a59b 100644 (file)
@@ -6,15 +6,15 @@ on:
   pull_request:
   push:
     branches:
-    - auto
-    - try
+      - auto
+      - try
 
 env:
   CARGO_INCREMENTAL: 0
   CARGO_NET_RETRY: 10
   CI: 1
   RUST_BACKTRACE: short
-  RUSTFLAGS: "-D warnings -W unreachable-pub -W rust-2021-compatibility"
+  RUSTFLAGS: "-D warnings -W unreachable-pub -W bare-trait-objects"
   RUSTUP_MAX_RETRIES: 10
 
 jobs:
@@ -31,25 +31,25 @@ jobs:
         os: [ubuntu-latest, windows-latest, macos-latest]
 
     steps:
-    - name: Checkout repository
-      uses: actions/checkout@v3
-      with:
-        ref: ${{ github.event.pull_request.head.sha }}
-        fetch-depth: 20
+      - name: Checkout repository
+        uses: actions/checkout@v3
+        with:
+          ref: ${{ github.event.pull_request.head.sha }}
+          fetch-depth: 20
 
-    - name: Install Rust toolchain
-      run: |
-        rustup update --no-self-update stable
-        rustup component add rustfmt rust-src
+      - name: Install Rust toolchain
+        run: |
+          rustup update --no-self-update stable
+          rustup component add rustfmt rust-src
 
-    - name: Cache Dependencies
-      uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
+      - name: Cache Dependencies
+        uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
 
-    - name: Compile
-      run: cargo test --no-run --locked
+      - name: Compile
+        run: cargo test --no-run --locked
 
-    - name: Test
-      run: cargo test -- --nocapture --quiet
+      - name: Test
+        run: cargo test -- --nocapture --quiet
 
   # Weird targets to catch non-portable code
   rust-cross:
@@ -64,25 +64,25 @@ jobs:
       targets_ide: "wasm32-unknown-unknown"
 
     steps:
-    - name: Checkout repository
-      uses: actions/checkout@v3
-
-    - name: Install Rust toolchain
-      run: |
-        rustup update --no-self-update stable
-        rustup target add ${{ env.targets }} ${{ env.targets_ide }}
-
-    - name: Cache Dependencies
-      uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
-
-    - name: Check
-      run: |
-        for target in ${{ env.targets }}; do
-          cargo check --target=$target --all-targets
-        done
-        for target in ${{ env.targets_ide }}; do
-          cargo check -p ide --target=$target --all-targets
-        done
+      - name: Checkout repository
+        uses: actions/checkout@v3
+
+      - name: Install Rust toolchain
+        run: |
+          rustup update --no-self-update stable
+          rustup target add ${{ env.targets }} ${{ env.targets_ide }}
+
+      - name: Cache Dependencies
+        uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
+
+      - name: Check
+        run: |
+          for target in ${{ env.targets }}; do
+            cargo check --target=$target --all-targets
+          done
+          for target in ${{ env.targets_ide }}; do
+            cargo check -p ide --target=$target --all-targets
+          done
 
   typescript:
     if: github.repository == 'rust-lang/rust-analyzer'
@@ -95,47 +95,47 @@ jobs:
     runs-on: ${{ matrix.os }}
 
     steps:
-    - name: Checkout repository
-      uses: actions/checkout@v3
-
-    - name: Install Nodejs
-      uses: actions/setup-node@v1
-      with:
-        node-version: 16.x
-
-    - name: Install xvfb
-      if: matrix.os == 'ubuntu-latest'
-      run: sudo apt-get install -y xvfb
-
-    - run: npm ci
-      working-directory: ./editors/code
-
-#    - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
-#      if: runner.os == 'Linux'
-#      working-directory: ./editors/code
-
-    - run: npm run lint
-      working-directory: ./editors/code
-
-    - name: Run VS Code tests (Linux)
-      if: matrix.os == 'ubuntu-latest'
-      env:
-        VSCODE_CLI: 1
-      run: xvfb-run npm test
-      working-directory: ./editors/code
-
-    - name: Run VS Code tests (Windows)
-      if: matrix.os == 'windows-latest'
-      env:
-        VSCODE_CLI: 1
-      run: npm test
-      working-directory: ./editors/code
-
-    - run: npm run pretest
-      working-directory: ./editors/code
-
-    - run: npm run package --scripts-prepend-node-path
-      working-directory: ./editors/code
+      - name: Checkout repository
+        uses: actions/checkout@v3
+
+      - name: Install Nodejs
+        uses: actions/setup-node@v1
+        with:
+          node-version: 16.x
+
+      - name: Install xvfb
+        if: matrix.os == 'ubuntu-latest'
+        run: sudo apt-get install -y xvfb
+
+      - run: npm ci
+        working-directory: ./editors/code
+
+      #    - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
+      #      if: runner.os == 'Linux'
+      #      working-directory: ./editors/code
+
+      - run: npm run lint
+        working-directory: ./editors/code
+
+      - name: Run VS Code tests (Linux)
+        if: matrix.os == 'ubuntu-latest'
+        env:
+          VSCODE_CLI: 1
+        run: xvfb-run npm test
+        working-directory: ./editors/code
+
+      - name: Run VS Code tests (Windows)
+        if: matrix.os == 'windows-latest'
+        env:
+          VSCODE_CLI: 1
+        run: npm test
+        working-directory: ./editors/code
+
+      - run: npm run pretest
+        working-directory: ./editors/code
+
+      - run: npm run package --scripts-prepend-node-path
+        working-directory: ./editors/code
 
   end-success:
     name: bors build finished
index b2e5db6f689b518e5b6cfdfbe11a7b79294bdbb1..303a10615bb7b7e33e5beb616a27059321cfff58 100644 (file)
@@ -248,7 +248,7 @@ jobs:
         if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
         working-directory: ./editors/code
         # token from https://dev.azure.com/rust-analyzer/
-        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
+        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
 
       - name: Publish Extension (Code Marketplace, nightly)
         if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
@@ -258,4 +258,4 @@ jobs:
       - name: Publish Extension (OpenVSX, nightly)
         if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
         working-directory: ./editors/code
-        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
+        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
index 1d818d96267c177223985d6588e138556227e9c2..22f5fb9926638e0f7ea9413563fbcec4a372483f 100644 (file)
@@ -250,6 +250,10 @@ pub struct Body {
 
 pub type LabelPtr = AstPtr<ast::Label>;
 pub type LabelSource = InFile<LabelPtr>;
+
+pub type FieldPtr = AstPtr<ast::RecordExprField>;
+pub type FieldSource = InFile<FieldPtr>;
+
 /// An item body together with the mapping from syntax nodes to HIR expression
 /// IDs. This is needed to go from e.g. a position in a file to the HIR
 /// expression containing it; but for type inference etc., we want to operate on
@@ -264,18 +268,18 @@ pub struct Body {
 #[derive(Default, Debug, Eq, PartialEq)]
 pub struct BodySourceMap {
     expr_map: FxHashMap<ExprSource, ExprId>,
-    expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
+    expr_map_back: ArenaMap<ExprId, ExprSource>,
 
     pat_map: FxHashMap<PatSource, PatId>,
-    pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
+    pat_map_back: ArenaMap<PatId, PatSource>,
 
     label_map: FxHashMap<LabelSource, LabelId>,
     label_map_back: ArenaMap<LabelId, LabelSource>,
 
     /// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
     /// Instead, we use id of expression (`92`) to identify the field.
-    field_map: FxHashMap<InFile<AstPtr<ast::RecordExprField>>, ExprId>,
-    field_map_back: FxHashMap<ExprId, InFile<AstPtr<ast::RecordExprField>>>,
+    field_map: FxHashMap<FieldSource, ExprId>,
+    field_map_back: FxHashMap<ExprId, FieldSource>,
 
     expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
 
@@ -420,7 +424,7 @@ fn index(&self, label: LabelId) -> &Label {
 // Perhaps `expr_syntax` and `expr_id`?
 impl BodySourceMap {
     pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
-        self.expr_map_back[expr].clone()
+        self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
     }
 
     pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
@@ -434,7 +438,7 @@ pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId
     }
 
     pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
-        self.pat_map_back[pat].clone()
+        self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
     }
 
     pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
@@ -456,9 +460,10 @@ pub fn node_label(&self, node: InFile<&ast::Label>) -> Option<LabelId> {
         self.label_map.get(&src).cloned()
     }
 
-    pub fn field_syntax(&self, expr: ExprId) -> InFile<AstPtr<ast::RecordExprField>> {
+    pub fn field_syntax(&self, expr: ExprId) -> FieldSource {
         self.field_map_back[&expr].clone()
     }
+
     pub fn node_field(&self, node: InFile<&ast::RecordExprField>) -> Option<ExprId> {
         let src = node.map(AstPtr::new);
         self.field_map.get(&src).cloned()
index f6ec8bf7e9e0b4475302dfb6ed17b3c0e8c44d88..3b3297f7811c07628ba30e2382531672f2c89c39 100644 (file)
@@ -24,7 +24,7 @@
 
 use crate::{
     adt::StructKind,
-    body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
+    body::{Body, BodySourceMap, Expander, ExprPtr, LabelPtr, LabelSource, PatPtr},
     body::{BodyDiagnostic, ExprSource, PatSource},
     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
     db::DefDatabase,
@@ -150,21 +150,21 @@ fn ctx(&self) -> LowerCtx<'_> {
         LowerCtx::new(self.db, self.expander.current_file_id)
     }
 
-    fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
+    fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
         let src = self.expander.to_source(ptr);
-        let id = self.make_expr(expr, Ok(src.clone()));
+        let id = self.make_expr(expr, src.clone());
         self.source_map.expr_map.insert(src, id);
         id
     }
     // desugared exprs don't have ptr, that's wrong and should be fixed
     // somehow.
     fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
-        self.make_expr(expr, Err(SyntheticSyntax))
+        self.body.exprs.alloc(expr)
     }
     fn missing_expr(&mut self) -> ExprId {
         self.alloc_expr_desugared(Expr::Missing)
     }
-    fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) -> ExprId {
+    fn make_expr(&mut self, expr: Expr, src: ExprSource) -> ExprId {
         let id = self.body.exprs.alloc(expr);
         self.source_map.expr_map_back.insert(id, src);
         id
@@ -172,20 +172,20 @@ fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) ->
 
     fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
         let src = self.expander.to_source(ptr);
-        let id = self.make_pat(pat, Ok(src.clone()));
+        let id = self.make_pat(pat, src.clone());
         self.source_map.pat_map.insert(src, id);
         id
     }
     fn missing_pat(&mut self) -> PatId {
-        self.make_pat(Pat::Missing, Err(SyntheticSyntax))
+        self.body.pats.alloc(Pat::Missing)
     }
-    fn make_pat(&mut self, pat: Pat, src: Result<PatSource, SyntheticSyntax>) -> PatId {
+    fn make_pat(&mut self, pat: Pat, src: PatSource) -> PatId {
         let id = self.body.pats.alloc(pat);
         self.source_map.pat_map_back.insert(id, src);
         id
     }
 
-    fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId {
+    fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
         let src = self.expander.to_source(ptr);
         let id = self.make_label(label, src.clone());
         self.source_map.label_map.insert(src, id);
@@ -550,20 +550,6 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
                     None => self.alloc_expr(Expr::Missing, syntax_ptr),
                 }
             }
-            ast::Expr::MacroStmts(e) => {
-                let statements: Box<[_]> =
-                    e.statements().filter_map(|s| self.collect_stmt(s)).collect();
-                let tail = e.expr().map(|e| self.collect_expr(e));
-
-                if e.syntax().children().next().is_none() {
-                    // HACK: make sure that macros that expand to nothing aren't treated as a `()`
-                    // expression when used in block tail position.
-                    cov_mark::hit!(empty_macro_in_trailing_position_is_removed);
-                    return None;
-                }
-
-                self.alloc_expr(Expr::MacroStmts { tail, statements }, syntax_ptr)
-            }
             ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
         })
     }
@@ -640,11 +626,46 @@ fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
         }
     }
 
-    fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Statement> {
+    fn collect_macro_as_stmt(
+        &mut self,
+        statements: &mut Vec<Statement>,
+        mac: ast::MacroExpr,
+    ) -> Option<ExprId> {
+        let mac_call = mac.macro_call()?;
+        let syntax_ptr = AstPtr::new(&ast::Expr::from(mac));
+        let macro_ptr = AstPtr::new(&mac_call);
+        let expansion = self.collect_macro_call(
+            mac_call,
+            macro_ptr,
+            false,
+            |this, expansion: Option<ast::MacroStmts>| match expansion {
+                Some(expansion) => {
+                    expansion.statements().for_each(|stmt| this.collect_stmt(statements, stmt));
+                    expansion.expr().and_then(|expr| match expr {
+                        ast::Expr::MacroExpr(mac) => this.collect_macro_as_stmt(statements, mac),
+                        expr => Some(this.collect_expr(expr)),
+                    })
+                }
+                None => None,
+            },
+        );
+        match expansion {
+            Some(tail) => {
+                // Make the macro-call point to its expanded expression so we can query
+                // semantics on syntax pointers to the macro
+                let src = self.expander.to_source(syntax_ptr);
+                self.source_map.expr_map.insert(src, tail);
+                Some(tail)
+            }
+            None => None,
+        }
+    }
+
+    fn collect_stmt(&mut self, statements: &mut Vec<Statement>, s: ast::Stmt) {
         match s {
             ast::Stmt::LetStmt(stmt) => {
                 if self.check_cfg(&stmt).is_none() {
-                    return None;
+                    return;
                 }
                 let pat = self.collect_pat_opt(stmt.pat());
                 let type_ref =
@@ -654,61 +675,26 @@ fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Statement> {
                     .let_else()
                     .and_then(|let_else| let_else.block_expr())
                     .map(|block| self.collect_block(block));
-                Some(Statement::Let { pat, type_ref, initializer, else_branch })
+                statements.push(Statement::Let { pat, type_ref, initializer, else_branch });
             }
             ast::Stmt::ExprStmt(stmt) => {
                 let expr = stmt.expr();
-                if let Some(expr) = &expr {
-                    if self.check_cfg(expr).is_none() {
-                        return None;
-                    }
+                match &expr {
+                    Some(expr) if self.check_cfg(expr).is_none() => return,
+                    _ => (),
                 }
                 let has_semi = stmt.semicolon_token().is_some();
                 // Note that macro could be expanded to multiple statements
-                if let Some(expr @ ast::Expr::MacroExpr(mac)) = &expr {
-                    let mac_call = mac.macro_call()?;
-                    let syntax_ptr = AstPtr::new(expr);
-                    let macro_ptr = AstPtr::new(&mac_call);
-                    let stmt = self.collect_macro_call(
-                        mac_call,
-                        macro_ptr,
-                        false,
-                        |this, expansion: Option<ast::MacroStmts>| match expansion {
-                            Some(expansion) => {
-                                let statements = expansion
-                                    .statements()
-                                    .filter_map(|stmt| this.collect_stmt(stmt))
-                                    .collect();
-                                let tail = expansion.expr().map(|expr| this.collect_expr(expr));
-
-                                let mac_stmts = this.alloc_expr(
-                                    Expr::MacroStmts { tail, statements },
-                                    AstPtr::new(&ast::Expr::MacroStmts(expansion)),
-                                );
-
-                                Some(mac_stmts)
-                            }
-                            None => None,
-                        },
-                    );
-
-                    let expr = match stmt {
-                        Some(expr) => {
-                            // Make the macro-call point to its expanded expression so we can query
-                            // semantics on syntax pointers to the macro
-                            let src = self.expander.to_source(syntax_ptr);
-                            self.source_map.expr_map.insert(src, expr);
-                            expr
-                        }
-                        None => self.alloc_expr(Expr::Missing, syntax_ptr),
-                    };
-                    Some(Statement::Expr { expr, has_semi })
+                if let Some(ast::Expr::MacroExpr(mac)) = expr {
+                    if let Some(expr) = self.collect_macro_as_stmt(statements, mac) {
+                        statements.push(Statement::Expr { expr, has_semi })
+                    }
                 } else {
                     let expr = self.collect_expr_opt(expr);
-                    Some(Statement::Expr { expr, has_semi })
+                    statements.push(Statement::Expr { expr, has_semi });
                 }
             }
-            ast::Stmt::Item(_item) => None,
+            ast::Stmt::Item(_item) => (),
         }
     }
 
@@ -729,9 +715,12 @@ fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
         let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
         let prev_local_module = mem::replace(&mut self.expander.module, module);
 
-        let mut statements: Vec<_> =
-            block.statements().filter_map(|s| self.collect_stmt(s)).collect();
-        let tail = block.tail_expr().and_then(|e| self.maybe_collect_expr(e));
+        let mut statements = Vec::new();
+        block.statements().for_each(|s| self.collect_stmt(&mut statements, s));
+        let tail = block.tail_expr().and_then(|e| match e {
+            ast::Expr::MacroExpr(mac) => self.collect_macro_as_stmt(&mut statements, mac),
+            expr => self.maybe_collect_expr(expr),
+        });
         let tail = tail.or_else(|| {
             let stmt = statements.pop()?;
             if let Statement::Expr { expr, has_semi: false } = stmt {
index ddd476efe5c4d764dabd4ff597e732d902fb3dec..f2fed954444e2ca80b04a41a7bafa488f87905e4 100644 (file)
@@ -422,19 +422,6 @@ fn print_expr(&mut self, expr: ExprId) {
                 }
                 w!(self, "}}");
             }
-            Expr::MacroStmts { statements, tail } => {
-                w!(self, "{{ // macro statements");
-                self.indented(|p| {
-                    for stmt in statements.iter() {
-                        p.print_stmt(stmt);
-                    }
-                    if let Some(tail) = tail {
-                        p.print_expr(*tail);
-                    }
-                });
-                self.newline();
-                w!(self, "}}");
-            }
         }
     }
 
index f4c390dce26e0520168594430508281406137c3f..45f64ebb06007b7c5cf1a414d02930d5a12b203a 100644 (file)
@@ -47,16 +47,9 @@ pub struct ScopeData {
 impl ExprScopes {
     pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
         let body = db.body(def);
-        Arc::new(ExprScopes::new(&*body))
-    }
-
-    fn new(body: &Body) -> ExprScopes {
-        let mut scopes =
-            ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() };
-        let mut root = scopes.root_scope();
-        scopes.add_params_bindings(body, root, &body.params);
-        compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
-        scopes
+        let mut scopes = ExprScopes::new(&*body);
+        scopes.shrink_to_fit();
+        Arc::new(scopes)
     }
 
     pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
@@ -89,6 +82,17 @@ pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
     pub fn scope_by_expr(&self) -> &FxHashMap<ExprId, ScopeId> {
         &self.scope_by_expr
     }
+}
+
+impl ExprScopes {
+    fn new(body: &Body) -> ExprScopes {
+        let mut scopes =
+            ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() };
+        let mut root = scopes.root_scope();
+        scopes.add_params_bindings(body, root, &body.params);
+        compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
+        scopes
+    }
 
     fn root_scope(&mut self) -> ScopeId {
         self.scopes.alloc(ScopeData { parent: None, block: None, label: None, entries: vec![] })
@@ -138,6 +142,13 @@ fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId])
     fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
         self.scope_by_expr.insert(node, scope);
     }
+
+    fn shrink_to_fit(&mut self) {
+        let ExprScopes { scopes, scope_by_expr } = self;
+        scopes.shrink_to_fit();
+        scopes.values_mut().for_each(|it| it.entries.shrink_to_fit());
+        scope_by_expr.shrink_to_fit();
+    }
 }
 
 fn compute_block_scopes(
@@ -176,9 +187,6 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
 
     scopes.set_scope(expr, *scope);
     match &body[expr] {
-        Expr::MacroStmts { statements, tail } => {
-            compute_block_scopes(statements, *tail, body, scopes, scope);
-        }
         Expr::Block { statements, tail, id, label } => {
             let mut scope = scopes.new_block_scope(*scope, *id, make_label(label));
             // Overwrite the old scope for the block expr, so that every block scope can be found
index 4381b43c258bfe90a9387e10f7608981090105f8..419d3feec3b6c2240c8be326edb0ad24a402c9eb 100644 (file)
@@ -206,10 +206,6 @@ pub enum Expr {
     Unsafe {
         body: ExprId,
     },
-    MacroStmts {
-        statements: Box<[Statement]>,
-        tail: Option<ExprId>,
-    },
     Array(Array),
     Literal(Literal),
     Underscore,
@@ -263,7 +259,7 @@ pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
             Expr::Let { expr, .. } => {
                 f(*expr);
             }
-            Expr::MacroStmts { tail, statements } | Expr::Block { statements, tail, .. } => {
+            Expr::Block { statements, tail, .. } => {
                 for stmt in statements.iter() {
                     match stmt {
                         Statement::Let { initializer, .. } => {
index 6eb530ecc54209d5e2f37ea98a8012c09ac3e87a..9b4ce9f97c86ff4b708e8c124ac71f07b385463e 100644 (file)
@@ -64,7 +64,7 @@
 use itertools::Itertools;
 use la_arena::Arena;
 use profile::Count;
-use rustc_hash::FxHashMap;
+use rustc_hash::{FxHashMap, FxHashSet};
 use stdx::format_to;
 use syntax::{ast, SmolStr};
 
@@ -98,7 +98,11 @@ pub struct DefMap {
     /// The prelude module for this crate. This either comes from an import
     /// marked with the `prelude_import` attribute, or (in the normal case) from
     /// a dependency (`std` or `core`).
+    /// The prelude is empty for non-block DefMaps (unless `#[prelude_import]` was used,
+    /// but that attribute is nightly and when used in a block, it affects resolution globally
+    /// so we aren't handling this correctly anyways).
     prelude: Option<ModuleId>,
+    /// The extern prelude is only populated for non-block DefMaps
     extern_prelude: FxHashMap<Name, ModuleId>,
 
     /// Side table for resolving derive helpers.
@@ -114,6 +118,8 @@ pub struct DefMap {
     registered_attrs: Vec<SmolStr>,
     /// Custom tool modules registered with `#![register_tool]`.
     registered_tools: Vec<SmolStr>,
+    /// Unstable features of Rust enabled with `#![feature(A, B)]`.
+    unstable_features: FxHashSet<SmolStr>,
 
     edition: Edition,
     recursion_limit: Option<u32>,
@@ -284,6 +290,7 @@ fn empty(krate: CrateId, edition: Edition, module_data: ModuleData) -> DefMap {
             modules,
             registered_attrs: Vec::new(),
             registered_tools: Vec::new(),
+            unstable_features: FxHashSet::default(),
             diagnostics: Vec::new(),
         }
     }
@@ -314,6 +321,10 @@ pub fn registered_attrs(&self) -> &[SmolStr] {
         &self.registered_attrs
     }
 
+    pub fn is_unstable_feature_enabled(&self, feature: &str) -> bool {
+        self.unstable_features.contains(feature)
+    }
+
     pub fn root(&self) -> LocalModuleId {
         self.root
     }
@@ -479,6 +490,7 @@ fn shrink_to_fit(&mut self) {
             registered_tools,
             fn_proc_macro_mapping,
             derive_helpers_in_scope,
+            unstable_features,
             proc_macro_loading_error: _,
             block: _,
             edition: _,
@@ -496,6 +508,7 @@ fn shrink_to_fit(&mut self) {
         registered_tools.shrink_to_fit();
         fn_proc_macro_mapping.shrink_to_fit();
         derive_helpers_in_scope.shrink_to_fit();
+        unstable_features.shrink_to_fit();
         for (_, module) in modules.iter_mut() {
             module.children.shrink_to_fit();
             module.scope.shrink_to_fit();
index 8a6bb929c3df7bd660e2fcd5995b8e38b61bcfc0..495bbe4579f00780774fc970110130f7fdd0ddb3 100644 (file)
@@ -294,6 +294,17 @@ fn seed_with_top_level(&mut self) {
                     continue;
                 }
 
+                if *attr_name == hir_expand::name![feature] {
+                    let features =
+                        attr.parse_path_comma_token_tree().into_iter().flatten().filter_map(
+                            |feat| match feat.segments() {
+                                [name] => Some(name.to_smol_str()),
+                                _ => None,
+                            },
+                        );
+                    self.def_map.unstable_features.extend(features);
+                }
+
                 let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
                     || *attr_name == hir_expand::name![register_tool];
                 if !attr_is_register_like {
@@ -501,10 +512,9 @@ fn inject_prelude(&mut self, crate_attrs: &Attrs) {
             Edition::Edition2021 => name![rust_2021],
         };
 
-        let path_kind = if self.def_map.edition == Edition::Edition2015 {
-            PathKind::Plain
-        } else {
-            PathKind::Abs
+        let path_kind = match self.def_map.edition {
+            Edition::Edition2015 => PathKind::Plain,
+            _ => PathKind::Abs,
         };
         let path =
             ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter());
@@ -524,7 +534,6 @@ fn inject_prelude(&mut self, crate_attrs: &Attrs) {
             match per_ns.types {
                 Some((ModuleDefId::ModuleId(m), _)) => {
                     self.def_map.prelude = Some(m);
-                    return;
                 }
                 types => {
                     tracing::debug!(
@@ -839,7 +848,10 @@ fn record_resolved_import(&mut self, directive: &ImportDirective) {
                 tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
 
                 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
-                if import.is_extern_crate && module_id == self.def_map.root {
+                if import.is_extern_crate
+                    && self.def_map.block.is_none()
+                    && module_id == self.def_map.root
+                {
                     if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name)
                     {
                         self.def_map.extern_prelude.insert(name.clone(), def);
index 99f7f1b549e2c91f0c09e3af97a6be772f0c1b61..ca7bcc814e8f8e41e4ced5c765e48f22af51a505 100644 (file)
@@ -65,6 +65,7 @@ pub(super) fn resolve_declaration(
         name: &Name,
         attr_path: Option<&SmolStr>,
     ) -> Result<(FileId, bool, ModDir), Box<[String]>> {
+        let name = name.unescaped();
         let orig_file_id = file_id.original_file(db.upcast());
 
         let mut candidate_files = ArrayVec::<_, 2>::new();
@@ -73,12 +74,10 @@ pub(super) fn resolve_declaration(
                 candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner))
             }
             None if file_id.is_include_macro(db.upcast()) => {
-                let name = name.unescaped();
                 candidate_files.push(format!("{}.rs", name));
                 candidate_files.push(format!("{}/mod.rs", name));
             }
             None => {
-                let name = name.unescaped();
                 candidate_files.push(format!("{}{}.rs", self.dir_path.0, name));
                 candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name));
             }
index 3fa585574deec5076c4ca53f0afd3be52747310e..ba3bf8b5a5cfa54075da94a07765c26f98fb2a7b 100644 (file)
@@ -127,7 +127,15 @@ fn module_resolution_works_for_raw_modules() {
 use self::r#async::Bar;
 
 //- /async.rs
+mod foo;
+mod r#async;
 pub struct Bar;
+
+//- /async/foo.rs
+pub struct Foo;
+
+//- /async/async.rs
+pub struct Baz;
 "#,
         expect![[r#"
             crate
@@ -136,6 +144,14 @@ fn module_resolution_works_for_raw_modules() {
 
             crate::r#async
             Bar: t v
+            foo: t
+            r#async: t
+
+            crate::r#async::foo
+            Foo: t v
+
+            crate::r#async::r#async
+            Baz: t v
         "#]],
     );
 }
index 3163fa0f93fa573c0e2215f2ccaf5f1627340b38..8aa5973cac57baae18937f13d92a45f2d83242f2 100644 (file)
@@ -31,12 +31,10 @@ pub struct Resolver {
     ///
     /// When using, you generally want to process the scopes in reverse order,
     /// there's `scopes` *method* for that.
-    ///
-    /// Invariant: There exists at least one Scope::ModuleScope at the start of the vec.
     scopes: Vec<Scope>,
+    module_scope: ModuleItemMap,
 }
 
-// FIXME how to store these best
 #[derive(Debug, Clone)]
 struct ModuleItemMap {
     def_map: Arc<DefMap>,
@@ -53,7 +51,7 @@ struct ExprScope {
 #[derive(Debug, Clone)]
 enum Scope {
     /// All the items and imported names of a module
-    ModuleScope(ModuleItemMap),
+    BlockScope(ModuleItemMap),
     /// Brings the generic parameters of an item into scope
     GenericParams { def: GenericDefId, params: Interned<GenericParams> },
     /// Brings `Self` in `impl` block into scope
@@ -127,24 +125,6 @@ pub fn resolve_known_enum(&self, db: &dyn DefDatabase, path: &ModPath) -> Option
         }
     }
 
-    fn scopes(&self) -> impl Iterator<Item = &Scope> {
-        self.scopes.iter().rev()
-    }
-
-    fn resolve_module_path(
-        &self,
-        db: &dyn DefDatabase,
-        path: &ModPath,
-        shadow: BuiltinShadowMode,
-    ) -> PerNs {
-        let (item_map, module) = self.module_scope();
-        let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
-        if segment_index.is_some() {
-            return PerNs::none();
-        }
-        module_res
-    }
-
     pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNs {
         self.resolve_module_path(db, path, BuiltinShadowMode::Module)
     }
@@ -155,7 +135,7 @@ pub fn resolve_module_path_in_trait_assoc_items(
         db: &dyn DefDatabase,
         path: &ModPath,
     ) -> Option<PerNs> {
-        let (item_map, module) = self.module_scope();
+        let (item_map, module) = self.item_scope();
         let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module);
         match module_res.take_types()? {
             ModuleDefId::TraitId(it) => {
@@ -183,37 +163,38 @@ pub fn resolve_path_in_type_ns(
     ) -> Option<(TypeNs, Option<usize>)> {
         let first_name = path.segments().first()?;
         let skip_to_mod = path.kind != PathKind::Plain;
+        if skip_to_mod {
+            return self.module_scope.resolve_path_in_type_ns(db, path);
+        }
+
+        let remaining_idx = || if path.segments().len() == 1 { None } else { Some(1) };
+
         for scope in self.scopes() {
             match scope {
                 Scope::ExprScope(_) => continue,
-                Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue,
-
                 Scope::GenericParams { params, def } => {
                     if let Some(id) = params.find_type_by_name(first_name, *def) {
-                        let idx = if path.segments().len() == 1 { None } else { Some(1) };
-                        return Some((TypeNs::GenericParam(id), idx));
+                        return Some((TypeNs::GenericParam(id), remaining_idx()));
                     }
                 }
-                Scope::ImplDefScope(impl_) => {
+                &Scope::ImplDefScope(impl_) => {
                     if first_name == &name![Self] {
-                        let idx = if path.segments().len() == 1 { None } else { Some(1) };
-                        return Some((TypeNs::SelfType(*impl_), idx));
+                        return Some((TypeNs::SelfType(impl_), remaining_idx()));
                     }
                 }
-                Scope::AdtScope(adt) => {
+                &Scope::AdtScope(adt) => {
                     if first_name == &name![Self] {
-                        let idx = if path.segments().len() == 1 { None } else { Some(1) };
-                        return Some((TypeNs::AdtSelfType(*adt), idx));
+                        return Some((TypeNs::AdtSelfType(adt), remaining_idx()));
                     }
                 }
-                Scope::ModuleScope(m) => {
+                Scope::BlockScope(m) => {
                     if let Some(res) = m.resolve_path_in_type_ns(db, path) {
                         return Some(res);
                     }
                 }
             }
         }
-        None
+        self.module_scope.resolve_path_in_type_ns(db, path)
     }
 
     pub fn resolve_path_in_type_ns_fully(
@@ -235,7 +216,7 @@ pub fn resolve_visibility(
     ) -> Option<Visibility> {
         match visibility {
             RawVisibility::Module(_) => {
-                let (item_map, module) = self.module_scope();
+                let (item_map, module) = self.item_scope();
                 item_map.resolve_visibility(db, module, visibility)
             }
             RawVisibility::Public => Some(Visibility::Public),
@@ -251,18 +232,14 @@ pub fn resolve_path_in_value_ns(
         let tmp = name![self];
         let first_name = if path.is_self() { &tmp } else { path.segments().first()? };
         let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
+        if skip_to_mod {
+            return self.module_scope.resolve_path_in_value_ns(db, path);
+        }
+
         for scope in self.scopes() {
             match scope {
-                Scope::AdtScope(_)
-                | Scope::ExprScope(_)
-                | Scope::GenericParams { .. }
-                | Scope::ImplDefScope(_)
-                    if skip_to_mod =>
-                {
-                    continue
-                }
-
-                Scope::ExprScope(scope) if n_segments <= 1 => {
+                Scope::ExprScope(_) if n_segments > 1 => continue,
+                Scope::ExprScope(scope) => {
                     let entry = scope
                         .expr_scopes
                         .entries(scope.scope_id)
@@ -273,44 +250,39 @@ pub fn resolve_path_in_value_ns(
                         return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat())));
                     }
                 }
-                Scope::ExprScope(_) => continue,
-
                 Scope::GenericParams { params, def } if n_segments > 1 => {
                     if let Some(id) = params.find_type_by_name(first_name, *def) {
                         let ty = TypeNs::GenericParam(id);
                         return Some(ResolveValueResult::Partial(ty, 1));
                     }
                 }
-                Scope::GenericParams { params, def } if n_segments == 1 => {
+                Scope::GenericParams { .. } if n_segments != 1 => continue,
+                Scope::GenericParams { params, def } => {
                     if let Some(id) = params.find_const_by_name(first_name, *def) {
                         let val = ValueNs::GenericParam(id);
                         return Some(ResolveValueResult::ValueNs(val));
                     }
                 }
-                Scope::GenericParams { .. } => continue,
 
-                Scope::ImplDefScope(impl_) => {
+                &Scope::ImplDefScope(impl_) => {
                     if first_name == &name![Self] {
-                        if n_segments > 1 {
-                            let ty = TypeNs::SelfType(*impl_);
-                            return Some(ResolveValueResult::Partial(ty, 1));
+                        return Some(if n_segments > 1 {
+                            ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1)
                         } else {
-                            return Some(ResolveValueResult::ValueNs(ValueNs::ImplSelf(*impl_)));
-                        }
+                            ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_))
+                        });
                     }
                 }
+                // bare `Self` doesn't work in the value namespace in a struct/enum definition
+                Scope::AdtScope(_) if n_segments == 1 => continue,
                 Scope::AdtScope(adt) => {
-                    if n_segments == 1 {
-                        // bare `Self` doesn't work in the value namespace in a struct/enum definition
-                        continue;
-                    }
                     if first_name == &name![Self] {
                         let ty = TypeNs::AdtSelfType(*adt);
                         return Some(ResolveValueResult::Partial(ty, 1));
                     }
                 }
 
-                Scope::ModuleScope(m) => {
+                Scope::BlockScope(m) => {
                     if let Some(def) = m.resolve_path_in_value_ns(db, path) {
                         return Some(def);
                     }
@@ -318,15 +290,16 @@ pub fn resolve_path_in_value_ns(
             }
         }
 
+        if let res @ Some(_) = self.module_scope.resolve_path_in_value_ns(db, path) {
+            return res;
+        }
+
         // If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back
         // to resolving to the primitive type, to allow this to still work in the presence of
         // `use core::u16;`.
         if path.kind == PathKind::Plain && path.segments().len() > 1 {
-            match BuiltinType::by_name(&path.segments()[0]) {
-                Some(builtin) => {
-                    return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
-                }
-                None => {}
+            if let Some(builtin) = BuiltinType::by_name(&path.segments()[0]) {
+                return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
             }
         }
 
@@ -345,7 +318,7 @@ pub fn resolve_path_in_value_ns_fully(
     }
 
     pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
-        let (item_map, module) = self.module_scope();
+        let (item_map, module) = self.item_scope();
         item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
     }
 
@@ -395,30 +368,43 @@ pub fn names_in_scope(
         for scope in self.scopes() {
             scope.process_names(&mut res, db);
         }
+        let ModuleItemMap { ref def_map, module_id } = self.module_scope;
+        // FIXME: should we provide `self` here?
+        // f(
+        //     Name::self_param(),
+        //     PerNs::types(Resolution::Def {
+        //         def: m.module.into(),
+        //     }),
+        // );
+        def_map[module_id].scope.entries().for_each(|(name, def)| {
+            res.add_per_ns(name, def);
+        });
+        def_map[module_id].scope.legacy_macros().for_each(|(name, macs)| {
+            macs.iter().for_each(|&mac| {
+                res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))));
+            })
+        });
+        def_map.extern_prelude().for_each(|(name, &def)| {
+            res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
+        });
+        BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
+            res.add_per_ns(name, def);
+        });
+        if let Some(prelude) = def_map.prelude() {
+            let prelude_def_map = prelude.def_map(db);
+            for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
+                res.add_per_ns(name, def)
+            }
+        }
         res.map
     }
 
     pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> {
         let mut traits = FxHashSet::default();
+
         for scope in self.scopes() {
             match scope {
-                Scope::ModuleScope(m) => {
-                    if let Some(prelude) = m.def_map.prelude() {
-                        let prelude_def_map = prelude.def_map(db);
-                        traits.extend(prelude_def_map[prelude.local_id].scope.traits());
-                    }
-                    traits.extend(m.def_map[m.module_id].scope.traits());
-
-                    // Add all traits that are in scope because of the containing DefMaps
-                    m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| {
-                        if let Some(prelude) = def_map.prelude() {
-                            let prelude_def_map = prelude.def_map(db);
-                            traits.extend(prelude_def_map[prelude.local_id].scope.traits());
-                        }
-                        traits.extend(def_map[module].scope.traits());
-                        None::<()>
-                    });
-                }
+                Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()),
                 &Scope::ImplDefScope(impl_) => {
                     if let Some(target_trait) = &db.impl_data(impl_).target_trait {
                         if let Some(TypeNs::TraitId(trait_)) =
@@ -431,35 +417,28 @@ pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> {
                 _ => (),
             }
         }
-        traits
-    }
 
-    fn module_scope(&self) -> (&DefMap, LocalModuleId) {
-        self.scopes()
-            .find_map(|scope| match scope {
-                Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)),
-                _ => None,
-            })
-            .expect("module scope invariant violated")
+        // Fill in the prelude traits
+        if let Some(prelude) = self.module_scope.def_map.prelude() {
+            let prelude_def_map = prelude.def_map(db);
+            traits.extend(prelude_def_map[prelude.local_id].scope.traits());
+        }
+        // Fill in module visible traits
+        traits.extend(self.module_scope.def_map[self.module_scope.module_id].scope.traits());
+        traits
     }
 
     pub fn module(&self) -> ModuleId {
-        let (def_map, local_id) = self.module_scope();
+        let (def_map, local_id) = self.item_scope();
         def_map.module_id(local_id)
     }
 
     pub fn krate(&self) -> CrateId {
-        self.def_map().krate()
+        self.module_scope.def_map.krate()
     }
 
     pub fn def_map(&self) -> &DefMap {
-        self.scopes
-            .get(0)
-            .and_then(|scope| match scope {
-                Scope::ModuleScope(m) => Some(&m.def_map),
-                _ => None,
-            })
-            .expect("module scope invariant violated")
+        self.item_scope().0
     }
 
     pub fn where_predicates_in_scope(
@@ -488,6 +467,36 @@ pub fn body_owner(&self) -> Option<DefWithBodyId> {
     }
 }
 
+impl Resolver {
+    fn scopes(&self) -> impl Iterator<Item = &Scope> {
+        self.scopes.iter().rev()
+    }
+
+    fn resolve_module_path(
+        &self,
+        db: &dyn DefDatabase,
+        path: &ModPath,
+        shadow: BuiltinShadowMode,
+    ) -> PerNs {
+        let (item_map, module) = self.item_scope();
+        let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
+        if segment_index.is_some() {
+            return PerNs::none();
+        }
+        module_res
+    }
+
+    /// The innermost block scope that contains items or the module scope that contains this resolver.
+    fn item_scope(&self) -> (&DefMap, LocalModuleId) {
+        self.scopes()
+            .find_map(|scope| match scope {
+                Scope::BlockScope(m) => Some((&*m.def_map, m.module_id)),
+                _ => None,
+            })
+            .unwrap_or((&self.module_scope.def_map, self.module_scope.module_id))
+    }
+}
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum ScopeDef {
     ModuleDef(ModuleDefId),
@@ -502,14 +511,7 @@ pub enum ScopeDef {
 impl Scope {
     fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
         match self {
-            Scope::ModuleScope(m) => {
-                // FIXME: should we provide `self` here?
-                // f(
-                //     Name::self_param(),
-                //     PerNs::types(Resolution::Def {
-                //         def: m.module.into(),
-                //     }),
-                // );
+            Scope::BlockScope(m) => {
                 m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
                     acc.add_per_ns(name, def);
                 });
@@ -521,18 +523,6 @@ fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
                         );
                     })
                 });
-                m.def_map.extern_prelude().for_each(|(name, &def)| {
-                    acc.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
-                });
-                BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
-                    acc.add_per_ns(name, def);
-                });
-                if let Some(prelude) = m.def_map.prelude() {
-                    let prelude_def_map = prelude.def_map(db);
-                    for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
-                        acc.add_per_ns(name, def)
-                    }
-                }
             }
             Scope::GenericParams { params, def: parent } => {
                 let parent = *parent;
@@ -596,7 +586,7 @@ pub fn resolver_for_scope(
         if let Some(block) = scopes.block(scope) {
             if let Some(def_map) = db.block_def_map(block) {
                 let root = def_map.root();
-                r = r.push_module_scope(def_map, root);
+                r = r.push_block_scope(def_map, root);
                 // FIXME: This adds as many module scopes as there are blocks, but resolving in each
                 // already traverses all parents, so this is O(n²). I think we could only store the
                 // innermost module scope instead?
@@ -623,8 +613,8 @@ fn push_impl_def_scope(self, impl_def: ImplId) -> Resolver {
         self.push_scope(Scope::ImplDefScope(impl_def))
     }
 
-    fn push_module_scope(self, def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
-        self.push_scope(Scope::ModuleScope(ModuleItemMap { def_map, module_id }))
+    fn push_block_scope(self, def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
+        self.push_scope(Scope::BlockScope(ModuleItemMap { def_map, module_id }))
     }
 
     fn push_expr_scope(
@@ -768,14 +758,19 @@ pub trait HasResolver: Copy {
 impl HasResolver for ModuleId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         let mut def_map = self.def_map(db);
-        let mut modules: SmallVec<[_; 2]> = smallvec![(def_map.clone(), self.local_id)];
+        let mut modules: SmallVec<[_; 1]> = smallvec![];
+        let mut module_id = self.local_id;
         while let Some(parent) = def_map.parent() {
+            modules.push((def_map, module_id));
             def_map = parent.def_map(db);
-            modules.push((def_map.clone(), parent.local_id));
+            module_id = parent.local_id;
         }
-        let mut resolver = Resolver { scopes: Vec::with_capacity(modules.len()) };
+        let mut resolver = Resolver {
+            scopes: Vec::with_capacity(modules.len()),
+            module_scope: ModuleItemMap { def_map, module_id },
+        };
         for (def_map, module) in modules.into_iter().rev() {
-            resolver = resolver.push_module_scope(def_map, module);
+            resolver = resolver.push_block_scope(def_map, module);
         }
         resolver
     }
index d753d88470c442cb3c372494c2fc38720eb91573..fc128102f225a18cc066193e649e843dd2147906 100644 (file)
@@ -969,7 +969,7 @@ pub fn from_call_site(call: &ast::MacroCall) -> ExpandTo {
         if parent.kind() == MACRO_EXPR
             && parent
                 .parent()
-                .map_or(true, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS))
+                .map_or(false, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS))
         {
             return ExpandTo::Statements;
         }
index 2b859f775095beb0e005fb1657e59d001e933408..4ce21a57967c72048f59b5db4517c544d075b528 100644 (file)
@@ -336,6 +336,7 @@ macro_rules! known_names {
         test,
         test_case,
         recursion_limit,
+        feature,
         // Safe intrinsics
         abort,
         add_with_overflow,
index b6f226dbfd20d238ff19338a20d07eab5a3b7008..344036dd8139d28d433c745b6121ab8c85e9865f 100644 (file)
@@ -104,8 +104,7 @@ pub(crate) fn deref(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
 
 fn builtin_deref(ty: &Ty) -> Option<&Ty> {
     match ty.kind(Interner) {
-        TyKind::Ref(.., ty) => Some(ty),
-        TyKind::Raw(.., ty) => Some(ty),
+        TyKind::Ref(.., ty) | TyKind::Raw(.., ty) => Some(ty),
         _ => None,
     }
 }
index 642e03edd230636ca3911a0e0eee44dc8989a41e..c8df4c796efca045f974d21e3b21a8a67e23bf28 100644 (file)
@@ -159,12 +159,7 @@ fn validate_match(
         }
 
         let pattern_arena = Arena::new();
-        let cx = MatchCheckCtx {
-            module: self.owner.module(db.upcast()),
-            body: self.owner,
-            db,
-            pattern_arena: &pattern_arena,
-        };
+        let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db, &pattern_arena);
 
         let mut m_arms = Vec::with_capacity(arms.len());
         let mut has_lowering_errors = false;
index bbbe539c13fbe2c94b1bb05c5c5ed3e9928398da..47d60fc41e700bc2962665e48ab04f6720b3884d 100644 (file)
 use smallvec::{smallvec, SmallVec};
 use stdx::never;
 
-use crate::{infer::normalize, AdtId, Interner, Scalar, Ty, TyExt, TyKind};
+use crate::{
+    infer::normalize, inhabitedness::is_enum_variant_uninhabited_from, AdtId, Interner, Scalar, Ty,
+    TyExt, TyKind,
+};
 
 use super::{
     is_box,
@@ -557,8 +560,8 @@ pub(super) fn new(pcx: PatCtxt<'_, '_>) -> Self {
             TyKind::Scalar(Scalar::Bool) => smallvec![make_range(0, 1, Scalar::Bool)],
             // TyKind::Array(..) if ... => unhandled(),
             TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
-            &TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => {
-                let enum_data = cx.db.enum_data(enum_id);
+            TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), subst) => {
+                let enum_data = cx.db.enum_data(*enum_id);
 
                 // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
                 // additional "unknown" constructor.
@@ -591,14 +594,15 @@ pub(super) fn new(pcx: PatCtxt<'_, '_>) -> Self {
                 let mut ctors: SmallVec<[_; 1]> = enum_data
                     .variants
                     .iter()
-                    .filter(|&(_, _v)| {
+                    .map(|(local_id, _)| EnumVariantId { parent: *enum_id, local_id })
+                    .filter(|&variant| {
                         // If `exhaustive_patterns` is enabled, we exclude variants known to be
                         // uninhabited.
                         let is_uninhabited = is_exhaustive_pat_feature
-                            && unimplemented!("after MatchCheckCtx.feature_exhaustive_patterns()");
+                            && is_enum_variant_uninhabited_from(variant, subst, cx.module, cx.db);
                         !is_uninhabited
                     })
-                    .map(|(local_id, _)| Variant(EnumVariantId { parent: enum_id, local_id }))
+                    .map(Variant)
                     .collect();
 
                 if is_secretly_empty || is_declared_nonexhaustive {
index 1221327b9510a9791984da46e12ab43d5ee142b9..c4d709a975b0299a7a0a0374b83d9e12824a8236 100644 (file)
 use smallvec::{smallvec, SmallVec};
 use typed_arena::Arena;
 
-use crate::{db::HirDatabase, Ty, TyExt};
+use crate::{db::HirDatabase, inhabitedness::is_ty_uninhabited_from, Ty, TyExt};
 
 use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard};
 
@@ -289,13 +289,27 @@ pub(crate) struct MatchCheckCtx<'a, 'p> {
     pub(crate) db: &'a dyn HirDatabase,
     /// Lowered patterns from arms plus generated by the check.
     pub(crate) pattern_arena: &'p Arena<DeconstructedPat<'p>>,
+    exhaustive_patterns: bool,
 }
 
 impl<'a, 'p> MatchCheckCtx<'a, 'p> {
-    pub(super) fn is_uninhabited(&self, _ty: &Ty) -> bool {
-        // FIXME(iDawer) implement exhaustive_patterns feature. More info in:
-        // Tracking issue for RFC 1872: exhaustive_patterns feature https://github.com/rust-lang/rust/issues/51085
-        false
+    pub(crate) fn new(
+        module: ModuleId,
+        body: DefWithBodyId,
+        db: &'a dyn HirDatabase,
+        pattern_arena: &'p Arena<DeconstructedPat<'p>>,
+    ) -> Self {
+        let def_map = db.crate_def_map(module.krate());
+        let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns");
+        Self { module, body, db, pattern_arena, exhaustive_patterns }
+    }
+
+    pub(super) fn is_uninhabited(&self, ty: &Ty) -> bool {
+        if self.feature_exhaustive_patterns() {
+            is_ty_uninhabited_from(ty, self.module, self.db)
+        } else {
+            false
+        }
     }
 
     /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
@@ -311,10 +325,9 @@ pub(super) fn is_foreign_non_exhaustive_enum(&self, ty: &Ty) -> bool {
         }
     }
 
-    // Rust feature described as "Allows exhaustive pattern matching on types that contain uninhabited types."
+    // Rust's unstable feature described as "Allows exhaustive pattern matching on types that contain uninhabited types."
     pub(super) fn feature_exhaustive_patterns(&self) -> bool {
-        // FIXME see MatchCheckCtx::is_uninhabited
-        false
+        self.exhaustive_patterns
     }
 }
 
index 5df48e5fdcbaf40502d0aa11f3b9bd666132b771..10ffde87eef1491b4c6777db2c19309ff6f36f4e 100644 (file)
@@ -182,7 +182,7 @@ fn map<U>(self, f: impl FnOnce(T) -> U) -> InferOk<U> {
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum InferenceDiagnostic {
     NoSuchField { expr: ExprId },
-    BreakOutsideOfLoop { expr: ExprId },
+    BreakOutsideOfLoop { expr: ExprId, is_break: bool },
     MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
 }
 
@@ -418,18 +418,45 @@ pub(crate) struct InferenceContext<'a> {
 
 #[derive(Clone, Debug)]
 struct BreakableContext {
+    /// Whether this context contains at least one break expression.
     may_break: bool,
+    /// The coercion target of the context.
     coerce: CoerceMany,
+    /// The optional label of the context.
     label: Option<name::Name>,
+    kind: BreakableKind,
+}
+
+#[derive(Clone, Debug)]
+enum BreakableKind {
+    Block,
+    Loop,
+    /// A border is something like an async block, closure etc. Anything that prevents
+    /// breaking/continuing through
+    Border,
 }
 
 fn find_breakable<'c>(
     ctxs: &'c mut [BreakableContext],
     label: Option<&name::Name>,
+) -> Option<&'c mut BreakableContext> {
+    let mut ctxs = ctxs
+        .iter_mut()
+        .rev()
+        .take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop));
+    match label {
+        Some(_) => ctxs.find(|ctx| ctx.label.as_ref() == label),
+        None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)),
+    }
+}
+
+fn find_continuable<'c>(
+    ctxs: &'c mut [BreakableContext],
+    label: Option<&name::Name>,
 ) -> Option<&'c mut BreakableContext> {
     match label {
-        Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label),
-        None => ctxs.last_mut(),
+        Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)),
+        None => find_breakable(ctxs, label),
     }
 }
 
index 2a13106390d9f7f90773d1377bdc8b24351ca393..2d04a864a2cfd98455a5d198edaec33cc8303f0b 100644 (file)
@@ -10,7 +10,7 @@
     cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
 };
 use hir_def::{
-    expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Statement, UnaryOp},
+    expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp},
     generics::TypeOrConstParamData,
     path::{GenericArg, GenericArgs},
     resolver::resolver_for_expr,
@@ -23,7 +23,7 @@
 use crate::{
     autoderef::{self, Autoderef},
     consteval,
-    infer::coerce::CoerceMany,
+    infer::{coerce::CoerceMany, find_continuable, BreakableKind},
     lower::{
         const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
     },
@@ -120,32 +120,37 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
                 let ty = match label {
                     Some(_) => {
                         let break_ty = self.table.new_type_var();
-                        self.breakables.push(BreakableContext {
-                            may_break: false,
-                            coerce: CoerceMany::new(break_ty.clone()),
-                            label: label.map(|label| self.body[label].name.clone()),
-                        });
-                        let ty = self.infer_block(
-                            tgt_expr,
-                            statements,
-                            *tail,
-                            &Expectation::has_type(break_ty),
+                        let (breaks, ty) = self.with_breakable_ctx(
+                            BreakableKind::Block,
+                            break_ty.clone(),
+                            *label,
+                            |this| {
+                                this.infer_block(
+                                    tgt_expr,
+                                    statements,
+                                    *tail,
+                                    &Expectation::has_type(break_ty),
+                                )
+                            },
                         );
-                        let ctxt = self.breakables.pop().expect("breakable stack broken");
-                        if ctxt.may_break {
-                            ctxt.coerce.complete()
-                        } else {
-                            ty
-                        }
+                        breaks.unwrap_or(ty)
                     }
                     None => self.infer_block(tgt_expr, statements, *tail, expected),
                 };
                 self.resolver = old_resolver;
                 ty
             }
-            Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected),
+            Expr::Unsafe { body } => self.infer_expr(*body, expected),
+            Expr::Const { body } => {
+                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
+                    this.infer_expr(*body, expected)
+                })
+                .1
+            }
             Expr::TryBlock { body } => {
-                let _inner = self.infer_expr(*body, expected);
+                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
+                    let _inner = this.infer_expr(*body, expected);
+                });
                 // FIXME should be std::result::Result<{inner}, _>
                 self.err_ty()
             }
@@ -154,7 +159,10 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
                 let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
                 let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
 
-                let inner_ty = self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
+                let (_, inner_ty) =
+                    self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
+                        this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty))
+                    });
 
                 self.diverges = prev_diverges;
                 self.return_ty = prev_ret_ty;
@@ -166,54 +174,44 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
                 TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty))
                     .intern(Interner)
             }
-            Expr::Loop { body, label } => {
-                self.breakables.push(BreakableContext {
-                    may_break: false,
-                    coerce: CoerceMany::new(self.table.new_type_var()),
-                    label: label.map(|label| self.body[label].name.clone()),
-                });
-                self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
-
-                let ctxt = self.breakables.pop().expect("breakable stack broken");
+            &Expr::Loop { body, label } => {
+                let ty = self.table.new_type_var();
+                let (breaks, ()) =
+                    self.with_breakable_ctx(BreakableKind::Loop, ty, label, |this| {
+                        this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+                    });
 
-                if ctxt.may_break {
-                    self.diverges = Diverges::Maybe;
-                    ctxt.coerce.complete()
-                } else {
-                    TyKind::Never.intern(Interner)
+                match breaks {
+                    Some(breaks) => {
+                        self.diverges = Diverges::Maybe;
+                        breaks
+                    }
+                    None => TyKind::Never.intern(Interner),
                 }
             }
-            Expr::While { condition, body, label } => {
-                self.breakables.push(BreakableContext {
-                    may_break: false,
-                    coerce: CoerceMany::new(self.err_ty()),
-                    label: label.map(|label| self.body[label].name.clone()),
+            &Expr::While { condition, body, label } => {
+                self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
+                    this.infer_expr(
+                        condition,
+                        &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
+                    );
+                    this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
                 });
-                self.infer_expr(
-                    *condition,
-                    &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
-                );
-                self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
-                let _ctxt = self.breakables.pop().expect("breakable stack broken");
+
                 // the body may not run, so it diverging doesn't mean we diverge
                 self.diverges = Diverges::Maybe;
                 TyBuilder::unit()
             }
-            Expr::For { iterable, body, pat, label } => {
-                let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
-
-                self.breakables.push(BreakableContext {
-                    may_break: false,
-                    coerce: CoerceMany::new(self.err_ty()),
-                    label: label.map(|label| self.body[label].name.clone()),
-                });
+            &Expr::For { iterable, body, pat, label } => {
+                let iterable_ty = self.infer_expr(iterable, &Expectation::none());
                 let pat_ty =
                     self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
 
-                self.infer_pat(*pat, &pat_ty, BindingMode::default());
+                self.infer_pat(pat, &pat_ty, BindingMode::default());
+                self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
+                    this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+                });
 
-                self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
-                let _ctxt = self.breakables.pop().expect("breakable stack broken");
                 // the body may not run, so it diverging doesn't mean we diverge
                 self.diverges = Diverges::Maybe;
                 TyBuilder::unit()
@@ -269,7 +267,9 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
                 let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
                 let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
 
-                self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
+                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
+                    this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
+                });
 
                 self.diverges = prev_diverges;
                 self.return_ty = prev_ret_ty;
@@ -372,37 +372,45 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
                 let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
                 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty())
             }
-            Expr::Continue { .. } => TyKind::Never.intern(Interner),
-            Expr::Break { expr, label } => {
-                let mut coerce = match find_breakable(&mut self.breakables, label.as_ref()) {
-                    Some(ctxt) => {
-                        // avoiding the borrowck
-                        mem::replace(
-                            &mut ctxt.coerce,
-                            CoerceMany::new(self.result.standard_types.unknown.clone()),
-                        )
-                    }
-                    None => CoerceMany::new(self.result.standard_types.unknown.clone()),
+            Expr::Continue { label } => {
+                if let None = find_continuable(&mut self.breakables, label.as_ref()) {
+                    self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
+                        expr: tgt_expr,
+                        is_break: false,
+                    });
                 };
-
+                TyKind::Never.intern(Interner)
+            }
+            Expr::Break { expr, label } => {
                 let val_ty = if let Some(expr) = *expr {
                     self.infer_expr(expr, &Expectation::none())
                 } else {
                     TyBuilder::unit()
                 };
 
-                // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
-                coerce.coerce(self, *expr, &val_ty);
+                match find_breakable(&mut self.breakables, label.as_ref()) {
+                    Some(ctxt) => {
+                        // avoiding the borrowck
+                        let mut coerce = mem::replace(
+                            &mut ctxt.coerce,
+                            CoerceMany::new(self.result.standard_types.unknown.clone()),
+                        );
 
-                if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
-                    ctxt.coerce = coerce;
-                    ctxt.may_break = true;
-                } else {
-                    self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
-                        expr: tgt_expr,
-                    });
-                };
+                        // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
+                        coerce.coerce(self, *expr, &val_ty);
 
+                        let ctxt = find_breakable(&mut self.breakables, label.as_ref())
+                            .expect("breakable stack changed during coercion");
+                        ctxt.coerce = coerce;
+                        ctxt.may_break = true;
+                    }
+                    None => {
+                        self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
+                            expr: tgt_expr,
+                            is_break: true,
+                        });
+                    }
+                }
                 TyKind::Never.intern(Interner)
             }
             Expr::Return { expr } => {
@@ -794,9 +802,6 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
                     None => self.table.new_float_var(),
                 },
             },
-            Expr::MacroStmts { tail, statements } => {
-                self.infer_block(tgt_expr, statements, *tail, expected)
-            }
             Expr::Underscore => {
                 // Underscore expressions may only appear in assignee expressions,
                 // which are handled by `infer_assignee_expr()`, so any underscore
@@ -1475,4 +1480,20 @@ fn builtin_binary_op_rhs_expectation(&mut self, op: BinaryOp, lhs_ty: Ty) -> Opt
             },
         })
     }
+
+    fn with_breakable_ctx<T>(
+        &mut self,
+        kind: BreakableKind,
+        ty: Ty,
+        label: Option<LabelId>,
+        cb: impl FnOnce(&mut Self) -> T,
+    ) -> (Option<Ty>, T) {
+        self.breakables.push({
+            let label = label.map(|label| self.body[label].name.clone());
+            BreakableContext { kind, may_break: false, coerce: CoerceMany::new(ty), label }
+        });
+        let res = cb(self);
+        let ctx = self.breakables.pop().expect("breakable stack broken");
+        (ctx.may_break.then(|| ctx.coerce.complete()), res)
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
new file mode 100644 (file)
index 0000000..0c54719
--- /dev/null
@@ -0,0 +1,173 @@
+//! Type inhabitedness logic.
+use std::ops::ControlFlow::{self, Break, Continue};
+
+use chalk_ir::{
+    visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
+    DebruijnIndex,
+};
+use hir_def::{
+    adt::VariantData, attr::Attrs, type_ref::ConstScalar, visibility::Visibility, AdtId,
+    EnumVariantId, HasModule, Lookup, ModuleId, VariantId,
+};
+
+use crate::{
+    db::HirDatabase, Binders, ConcreteConst, Const, ConstValue, Interner, Substitution, Ty, TyKind,
+};
+
+/// Checks whether a type is visibly uninhabited from a particular module.
+pub(crate) fn is_ty_uninhabited_from(ty: &Ty, target_mod: ModuleId, db: &dyn HirDatabase) -> bool {
+    let mut uninhabited_from = UninhabitedFrom { target_mod, db };
+    let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
+    inhabitedness == BREAK_VISIBLY_UNINHABITED
+}
+
+/// Checks whether a variant is visibly uninhabited from a particular module.
+pub(crate) fn is_enum_variant_uninhabited_from(
+    variant: EnumVariantId,
+    subst: &Substitution,
+    target_mod: ModuleId,
+    db: &dyn HirDatabase,
+) -> bool {
+    let enum_data = db.enum_data(variant.parent);
+    let vars_attrs = db.variants_attrs(variant.parent);
+    let is_local = variant.parent.lookup(db.upcast()).container.krate() == target_mod.krate();
+
+    let mut uninhabited_from = UninhabitedFrom { target_mod, db };
+    let inhabitedness = uninhabited_from.visit_variant(
+        variant.into(),
+        &enum_data.variants[variant.local_id].variant_data,
+        subst,
+        &vars_attrs[variant.local_id],
+        is_local,
+    );
+    inhabitedness == BREAK_VISIBLY_UNINHABITED
+}
+
+struct UninhabitedFrom<'a> {
+    target_mod: ModuleId,
+    db: &'a dyn HirDatabase,
+}
+
+const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(());
+const BREAK_VISIBLY_UNINHABITED: ControlFlow<VisiblyUninhabited> = Break(VisiblyUninhabited);
+#[derive(PartialEq, Eq)]
+struct VisiblyUninhabited;
+
+impl TypeVisitor<Interner> for UninhabitedFrom<'_> {
+    type BreakTy = VisiblyUninhabited;
+
+    fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = VisiblyUninhabited> {
+        self
+    }
+
+    fn visit_ty(
+        &mut self,
+        ty: &Ty,
+        outer_binder: DebruijnIndex,
+    ) -> ControlFlow<VisiblyUninhabited> {
+        match ty.kind(Interner) {
+            TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst),
+            TyKind::Never => BREAK_VISIBLY_UNINHABITED,
+            TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder),
+            TyKind::Array(item_ty, len) => match try_usize_const(len) {
+                Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
+                Some(1..) => item_ty.super_visit_with(self, outer_binder),
+            },
+
+            TyKind::Ref(..) | _ => CONTINUE_OPAQUELY_INHABITED,
+        }
+    }
+
+    fn interner(&self) -> Interner {
+        Interner
+    }
+}
+
+impl UninhabitedFrom<'_> {
+    fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow<VisiblyUninhabited> {
+        let attrs = self.db.attrs(adt.into());
+        let adt_non_exhaustive = attrs.by_key("non_exhaustive").exists();
+        let is_local = adt.module(self.db.upcast()).krate() == self.target_mod.krate();
+        if adt_non_exhaustive && !is_local {
+            return CONTINUE_OPAQUELY_INHABITED;
+        }
+
+        // An ADT is uninhabited iff all its variants uninhabited.
+        match adt {
+            // rustc: For now, `union`s are never considered uninhabited.
+            AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
+            AdtId::StructId(s) => {
+                let struct_data = self.db.struct_data(s);
+                self.visit_variant(s.into(), &struct_data.variant_data, subst, &attrs, is_local)
+            }
+            AdtId::EnumId(e) => {
+                let vars_attrs = self.db.variants_attrs(e);
+                let enum_data = self.db.enum_data(e);
+
+                for (local_id, enum_var) in enum_data.variants.iter() {
+                    let variant_inhabitedness = self.visit_variant(
+                        EnumVariantId { parent: e, local_id }.into(),
+                        &enum_var.variant_data,
+                        subst,
+                        &vars_attrs[local_id],
+                        is_local,
+                    );
+                    match variant_inhabitedness {
+                        Break(VisiblyUninhabited) => continue,
+                        Continue(()) => return CONTINUE_OPAQUELY_INHABITED,
+                    }
+                }
+                BREAK_VISIBLY_UNINHABITED
+            }
+        }
+    }
+
+    fn visit_variant(
+        &mut self,
+        variant: VariantId,
+        variant_data: &VariantData,
+        subst: &Substitution,
+        attrs: &Attrs,
+        is_local: bool,
+    ) -> ControlFlow<VisiblyUninhabited> {
+        let non_exhaustive_field_list = attrs.by_key("non_exhaustive").exists();
+        if non_exhaustive_field_list && !is_local {
+            return CONTINUE_OPAQUELY_INHABITED;
+        }
+
+        let is_enum = matches!(variant, VariantId::EnumVariantId(..));
+        let field_tys = self.db.field_types(variant);
+        let field_vis = self.db.field_visibilities(variant);
+
+        for (fid, _) in variant_data.fields().iter() {
+            self.visit_field(field_vis[fid], &field_tys[fid], subst, is_enum)?;
+        }
+        CONTINUE_OPAQUELY_INHABITED
+    }
+
+    fn visit_field(
+        &mut self,
+        vis: Visibility,
+        ty: &Binders<Ty>,
+        subst: &Substitution,
+        is_enum: bool,
+    ) -> ControlFlow<VisiblyUninhabited> {
+        if is_enum || vis.is_visible_from(self.db.upcast(), self.target_mod) {
+            let ty = ty.clone().substitute(Interner, subst);
+            ty.visit_with(self, DebruijnIndex::INNERMOST)
+        } else {
+            CONTINUE_OPAQUELY_INHABITED
+        }
+    }
+}
+
+fn try_usize_const(c: &Const) -> Option<u128> {
+    let data = &c.data(Interner);
+    if data.ty.kind(Interner) != &TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)) {
+        return None;
+    }
+    match data.value {
+        ConstValue::Concrete(ConcreteConst { interned: ConstScalar::UInt(value) }) => Some(value),
+        _ => None,
+    }
+}
index 5a5d610e360ffba3d4318288faa1b4422987a929..a82a331d4b8750e99c5fb8f69b6b04cf8007e96e 100644 (file)
@@ -14,6 +14,7 @@ macro_rules! eprintln {
 mod chalk_ext;
 pub mod consteval;
 mod infer;
+mod inhabitedness;
 mod interner;
 mod lower;
 mod mapping;
index 3f6d0844e9c1f27afc10ece6dde6b3414c169937..4a37a7945330cc2a216a3eb6582ca7bbd0db0287 100644 (file)
@@ -1,8 +1,8 @@
 //! Methods for lowering the HIR to types. There are two main cases here:
 //!
 //!  - Lowering a type reference like `&usize` or `Option<foo::bar::Baz>` to a
-//!    type: The entry point for this is `Ty::from_hir`.
-//!  - Building the type for an item: This happens through the `type_for_def` query.
+//!    type: The entry point for this is `TyLoweringContext::lower_ty`.
+//!  - Building the type for an item: This happens through the `ty` query.
 //!
 //! This usually involves resolving names, collecting generic arguments etc.
 use std::{
@@ -47,7 +47,7 @@
     consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic},
     db::HirDatabase,
     make_binders,
-    mapping::ToChalk,
+    mapping::{from_chalk_trait_id, ToChalk},
     static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
     utils::Generics,
     utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics},
@@ -332,7 +332,10 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
             TypeRef::Macro(macro_call) => {
                 let (mut expander, recursion_start) = {
                     match RefMut::filter_map(self.expander.borrow_mut(), Option::as_mut) {
+                        // There already is an expander here, this means we are already recursing
                         Ok(expander) => (expander, false),
+                        // No expander was created yet, so we are at the start of the expansion recursion
+                        // and therefore have to create an expander.
                         Err(expander) => (
                             RefMut::map(expander, |it| {
                                 it.insert(Expander::new(
@@ -362,9 +365,14 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
                                 .exit(self.db.upcast(), mark);
                             Some(ty)
                         }
-                        _ => None,
+                        _ => {
+                            drop(expander);
+                            None
+                        }
                     }
                 };
+
+                // drop the expander, resetting it to pre-recursion state
                 if recursion_start {
                     *self.expander.borrow_mut() = None;
                 }
@@ -974,13 +982,44 @@ fn assoc_type_bindings_from_type_bound(
     fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
         let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
         let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-            QuantifiedWhereClauses::from_iter(
+            let bounds =
+                bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false));
+
+            let mut auto_traits = SmallVec::<[_; 8]>::new();
+            let mut regular_traits = SmallVec::<[_; 2]>::new();
+            let mut other_bounds = SmallVec::<[_; 8]>::new();
+            for bound in bounds {
+                if let Some(id) = bound.trait_id() {
+                    if ctx.db.trait_data(from_chalk_trait_id(id)).is_auto {
+                        auto_traits.push(bound);
+                    } else {
+                        regular_traits.push(bound);
+                    }
+                } else {
+                    other_bounds.push(bound);
+                }
+            }
+
+            if regular_traits.len() > 1 {
+                return None;
+            }
+
+            auto_traits.sort_unstable_by_key(|b| b.trait_id().unwrap());
+            auto_traits.dedup();
+
+            Some(QuantifiedWhereClauses::from_iter(
                 Interner,
-                bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
-            )
+                regular_traits.into_iter().chain(other_bounds).chain(auto_traits),
+            ))
         });
-        let bounds = crate::make_single_type_binders(bounds);
-        TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
+
+        if let Some(bounds) = bounds {
+            let bounds = crate::make_single_type_binders(bounds);
+            TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
+        } else {
+            // FIXME: report error (additional non-auto traits)
+            TyKind::Error.intern(Interner)
+        }
     }
 
     fn lower_impl_trait(
index a1ab6060e790c0cdb4a9a02ffcd33e7b66d2aa0e..b3adafaafd38de8ea411754aa963079da3f3a309 100644 (file)
@@ -193,8 +193,6 @@ fn spam() {
             !0..6 '1isize': isize
             !0..6 '1isize': isize
             !0..6 '1isize': isize
-            !0..6 '1isize': isize
-            !0..6 '1isize': isize
             39..442 '{     ...!(); }': ()
             73..94 'spam!(...am!())': {unknown}
             100..119 'for _ ...!() {}': ()
@@ -276,8 +274,6 @@ fn spam() {
             !0..6 '1isize': isize
             !0..6 '1isize': isize
             !0..6 '1isize': isize
-            !0..6 '1isize': isize
-            !0..6 '1isize': isize
             53..456 '{     ...!(); }': ()
             87..108 'spam!(...am!())': {unknown}
             114..133 'for _ ...!() {}': ()
@@ -312,7 +308,6 @@ fn foo() {
         }
         "#,
         expect![[r#"
-            !0..8 'leta=();': ()
             !3..4 'a': ()
             !5..7 '()': ()
             57..84 '{     ...); } }': ()
@@ -321,7 +316,7 @@ fn foo() {
 }
 
 #[test]
-fn recurisve_macro_expanded_in_stmts() {
+fn recursive_macro_expanded_in_stmts() {
     check_infer(
         r#"
         macro_rules! ng {
@@ -340,11 +335,6 @@ fn foo() {
         }
         "#,
         expect![[r#"
-            !0..7 'leta=3;': ()
-            !0..13 'ng!{[leta=3]}': ()
-            !0..13 'ng!{[leta=]3}': ()
-            !0..13 'ng!{[leta]=3}': ()
-            !0..13 'ng!{[let]a=3}': ()
             !3..4 'a': i32
             !5..6 '3': i32
             196..237 '{     ...= a; }': ()
@@ -369,8 +359,6 @@ fn foo() {
         "#,
         expect![[r#"
             !0..1 '1': i32
-            !0..7 'mac!($)': ()
-            !0..26 'macro_...>{1};}': ()
             107..143 '{     ...!(); }': ()
             129..130 'a': i32
         "#]],
index c7895db1afbf5e523a3e6c9a03f09df74cd0aa73..23e51a9c16a5600138e3e519e2ae952c4a68c95e 100644 (file)
@@ -573,7 +573,6 @@ fn main() {
         }
         "#,
         expect![[r#"
-            !0..16 'let_a=...t_b=1;': ()
             !3..5 '_a': i32
             !6..7 '1': i32
             !11..13 '_b': i32
@@ -1679,7 +1678,6 @@ fn main() {
 
 #[test]
 fn trailing_empty_macro() {
-    cov_mark::check!(empty_macro_in_trailing_position_is_removed);
     check_no_mismatches(
         r#"
 macro_rules! m2 {
index 5b08f552109efe4a533c134e15046079056636ad..4ea103e5d9ec3cf1bc5fc85e4ff0866b18388826 100644 (file)
@@ -2549,7 +2549,6 @@ impl B for Astruct {}
         expect![[r#"
             569..573 'self': Box<[T], A>
             602..634 '{     ...     }': Vec<T, A>
-            612..628 'unimpl...ted!()': Vec<T, A>
             648..761 '{     ...t]); }': ()
             658..661 'vec': Vec<i32, Global>
             664..679 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
@@ -3070,3 +3069,17 @@ fn main() {
         "#,
     );
 }
+
+#[test]
+fn nested_break() {
+    check_no_mismatches(
+        r#"
+fn func() {
+    let int = loop {
+        break 0;
+        break (break 0);
+    };
+}
+    "#,
+    );
+}
index 0f37970e2b38d7fe678e101b19873789b2fbdd7e..e67c27aa2db97fb4cff6fd19475fa448aa422cc9 100644 (file)
@@ -3833,3 +3833,95 @@ fn test() {
 "#,
     )
 }
+
+#[test]
+fn dyn_multiple_auto_traits_in_different_order() {
+    check_no_mismatches(
+        r#"
+auto trait Send {}
+auto trait Sync {}
+
+fn f(t: &(dyn Sync + Send)) {}
+fn g(t: &(dyn Send + Sync)) {
+    f(t);
+}
+        "#,
+    );
+
+    check_no_mismatches(
+        r#"
+auto trait Send {}
+auto trait Sync {}
+trait T {}
+
+fn f(t: &(dyn T + Send + Sync)) {}
+fn g(t: &(dyn Sync + T + Send)) {
+    f(t);
+}
+        "#,
+    );
+
+    check_infer_with_mismatches(
+        r#"
+auto trait Send {}
+auto trait Sync {}
+trait T1 {}
+trait T2 {}
+
+fn f(t: &(dyn T1 + T2 + Send + Sync)) {}
+fn g(t: &(dyn Sync + T2 + T1 + Send)) {
+    f(t);
+}
+        "#,
+        expect![[r#"
+            68..69 't': &{unknown}
+            101..103 '{}': ()
+            109..110 't': &{unknown}
+            142..155 '{     f(t); }': ()
+            148..149 'f': fn f(&{unknown})
+            148..152 'f(t)': ()
+            150..151 't': &{unknown}
+        "#]],
+    );
+
+    check_no_mismatches(
+        r#"
+auto trait Send {}
+auto trait Sync {}
+trait T {
+    type Proj: Send + Sync;
+}
+
+fn f(t: &(dyn T<Proj = ()>  + Send + Sync)) {}
+fn g(t: &(dyn Sync + T<Proj = ()> + Send)) {
+    f(t);
+}
+        "#,
+    );
+}
+
+#[test]
+fn dyn_duplicate_auto_trait() {
+    check_no_mismatches(
+        r#"
+auto trait Send {}
+
+fn f(t: &(dyn Send + Send)) {}
+fn g(t: &(dyn Send)) {
+    f(t);
+}
+        "#,
+    );
+
+    check_no_mismatches(
+        r#"
+auto trait Send {}
+trait T {}
+
+fn f(t: &(dyn T + Send + Send)) {}
+fn g(t: &(dyn T + Send)) {
+    f(t);
+}
+        "#,
+    );
+}
index 50374f4b3fe47ebdd8e6907c26430a013b185687..5edc16d8bce9060262914d14060b4bfd1cb3e6d2 100644 (file)
@@ -124,6 +124,7 @@ pub struct NoSuchField {
 #[derive(Debug)]
 pub struct BreakOutsideOfLoop {
     pub expr: InFile<AstPtr<ast::Expr>>,
+    pub is_break: bool,
 }
 
 #[derive(Debug)]
index 6dccf2ed20b8e8e6dc00534678e42e7a558de526..e4bb63a864719956e4b31b76e8994852f3b3ca55 100644 (file)
@@ -1216,11 +1216,11 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
                     let field = source_map.field_syntax(*expr);
                     acc.push(NoSuchField { field }.into())
                 }
-                hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
+                &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
                     let expr = source_map
-                        .expr_syntax(*expr)
+                        .expr_syntax(expr)
                         .expect("break outside of loop in synthetic syntax");
-                    acc.push(BreakOutsideOfLoop { expr }.into())
+                    acc.push(BreakOutsideOfLoop { expr, is_break }.into())
                 }
                 hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
                     match source_map.expr_syntax(*call_expr) {
index bd35af06e23eb0ccbbd29146b61ca99394db1bfa..342912b678a1db836de2a77eb92f674fbc7246cd 100644 (file)
@@ -140,11 +140,19 @@ fn expand_expr(
     ) -> Option<InFile<ast::Expr>> {
         let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
         let expanded = db.parse_or_expand(macro_file)?;
-
-        let res = match ast::MacroCall::cast(expanded.clone()) {
-            Some(call) => self.expand_expr(db, InFile::new(macro_file, call))?,
-            _ => InFile::new(macro_file, ast::Expr::cast(expanded)?),
+        let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) {
+            match stmts.expr()? {
+                ast::Expr::MacroExpr(mac) => {
+                    self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))?
+                }
+                expr => InFile::new(macro_file, expr),
+            }
+        } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) {
+            self.expand_expr(db, InFile::new(macro_file, call))?
+        } else {
+            InFile::new(macro_file, ast::Expr::cast(expanded)?)
         };
+
         Some(res)
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs
new file mode 100644 (file)
index 0000000..54a7f48
--- /dev/null
@@ -0,0 +1,294 @@
+use syntax::ast::{self, AstNode};
+
+use crate::{AssistContext, AssistId, AssistKind, Assists};
+
+// Assist: convert_two_arm_bool_match_to_matches_macro
+//
+// Convert 2-arm match that evaluates to a boolean into the equivalent matches! invocation.
+//
+// ```
+// fn main() {
+//     match scrutinee$0 {
+//         Some(val) if val.cond() => true,
+//         _ => false,
+//     }
+// }
+// ```
+// ->
+// ```
+// fn main() {
+//     matches!(scrutinee, Some(val) if val.cond())
+// }
+// ```
+pub(crate) fn convert_two_arm_bool_match_to_matches_macro(
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+) -> Option<()> {
+    let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?;
+    let match_arm_list = match_expr.match_arm_list()?;
+    let mut arms = match_arm_list.arms();
+    let first_arm = arms.next()?;
+    let second_arm = arms.next()?;
+    if arms.next().is_some() {
+        cov_mark::hit!(non_two_arm_match);
+        return None;
+    }
+    let first_arm_expr = first_arm.expr();
+    let second_arm_expr = second_arm.expr();
+
+    let invert_matches = if is_bool_literal_expr(&first_arm_expr, true)
+        && is_bool_literal_expr(&second_arm_expr, false)
+    {
+        false
+    } else if is_bool_literal_expr(&first_arm_expr, false)
+        && is_bool_literal_expr(&second_arm_expr, true)
+    {
+        true
+    } else {
+        cov_mark::hit!(non_invert_bool_literal_arms);
+        return None;
+    };
+
+    let target_range = ctx.sema.original_range(match_expr.syntax()).range;
+    let expr = match_expr.expr()?;
+
+    acc.add(
+        AssistId("convert_two_arm_bool_match_to_matches_macro", AssistKind::RefactorRewrite),
+        "Convert to matches!",
+        target_range,
+        |builder| {
+            let mut arm_str = String::new();
+            if let Some(ref pat) = first_arm.pat() {
+                arm_str += &pat.to_string();
+            }
+            if let Some(ref guard) = first_arm.guard() {
+                arm_str += &format!(" {}", &guard.to_string());
+            }
+            if invert_matches {
+                builder.replace(target_range, format!("!matches!({}, {})", expr, arm_str));
+            } else {
+                builder.replace(target_range, format!("matches!({}, {})", expr, arm_str));
+            }
+        },
+    )
+}
+
+fn is_bool_literal_expr(expr: &Option<ast::Expr>, expect_bool: bool) -> bool {
+    if let Some(ast::Expr::Literal(lit)) = expr {
+        if let ast::LiteralKind::Bool(b) = lit.kind() {
+            return b == expect_bool;
+        }
+    }
+
+    return false;
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
+
+    use super::convert_two_arm_bool_match_to_matches_macro;
+
+    #[test]
+    fn not_applicable_outside_of_range_left() {
+        check_assist_not_applicable(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    $0 match a {
+        Some(_val) => true,
+        _ => false
+    }
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn not_applicable_non_two_arm_match() {
+        cov_mark::check!(non_two_arm_match);
+        check_assist_not_applicable(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(3) => true,
+        Some(4) => true,
+        _ => false
+    }
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn not_applicable_non_bool_literal_arms() {
+        cov_mark::check!(non_invert_bool_literal_arms);
+        check_assist_not_applicable(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(val) => val == 3,
+        _ => false
+    }
+}
+        "#,
+        );
+    }
+    #[test]
+    fn not_applicable_both_false_arms() {
+        cov_mark::check!(non_invert_bool_literal_arms);
+        check_assist_not_applicable(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(val) => false,
+        _ => false
+    }
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn not_applicable_both_true_arms() {
+        cov_mark::check!(non_invert_bool_literal_arms);
+        check_assist_not_applicable(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(val) => true,
+        _ => true
+    }
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn convert_simple_case() {
+        check_assist(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(_val) => true,
+        _ => false
+    }
+}
+"#,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    matches!(a, Some(_val))
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_simple_invert_case() {
+        check_assist(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(_val) => false,
+        _ => true
+    }
+}
+"#,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    !matches!(a, Some(_val))
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_with_guard_case() {
+        check_assist(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(val) if val > 3 => true,
+        _ => false
+    }
+}
+"#,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    matches!(a, Some(val) if val > 3)
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_enum_match_cases() {
+        check_assist(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+enum X { A, B }
+
+fn foo(a: X) -> bool {
+    match a$0 {
+        X::A => true,
+        _ => false
+    }
+}
+"#,
+            r#"
+enum X { A, B }
+
+fn foo(a: X) -> bool {
+    matches!(a, X::A)
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_target_simple() {
+        check_assist_target(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(val) => true,
+        _ => false
+    }
+}
+"#,
+            r#"match a {
+        Some(val) => true,
+        _ => false
+    }"#,
+        );
+    }
+
+    #[test]
+    fn convert_target_complex() {
+        check_assist_target(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+enum E { X, Y }
+
+fn main() {
+    match E::X$0 {
+        E::X => true,
+        _ => false,
+    }
+}
+"#,
+            "match E::X {
+        E::X => true,
+        _ => false,
+    }",
+        );
+    }
+}
index dfb5652126467ee974ca77dc60820836d796f6f0..ddc2052e7aa240f92f32c3122423138edea0f4da 100644 (file)
@@ -101,21 +101,22 @@ pub(crate) fn extract_struct_from_enum_variant(
                 });
             }
 
-            let indent = enum_ast.indent_level();
             let generic_params = enum_ast
                 .generic_param_list()
                 .and_then(|known_generics| extract_generic_params(&known_generics, &field_list));
             let generics = generic_params.as_ref().map(|generics| generics.clone_for_update());
             let def =
                 create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast);
+
+            let enum_ast = variant.parent_enum();
+            let indent = enum_ast.indent_level();
             def.reindent_to(indent);
 
-            let start_offset = &variant.parent_enum().syntax().clone();
-            ted::insert_all_raw(
-                ted::Position::before(start_offset),
+            ted::insert_all(
+                ted::Position::before(enum_ast.syntax()),
                 vec![
                     def.syntax().clone().into(),
-                    make::tokens::whitespace(&format!("\n\n{}", indent)).into(),
+                    make::tokens::whitespace(&format!("\n\n{indent}")).into(),
                 ],
             );
 
@@ -227,7 +228,7 @@ fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, b
 }
 
 fn create_struct_def(
-    variant_name: ast::Name,
+    name: ast::Name,
     variant: &ast::Variant,
     field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
     generics: Option<ast::GenericParamList>,
@@ -269,43 +270,27 @@ fn create_struct_def(
             field_list.into()
         }
     };
-
     field_list.reindent_to(IndentLevel::single());
 
-    let strukt = make::struct_(enum_vis, variant_name, generics, field_list).clone_for_update();
-
-    // FIXME: Consider making this an actual function somewhere (like in `AttrsOwnerEdit`) after some deliberation
-    let attrs_and_docs = |node: &SyntaxNode| {
-        let mut select_next_ws = false;
-        node.children_with_tokens().filter(move |child| {
-            let accept = match child.kind() {
-                ATTR | COMMENT => {
-                    select_next_ws = true;
-                    return true;
-                }
-                WHITESPACE if select_next_ws => true,
-                _ => false,
-            };
-            select_next_ws = false;
-
-            accept
-        })
-    };
+    let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update();
 
-    // copy attributes & comments from variant
-    let variant_attrs = attrs_and_docs(variant.syntax())
-        .map(|tok| match tok.kind() {
-            WHITESPACE => make::tokens::single_newline().into(),
-            _ => tok,
-        })
-        .collect();
-    ted::insert_all(ted::Position::first_child_of(strukt.syntax()), variant_attrs);
+    // take comments from variant
+    ted::insert_all(
+        ted::Position::first_child_of(strukt.syntax()),
+        take_all_comments(variant.syntax()),
+    );
 
     // copy attributes from enum
     ted::insert_all(
         ted::Position::first_child_of(strukt.syntax()),
-        enum_.attrs().map(|it| it.syntax().clone_for_update().into()).collect(),
+        enum_
+            .attrs()
+            .flat_map(|it| {
+                vec![it.syntax().clone_for_update().into(), make::tokens::single_newline().into()]
+            })
+            .collect(),
     );
+
     strukt
 }
 
@@ -346,16 +331,48 @@ fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList
         })
         .unwrap_or_else(|| make::ty(&name.text()));
 
+    // change from a record to a tuple field list
     let tuple_field = make::tuple_field(None, ty);
-    let replacement = make::variant(
-        name,
-        Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))),
-    )
-    .clone_for_update();
-    ted::replace(variant.syntax(), replacement.syntax());
+    let field_list = make::tuple_field_list(iter::once(tuple_field)).clone_for_update();
+    ted::replace(variant.field_list()?.syntax(), field_list.syntax());
+
+    // remove any ws after the name
+    if let Some(ws) = name
+        .syntax()
+        .siblings_with_tokens(syntax::Direction::Next)
+        .find_map(|tok| tok.into_token().filter(|tok| tok.kind() == WHITESPACE))
+    {
+        ted::remove(SyntaxElement::Token(ws));
+    }
+
     Some(())
 }
 
+// Note: this also detaches whitespace after comments,
+// since `SyntaxNode::splice_children` (and by extension `ted::insert_all_raw`)
+// detaches nodes. If we only took the comments, we'd leave behind the old whitespace.
+fn take_all_comments(node: &SyntaxNode) -> Vec<SyntaxElement> {
+    let mut remove_next_ws = false;
+    node.children_with_tokens()
+        .filter_map(move |child| match child.kind() {
+            COMMENT => {
+                remove_next_ws = true;
+                child.detach();
+                Some(child)
+            }
+            WHITESPACE if remove_next_ws => {
+                remove_next_ws = false;
+                child.detach();
+                Some(make::tokens::single_newline().into())
+            }
+            _ => {
+                remove_next_ws = false;
+                None
+            }
+        })
+        .collect()
+}
+
 fn apply_references(
     insert_use_cfg: InsertUseConfig,
     segment: ast::PathSegment,
@@ -480,10 +497,14 @@ enum En<T> { Var(Var<T>) }"#,
     fn test_extract_struct_carries_over_attributes() {
         check_assist(
             extract_struct_from_enum_variant,
-            r#"#[derive(Debug)]
+            r#"
+#[derive(Debug)]
 #[derive(Clone)]
 enum Enum { Variant{ field: u32$0 } }"#,
-            r#"#[derive(Debug)]#[derive(Clone)] struct Variant{ field: u32 }
+            r#"
+#[derive(Debug)]
+#[derive(Clone)]
+struct Variant{ field: u32 }
 
 #[derive(Debug)]
 #[derive(Clone)]
@@ -614,7 +635,7 @@ enum A { One(One) }"#,
     }
 
     #[test]
-    fn test_extract_struct_keep_comments_and_attrs_on_variant_struct() {
+    fn test_extract_struct_move_struct_variant_comments() {
         check_assist(
             extract_struct_from_enum_variant,
             r#"
@@ -631,19 +652,19 @@ enum A {
 /* comment */
 // other
 /// comment
-#[attr]
 struct One{
     a: u32
 }
 
 enum A {
+    #[attr]
     One(One)
 }"#,
         );
     }
 
     #[test]
-    fn test_extract_struct_keep_comments_and_attrs_on_variant_tuple() {
+    fn test_extract_struct_move_tuple_variant_comments() {
         check_assist(
             extract_struct_from_enum_variant,
             r#"
@@ -658,10 +679,10 @@ enum A {
 /* comment */
 // other
 /// comment
-#[attr]
 struct One(u32, u32);
 
 enum A {
+    #[attr]
     One(One)
 }"#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_or_with_or_else.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_or_with_or_else.rs
new file mode 100644 (file)
index 0000000..7d91be6
--- /dev/null
@@ -0,0 +1,364 @@
+use ide_db::{
+    assists::{AssistId, AssistKind},
+    famous_defs::FamousDefs,
+};
+use syntax::{
+    ast::{self, make, Expr, HasArgList},
+    AstNode,
+};
+
+use crate::{AssistContext, Assists};
+
+// Assist: replace_or_with_or_else
+//
+// Replace `unwrap_or` with `unwrap_or_else` and `ok_or` with `ok_or_else`.
+//
+// ```
+// # //- minicore:option
+// fn foo() {
+//     let a = Some(1);
+//     a.unwra$0p_or(2);
+// }
+// ```
+// ->
+// ```
+// fn foo() {
+//     let a = Some(1);
+//     a.unwrap_or_else(|| 2);
+// }
+// ```
+pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
+
+    let kind = is_option_or_result(call.receiver()?, ctx)?;
+
+    let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
+
+    let mut map_or = false;
+
+    let replace = match &*name.text() {
+        "unwrap_or" => "unwrap_or_else".to_string(),
+        "or" => "or_else".to_string(),
+        "ok_or" if kind == Kind::Option => "ok_or_else".to_string(),
+        "map_or" => {
+            map_or = true;
+            "map_or_else".to_string()
+        }
+        _ => return None,
+    };
+
+    let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
+        [] => make::arg_list(Vec::new()),
+        [first] => {
+            let param = into_closure(first);
+            make::arg_list(vec![param])
+        }
+        [first, second] if map_or => {
+            let param = into_closure(first);
+            make::arg_list(vec![param, second.clone()])
+        }
+        _ => return None,
+    };
+
+    acc.add(
+        AssistId("replace_or_with_or_else", AssistKind::RefactorRewrite),
+        format!("Replace {} with {}", name.text(), replace),
+        call.syntax().text_range(),
+        |builder| {
+            builder.replace(name.syntax().text_range(), replace);
+            builder.replace_ast(arg_list, arg)
+        },
+    )
+}
+
+fn into_closure(param: &Expr) -> Expr {
+    (|| {
+        if let ast::Expr::CallExpr(call) = param {
+            if call.arg_list()?.args().count() == 0 {
+                Some(call.expr()?.clone())
+            } else {
+                None
+            }
+        } else {
+            None
+        }
+    })()
+    .unwrap_or_else(|| make::expr_closure(None, param.clone()))
+}
+
+// Assist: replace_or_else_with_or
+//
+// Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`.
+//
+// ```
+// # //- minicore:option
+// fn foo() {
+//     let a = Some(1);
+//     a.unwra$0p_or_else(|| 2);
+// }
+// ```
+// ->
+// ```
+// fn foo() {
+//     let a = Some(1);
+//     a.unwrap_or(2);
+// }
+// ```
+pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
+
+    let kind = is_option_or_result(call.receiver()?, ctx)?;
+
+    let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
+
+    let mut map_or = false;
+    let replace = match &*name.text() {
+        "unwrap_or_else" => "unwrap_or".to_string(),
+        "or_else" => "or".to_string(),
+        "ok_or_else" if kind == Kind::Option => "ok_or".to_string(),
+        "map_or_else" => {
+            map_or = true;
+            "map_or".to_string()
+        }
+        _ => return None,
+    };
+
+    let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
+        [] => make::arg_list(Vec::new()),
+        [first] => {
+            let param = into_call(first);
+            make::arg_list(vec![param])
+        }
+        [first, second] if map_or => {
+            let param = into_call(first);
+            make::arg_list(vec![param, second.clone()])
+        }
+        _ => return None,
+    };
+
+    acc.add(
+        AssistId("replace_or_else_with_or", AssistKind::RefactorRewrite),
+        format!("Replace {} with {}", name.text(), replace),
+        call.syntax().text_range(),
+        |builder| {
+            builder.replace(name.syntax().text_range(), replace);
+            builder.replace_ast(arg_list, arg)
+        },
+    )
+}
+
+fn into_call(param: &Expr) -> Expr {
+    (|| {
+        if let ast::Expr::ClosureExpr(closure) = param {
+            if closure.param_list()?.params().count() == 0 {
+                Some(closure.body()?.clone())
+            } else {
+                None
+            }
+        } else {
+            None
+        }
+    })()
+    .unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())))
+}
+
+#[derive(PartialEq, Eq)]
+enum Kind {
+    Option,
+    Result,
+}
+
+fn is_option_or_result(receiver: Expr, ctx: &AssistContext<'_>) -> Option<Kind> {
+    let ty = ctx.sema.type_of_expr(&receiver)?.adjusted().as_adt()?.as_enum()?;
+    let option_enum =
+        FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_option_Option();
+
+    if let Some(option_enum) = option_enum {
+        if ty == option_enum {
+            return Some(Kind::Option);
+        }
+    }
+
+    let result_enum =
+        FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_result_Result();
+
+    if let Some(result_enum) = result_enum {
+        if ty == result_enum {
+            return Some(Kind::Result);
+        }
+    }
+
+    None
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    use super::*;
+
+    #[test]
+    fn replace_or_with_or_else_simple() {
+        check_assist(
+            replace_or_with_or_else,
+            r#"
+//- minicore: option
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_$0or(2);
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_or_else(|| 2);
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_with_or_else_call() {
+        check_assist(
+            replace_or_with_or_else,
+            r#"
+//- minicore: option
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_$0or(x());
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_or_else(x);
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_with_or_else_block() {
+        check_assist(
+            replace_or_with_or_else,
+            r#"
+//- minicore: option
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_$0or({
+        let mut x = bar();
+        for i in 0..10 {
+            x += i;
+        }
+        x
+    });
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_or_else(|| {
+        let mut x = bar();
+        for i in 0..10 {
+            x += i;
+        }
+        x
+    });
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_else_with_or_simple() {
+        check_assist(
+            replace_or_else_with_or,
+            r#"
+//- minicore: option
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_$0or_else(|| 2);
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_or(2);
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_else_with_or_call() {
+        check_assist(
+            replace_or_else_with_or,
+            r#"
+//- minicore: option
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_$0or_else(x);
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_or(x());
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_else_with_or_result() {
+        check_assist(
+            replace_or_else_with_or,
+            r#"
+//- minicore: result
+fn foo() {
+    let foo = Ok(1);
+    return foo.unwrap_$0or_else(x);
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Ok(1);
+    return foo.unwrap_or(x());
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_else_with_or_map() {
+        check_assist(
+            replace_or_else_with_or,
+            r#"
+//- minicore: result
+fn foo() {
+    let foo = Ok("foo");
+    return foo.map$0_or_else(|| 42, |v| v.len());
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Ok("foo");
+    return foo.map_or(42, |v| v.len());
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_else_with_or_not_applicable() {
+        check_assist_not_applicable(
+            replace_or_else_with_or,
+            r#"
+fn foo() {
+    let foo = Ok(1);
+    return foo.unwrap_$0or_else(x);
+}
+"#,
+        )
+    }
+}
index 5242f3b5100cfa9357d322ac8f2cc647def5385f..521447c26dfbed01d20ac10592fd127a286f16ec 100644 (file)
@@ -1,5 +1,6 @@
+use hir::HirDisplay;
 use syntax::{
-    ast::{Expr, GenericArg},
+    ast::{Expr, GenericArg, GenericArgList},
     ast::{LetStmt, Type::InferType},
     AstNode, TextRange,
 };
@@ -34,21 +35,7 @@ pub(crate) fn replace_turbofish_with_explicit_type(
 
     let initializer = let_stmt.initializer()?;
 
-    let generic_args = match &initializer {
-        Expr::MethodCallExpr(ce) => ce.generic_arg_list()?,
-        Expr::CallExpr(ce) => {
-            if let Expr::PathExpr(pe) = ce.expr()? {
-                pe.path()?.segment()?.generic_arg_list()?
-            } else {
-                cov_mark::hit!(not_applicable_if_non_path_function_call);
-                return None;
-            }
-        }
-        _ => {
-            cov_mark::hit!(not_applicable_if_non_function_call_initializer);
-            return None;
-        }
-    };
+    let generic_args = generic_arg_list(&initializer)?;
 
     // Find range of ::<_>
     let colon2 = generic_args.coloncolon_token()?;
@@ -65,7 +52,16 @@ pub(crate) fn replace_turbofish_with_explicit_type(
 
     // An improvement would be to check that this is correctly part of the return value of the
     // function call, or sub in the actual return type.
-    let turbofish_type = &turbofish_args[0];
+    let returned_type = match ctx.sema.type_of_expr(&initializer) {
+        Some(returned_type) if !returned_type.original.contains_unknown() => {
+            let module = ctx.sema.scope(let_stmt.syntax())?.module();
+            returned_type.original.display_source_code(ctx.db(), module.into()).ok()?
+        }
+        _ => {
+            cov_mark::hit!(fallback_to_turbofish_type_if_type_info_not_available);
+            turbofish_args[0].to_string()
+        }
+    };
 
     let initializer_start = initializer.syntax().text_range().start();
     if ctx.offset() > turbofish_range.end() || ctx.offset() < initializer_start {
@@ -83,7 +79,7 @@ pub(crate) fn replace_turbofish_with_explicit_type(
             "Replace turbofish with explicit type",
             TextRange::new(initializer_start, turbofish_range.end()),
             |builder| {
-                builder.insert(ident_range.end(), format!(": {}", turbofish_type));
+                builder.insert(ident_range.end(), format!(": {}", returned_type));
                 builder.delete(turbofish_range);
             },
         );
@@ -98,7 +94,7 @@ pub(crate) fn replace_turbofish_with_explicit_type(
             "Replace `_` with turbofish type",
             turbofish_range,
             |builder| {
-                builder.replace(underscore_range, turbofish_type.to_string());
+                builder.replace(underscore_range, returned_type);
                 builder.delete(turbofish_range);
             },
         );
@@ -107,6 +103,26 @@ pub(crate) fn replace_turbofish_with_explicit_type(
     None
 }
 
+fn generic_arg_list(expr: &Expr) -> Option<GenericArgList> {
+    match expr {
+        Expr::MethodCallExpr(expr) => expr.generic_arg_list(),
+        Expr::CallExpr(expr) => {
+            if let Expr::PathExpr(pe) = expr.expr()? {
+                pe.path()?.segment()?.generic_arg_list()
+            } else {
+                cov_mark::hit!(not_applicable_if_non_path_function_call);
+                return None;
+            }
+        }
+        Expr::AwaitExpr(expr) => generic_arg_list(&expr.expr()?),
+        Expr::TryExpr(expr) => generic_arg_list(&expr.expr()?),
+        _ => {
+            cov_mark::hit!(not_applicable_if_non_function_call_initializer);
+            None
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -115,6 +131,7 @@ mod tests {
 
     #[test]
     fn replaces_turbofish_for_vec_string() {
+        cov_mark::check!(fallback_to_turbofish_type_if_type_info_not_available);
         check_assist(
             replace_turbofish_with_explicit_type,
             r#"
@@ -135,6 +152,7 @@ fn main() {
     #[test]
     fn replaces_method_calls() {
         // foo.make() is a method call which uses a different expr in the let initializer
+        cov_mark::check!(fallback_to_turbofish_type_if_type_info_not_available);
         check_assist(
             replace_turbofish_with_explicit_type,
             r#"
@@ -237,6 +255,110 @@ fn make<T>() -> T {}
 fn main() {
     let a = make$0::<Vec<String>, i32>();
 }
+"#,
+        );
+    }
+
+    #[test]
+    fn replaces_turbofish_for_known_type() {
+        check_assist(
+            replace_turbofish_with_explicit_type,
+            r#"
+fn make<T>() -> T {}
+fn main() {
+    let a = make$0::<i32>();
+}
+"#,
+            r#"
+fn make<T>() -> T {}
+fn main() {
+    let a: i32 = make();
+}
+"#,
+        );
+        check_assist(
+            replace_turbofish_with_explicit_type,
+            r#"
+//- minicore: option
+fn make<T>() -> T {}
+fn main() {
+    let a = make$0::<Option<bool>>();
+}
+"#,
+            r#"
+fn make<T>() -> T {}
+fn main() {
+    let a: Option<bool> = make();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replaces_turbofish_not_same_type() {
+        check_assist(
+            replace_turbofish_with_explicit_type,
+            r#"
+//- minicore: option
+fn make<T>() -> Option<T> {}
+fn main() {
+    let a = make$0::<u128>();
+}
+"#,
+            r#"
+fn make<T>() -> Option<T> {}
+fn main() {
+    let a: Option<u128> = make();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replaces_turbofish_for_type_with_defaulted_generic_param() {
+        check_assist(
+            replace_turbofish_with_explicit_type,
+            r#"
+struct HasDefault<T, U = i32>(T, U);
+fn make<T>() -> HasDefault<T> {}
+fn main() {
+    let a = make$0::<bool>();
+}
+"#,
+            r#"
+struct HasDefault<T, U = i32>(T, U);
+fn make<T>() -> HasDefault<T> {}
+fn main() {
+    let a: HasDefault<bool> = make();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replaces_turbofish_try_await() {
+        check_assist(
+            replace_turbofish_with_explicit_type,
+            r#"
+//- minicore: option, future
+struct Fut<T>(T);
+impl<T> core::future::Future for Fut<T> {
+    type Output = Option<T>;
+}
+fn make<T>() -> Fut<T> {}
+fn main() {
+    let a = make$0::<bool>().await?;
+}
+"#,
+            r#"
+struct Fut<T>(T);
+impl<T> core::future::Future for Fut<T> {
+    type Output = Option<T>;
+}
+fn make<T>() -> Fut<T> {}
+fn main() {
+    let a: bool = make().await?;
+}
 "#,
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
new file mode 100644 (file)
index 0000000..9565f0e
--- /dev/null
@@ -0,0 +1,293 @@
+use syntax::{
+    algo::neighbor,
+    ast::{self, edit::IndentLevel, make, AstNode},
+    ted::{self, Position},
+    Direction, SyntaxKind, T,
+};
+
+use crate::{AssistContext, AssistId, AssistKind, Assists};
+
+// Assist: unmerge_match_arm
+//
+// Splits the current match with a `|` pattern into two arms with identical bodies.
+//
+// ```
+// enum Action { Move { distance: u32 }, Stop }
+//
+// fn handle(action: Action) {
+//     match action {
+//         Action::Move(..) $0| Action::Stop => foo(),
+//     }
+// }
+// ```
+// ->
+// ```
+// enum Action { Move { distance: u32 }, Stop }
+//
+// fn handle(action: Action) {
+//     match action {
+//         Action::Move(..) => foo(),
+//         Action::Stop => foo(),
+//     }
+// }
+// ```
+pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let pipe_token = ctx.find_token_syntax_at_offset(T![|])?;
+    let or_pat = ast::OrPat::cast(pipe_token.parent()?)?.clone_for_update();
+    let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?;
+    let match_arm_body = match_arm.expr()?;
+
+    // We don't need to check for leading pipe because it is directly under `MatchArm`
+    // without `OrPat`.
+
+    let new_parent = match_arm.syntax().parent()?;
+    let old_parent_range = new_parent.text_range();
+
+    acc.add(
+        AssistId("unmerge_match_arm", AssistKind::RefactorRewrite),
+        "Unmerge match arm",
+        pipe_token.text_range(),
+        |edit| {
+            let pats_after = pipe_token
+                .siblings_with_tokens(Direction::Next)
+                .filter_map(|it| ast::Pat::cast(it.into_node()?));
+            // FIXME: We should add a leading pipe if the original arm has one.
+            let new_match_arm = make::match_arm(
+                pats_after,
+                match_arm.guard().and_then(|guard| guard.condition()),
+                match_arm_body,
+            )
+            .clone_for_update();
+
+            let mut pipe_index = pipe_token.index();
+            if pipe_token
+                .prev_sibling_or_token()
+                .map_or(false, |it| it.kind() == SyntaxKind::WHITESPACE)
+            {
+                pipe_index -= 1;
+            }
+            or_pat.syntax().splice_children(
+                pipe_index..or_pat.syntax().children_with_tokens().count(),
+                Vec::new(),
+            );
+
+            let mut insert_after_old_arm = Vec::new();
+
+            // A comma can be:
+            //  - After the arm. In this case we always want to insert a comma after the newly
+            //    inserted arm.
+            //  - Missing after the arm, with no arms after. In this case we want to insert a
+            //    comma before the newly inserted arm. It can not be necessary if there arm
+            //    body is a block, but we don't bother to check that.
+            //  - Missing after the arm with arms after, if the arm body is a block. In this case
+            //    we don't want to insert a comma at all.
+            let has_comma_after =
+                std::iter::successors(match_arm.syntax().last_child_or_token(), |it| {
+                    it.prev_sibling_or_token()
+                })
+                .map(|it| it.kind())
+                .skip_while(|it| it.is_trivia())
+                .next()
+                    == Some(T![,]);
+            let has_arms_after = neighbor(&match_arm, Direction::Next).is_some();
+            if !has_comma_after && !has_arms_after {
+                insert_after_old_arm.push(make::token(T![,]).into());
+            }
+
+            let indent = IndentLevel::from_node(match_arm.syntax());
+            insert_after_old_arm.push(make::tokens::whitespace(&format!("\n{indent}")).into());
+
+            insert_after_old_arm.push(new_match_arm.syntax().clone().into());
+
+            ted::insert_all_raw(Position::after(match_arm.syntax()), insert_after_old_arm);
+
+            if has_comma_after {
+                ted::insert_raw(
+                    Position::last_child_of(new_match_arm.syntax()),
+                    make::token(T![,]),
+                );
+            }
+
+            edit.replace(old_parent_range, new_parent.to_string());
+        },
+    )
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    use super::*;
+
+    #[test]
+    fn unmerge_match_arm_single_pipe() {
+        check_assist(
+            unmerge_match_arm,
+            r#"
+#[derive(Debug)]
+enum X { A, B, C }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A $0| X::B => { 1i32 }
+        X::C => { 2i32 }
+    };
+}
+"#,
+            r#"
+#[derive(Debug)]
+enum X { A, B, C }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A => { 1i32 }
+        X::B => { 1i32 }
+        X::C => { 2i32 }
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unmerge_match_arm_guard() {
+        check_assist(
+            unmerge_match_arm,
+            r#"
+#[derive(Debug)]
+enum X { A, B, C }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A $0| X::B if true => { 1i32 }
+        _ => { 2i32 }
+    };
+}
+"#,
+            r#"
+#[derive(Debug)]
+enum X { A, B, C }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A if true => { 1i32 }
+        X::B if true => { 1i32 }
+        _ => { 2i32 }
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unmerge_match_arm_leading_pipe() {
+        check_assist_not_applicable(
+            unmerge_match_arm,
+            r#"
+
+fn main() {
+    let y = match 0 {
+        |$0 0 => { 1i32 }
+        1 => { 2i32 }
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unmerge_match_arm_multiple_pipes() {
+        check_assist(
+            unmerge_match_arm,
+            r#"
+#[derive(Debug)]
+enum X { A, B, C, D, E }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A | X::B |$0 X::C | X::D => 1i32,
+        X::E => 2i32,
+    };
+}
+"#,
+            r#"
+#[derive(Debug)]
+enum X { A, B, C, D, E }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A | X::B => 1i32,
+        X::C | X::D => 1i32,
+        X::E => 2i32,
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unmerge_match_arm_inserts_comma_if_required() {
+        check_assist(
+            unmerge_match_arm,
+            r#"
+#[derive(Debug)]
+enum X { A, B }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A $0| X::B => 1i32
+    };
+}
+"#,
+            r#"
+#[derive(Debug)]
+enum X { A, B }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A => 1i32,
+        X::B => 1i32
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unmerge_match_arm_inserts_comma_if_had_after() {
+        check_assist(
+            unmerge_match_arm,
+            r#"
+#[derive(Debug)]
+enum X { A, B }
+
+fn main() {
+    let x = X::A;
+    match x {
+        X::A $0| X::B => {},
+    }
+}
+"#,
+            r#"
+#[derive(Debug)]
+enum X { A, B }
+
+fn main() {
+    let x = X::A;
+    match x {
+        X::A => {},
+        X::B => {},
+    }
+}
+"#,
+        );
+    }
+}
index 7fb35143fa2ff1303459cedde3579f16221d7fa7..e52544db5f530ff969735c4a25b305c64c5491ae 100644 (file)
@@ -122,6 +122,7 @@ mod handlers {
     mod convert_let_else_to_match;
     mod convert_tuple_struct_to_named_struct;
     mod convert_to_guarded_return;
+    mod convert_two_arm_bool_match_to_matches_macro;
     mod convert_while_to_loop;
     mod destructure_tuple_binding;
     mod expand_glob_import;
@@ -179,12 +180,14 @@ mod handlers {
     mod replace_try_expr_with_match;
     mod replace_derive_with_manual_impl;
     mod replace_if_let_with_match;
+    mod replace_or_with_or_else;
     mod introduce_named_generic;
     mod replace_let_with_if_let;
     mod replace_qualified_name_with_use;
     mod replace_string_with_char;
     mod replace_turbofish_with_explicit_type;
     mod split_import;
+    mod unmerge_match_arm;
     mod sort_items;
     mod toggle_ignore;
     mod unmerge_use;
@@ -215,6 +218,7 @@ pub(crate) fn all() -> &'static [Handler] {
             convert_let_else_to_match::convert_let_else_to_match,
             convert_to_guarded_return::convert_to_guarded_return,
             convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
+            convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro,
             convert_while_to_loop::convert_while_to_loop,
             destructure_tuple_binding::destructure_tuple_binding,
             expand_glob_import::expand_glob_import,
@@ -273,11 +277,14 @@ pub(crate) fn all() -> &'static [Handler] {
             replace_if_let_with_match::replace_if_let_with_match,
             replace_if_let_with_match::replace_match_with_if_let,
             replace_let_with_if_let::replace_let_with_if_let,
+            replace_or_with_or_else::replace_or_else_with_or,
+            replace_or_with_or_else::replace_or_with_or_else,
             replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type,
             replace_qualified_name_with_use::replace_qualified_name_with_use,
             sort_items::sort_items,
             split_import::split_import,
             toggle_ignore::toggle_ignore,
+            unmerge_match_arm::unmerge_match_arm,
             unmerge_use::unmerge_use,
             unnecessary_async::unnecessary_async,
             unwrap_block::unwrap_block,
index 22319f36134fb6b6d0ee259ae1f2245754d36917..a8c8622c1c1d89cdcab5caf4d489f96f454112f2 100644 (file)
@@ -472,6 +472,26 @@ pub fn y(&self) -> f32 {
     )
 }
 
+#[test]
+fn doctest_convert_two_arm_bool_match_to_matches_macro() {
+    check_doc_test(
+        "convert_two_arm_bool_match_to_matches_macro",
+        r#####"
+fn main() {
+    match scrutinee$0 {
+        Some(val) if val.cond() => true,
+        _ => false,
+    }
+}
+"#####,
+        r#####"
+fn main() {
+    matches!(scrutinee, Some(val) if val.cond())
+}
+"#####,
+    )
+}
+
 #[test]
 fn doctest_convert_while_to_loop() {
     check_doc_test(
@@ -2009,6 +2029,46 @@ fn handle(action: Action) {
     )
 }
 
+#[test]
+fn doctest_replace_or_else_with_or() {
+    check_doc_test(
+        "replace_or_else_with_or",
+        r#####"
+//- minicore:option
+fn foo() {
+    let a = Some(1);
+    a.unwra$0p_or_else(|| 2);
+}
+"#####,
+        r#####"
+fn foo() {
+    let a = Some(1);
+    a.unwrap_or(2);
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_replace_or_with_or_else() {
+    check_doc_test(
+        "replace_or_with_or_else",
+        r#####"
+//- minicore:option
+fn foo() {
+    let a = Some(1);
+    a.unwra$0p_or(2);
+}
+"#####,
+        r#####"
+fn foo() {
+    let a = Some(1);
+    a.unwrap_or_else(|| 2);
+}
+"#####,
+    )
+}
+
 #[test]
 fn doctest_replace_qualified_name_with_use() {
     check_doc_test(
@@ -2207,6 +2267,32 @@ fn arithmetics {
     )
 }
 
+#[test]
+fn doctest_unmerge_match_arm() {
+    check_doc_test(
+        "unmerge_match_arm",
+        r#####"
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move(..) $0| Action::Stop => foo(),
+    }
+}
+"#####,
+        r#####"
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move(..) => foo(),
+        Action::Stop => foo(),
+    }
+}
+"#####,
+    )
+}
+
 #[test]
 fn doctest_unmerge_use() {
     check_doc_test(
index 4d66af9e8d5b8b0933b785d685d55114caf91bfe..588b52cc1ee3a72090d66899fdf89756ad6c48f3 100644 (file)
@@ -282,14 +282,26 @@ pub(crate) fn complete_expr_path(
                         }
                     }
 
-                    if let Some(ty) = innermost_ret_ty {
+                    if let Some(ret_ty) = innermost_ret_ty {
                         add_keyword(
                             "return",
-                            match (in_block_expr, ty.is_unit()) {
-                                (true, true) => "return ;",
-                                (true, false) => "return;",
-                                (false, true) => "return $0",
-                                (false, false) => "return",
+                            match (ret_ty.is_unit(), in_block_expr) {
+                                (true, true) => {
+                                    cov_mark::hit!(return_unit_block);
+                                    "return;"
+                                }
+                                (true, false) => {
+                                    cov_mark::hit!(return_unit_no_block);
+                                    "return"
+                                }
+                                (false, true) => {
+                                    cov_mark::hit!(return_value_block);
+                                    "return $0;"
+                                }
+                                (false, false) => {
+                                    cov_mark::hit!(return_value_no_block);
+                                    "return $0"
+                                }
                             },
                         );
                     }
index 925081ebf66025552c5a5a1e03bbbf0c2e058176..38e24ebc732d497aa4250f6fe23d06a2c2614f61 100644 (file)
@@ -1,7 +1,7 @@
 //! Completion tests for expressions.
 use expect_test::{expect, Expect};
 
-use crate::tests::{completion_list, BASE_ITEMS_FIXTURE};
+use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE};
 
 fn check(ra_fixture: &str, expect: Expect) {
     let actual = completion_list(&format!("{}{}", BASE_ITEMS_FIXTURE, ra_fixture));
@@ -670,3 +670,39 @@ fn test() fn() -> Zulu
         "#]],
     );
 }
+
+#[test]
+fn return_unit_block() {
+    cov_mark::check!(return_unit_block);
+    check_edit("return", r#"fn f() { if true { $0 } }"#, r#"fn f() { if true { return; } }"#);
+}
+
+#[test]
+fn return_unit_no_block() {
+    cov_mark::check!(return_unit_no_block);
+    check_edit(
+        "return",
+        r#"fn f() { match () { () => $0 } }"#,
+        r#"fn f() { match () { () => return } }"#,
+    );
+}
+
+#[test]
+fn return_value_block() {
+    cov_mark::check!(return_value_block);
+    check_edit(
+        "return",
+        r#"fn f() -> i32 { if true { $0 } }"#,
+        r#"fn f() -> i32 { if true { return $0; } }"#,
+    );
+}
+
+#[test]
+fn return_value_no_block() {
+    cov_mark::check!(return_value_no_block);
+    check_edit(
+        "return",
+        r#"fn f() -> i32 { match () { () => $0 } }"#,
+        r#"fn f() -> i32 { match () { () => return $0 } }"#,
+    );
+}
index 84bde4d44dbb34dda5249336ec315966d1f0c881..b890e2b58df8f2688923c1262665e7361a747881 100644 (file)
@@ -315,7 +315,6 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
         | ast::Expr::IndexExpr(_)
         | ast::Expr::Literal(_)
         | ast::Expr::MacroExpr(_)
-        | ast::Expr::MacroStmts(_)
         | ast::Expr::MethodCallExpr(_)
         | ast::Expr::ParenExpr(_)
         | ast::Expr::PathExpr(_)
index d12594a4ce5c5f77c0f101870c890214ef50731d..0c92e706b3916f65c73df4b6e3945b4e6501a052 100644 (file)
@@ -7,9 +7,10 @@ pub(crate) fn break_outside_of_loop(
     ctx: &DiagnosticsContext<'_>,
     d: &hir::BreakOutsideOfLoop,
 ) -> Diagnostic {
+    let construct = if d.is_break { "break" } else { "continue" };
     Diagnostic::new(
         "break-outside-of-loop",
-        "break outside of loop",
+        format!("{construct} outside of loop"),
         ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
     )
 }
@@ -19,11 +20,122 @@ mod tests {
     use crate::tests::check_diagnostics;
 
     #[test]
-    fn break_outside_of_loop() {
+    fn outside_of_loop() {
         check_diagnostics(
             r#"
-fn foo() { break; }
-         //^^^^^ error: break outside of loop
+fn foo() {
+    break;
+  //^^^^^ error: break outside of loop
+    break 'a;
+  //^^^^^^^^ error: break outside of loop
+    continue;
+  //^^^^^^^^ error: continue outside of loop
+    continue 'a;
+  //^^^^^^^^^^^ error: continue outside of loop
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn try_blocks_are_borders() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    'a: loop {
+        try {
+                break;
+              //^^^^^ error: break outside of loop
+                break 'a;
+              //^^^^^^^^ error: break outside of loop
+                continue;
+              //^^^^^^^^ error: continue outside of loop
+                continue 'a;
+              //^^^^^^^^^^^ error: continue outside of loop
+        };
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn async_blocks_are_borders() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    'a: loop {
+        try {
+                break;
+              //^^^^^ error: break outside of loop
+                break 'a;
+              //^^^^^^^^ error: break outside of loop
+                continue;
+              //^^^^^^^^ error: continue outside of loop
+                continue 'a;
+              //^^^^^^^^^^^ error: continue outside of loop
+        };
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn closures_are_borders() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    'a: loop {
+        try {
+                break;
+              //^^^^^ error: break outside of loop
+                break 'a;
+              //^^^^^^^^ error: break outside of loop
+                continue;
+              //^^^^^^^^ error: continue outside of loop
+                continue 'a;
+              //^^^^^^^^^^^ error: continue outside of loop
+        };
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn blocks_pass_through() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    'a: loop {
+        {
+            break;
+            break 'a;
+            continue;
+            continue 'a;
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn label_blocks() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    'a: {
+        break;
+      //^^^^^ error: break outside of loop
+        break 'a;
+        continue;
+      //^^^^^^^^ error: continue outside of loop
+        continue 'a;
+      //^^^^^^^^^^^ error: continue outside of loop
+    }
+}
 "#,
         );
     }
index 5fcaf405b14b94887cc6e81c1dd05db061eac143..c24430ce604692de844a2cc86cea6e0e2bc24abe 100644 (file)
@@ -947,6 +947,50 @@ fn f() {
         );
     }
 
+    mod rust_unstable {
+        use super::*;
+
+        #[test]
+        fn rfc_1872_exhaustive_patterns() {
+            check_diagnostics_no_bails(
+                r"
+//- minicore: option, result
+#![feature(exhaustive_patterns)]
+enum Void {}
+fn test() {
+    match None::<!> { None => () }
+    match Result::<u8, !>::Ok(2) { Ok(_) => () }
+    match Result::<u8, Void>::Ok(2) { Ok(_) => () }
+    match (2, loop {}) {}
+    match Result::<!, !>::Ok(loop {}) {}
+    match (&loop {}) {} // https://github.com/rust-lang/rust/issues/50642#issuecomment-388234919
+    //    ^^^^^^^^^^ error: missing match arm: type `&!` is non-empty
+}",
+            );
+        }
+
+        #[test]
+        fn rfc_1872_private_uninhabitedness() {
+            check_diagnostics_no_bails(
+                r"
+//- minicore: option
+//- /lib.rs crate:lib
+#![feature(exhaustive_patterns)]
+pub struct PrivatelyUninhabited { private_field: Void }
+enum Void {}
+fn test_local(x: Option<PrivatelyUninhabited>) {
+    match x {}
+} //      ^ error: missing match arm: `None` not covered
+//- /main.rs crate:main deps:lib
+#![feature(exhaustive_patterns)]
+fn test(x: Option<lib::PrivatelyUninhabited>) {
+    match x {}
+    //    ^ error: missing match arm: `None` and `Some(_)` not covered
+}",
+            );
+        }
+    }
+
     mod false_negatives {
         //! The implementation of match checking here is a work in progress. As we roll this out, we
         //! prefer false negatives to false positives (ideally there would be no false positives). This
index ed19784d1fa49d11355835d94be8b83983f75792..e9034daefa8d46c1dea2afce1e07683f52f82f66 100644 (file)
@@ -1910,7 +1910,7 @@ pub fn new() -> Self { Vec {} }
 pub struct Box<T> {}
 
 trait Display {}
-trait Sync {}
+auto trait Sync {}
 
 fn main() {
     // The block expression wrapping disables the constructor hint hiding logic
index 8de5d33a1936d42479470854e39bee711f1916a2..5dc9c6c82a14e06f0dda759607d69f9431713d07 100644 (file)
@@ -118,6 +118,11 @@ fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) {
     match mode {
         Mode::Use => {}
         Mode::Type => {
+            // test typepathfn_with_coloncolon
+            // type F = Start::(Middle) -> (Middle)::End;
+            if p.at(T![::]) && p.nth_at(2, T!['(']) {
+                p.bump(T![::]);
+            }
             // test path_fn_trait_args
             // type F = Box<Fn(i32) -> ()>;
             if p.at(T!['(']) {
index 628fa745e752d678d625ef5489173918529b265b..c84f45f1f8e4ec0f059a484354a45fc042fb2e0a 100644 (file)
@@ -262,33 +262,117 @@ pub enum SyntaxKind {
 use self::SyntaxKind::*;
 impl SyntaxKind {
     pub fn is_keyword(self) -> bool {
-        match self {
-            AS_KW | ASYNC_KW | AWAIT_KW | BOX_KW | BREAK_KW | CONST_KW | CONTINUE_KW | CRATE_KW
-            | DYN_KW | ELSE_KW | ENUM_KW | EXTERN_KW | FALSE_KW | FN_KW | FOR_KW | IF_KW
-            | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW
-            | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | SELF_TYPE_KW | STATIC_KW
-            | STRUCT_KW | SUPER_KW | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW
-            | WHERE_KW | WHILE_KW | YIELD_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW
-            | RAW_KW | MACRO_RULES_KW => true,
-            _ => false,
-        }
+        matches!(
+            self,
+            AS_KW
+                | ASYNC_KW
+                | AWAIT_KW
+                | BOX_KW
+                | BREAK_KW
+                | CONST_KW
+                | CONTINUE_KW
+                | CRATE_KW
+                | DYN_KW
+                | ELSE_KW
+                | ENUM_KW
+                | EXTERN_KW
+                | FALSE_KW
+                | FN_KW
+                | FOR_KW
+                | IF_KW
+                | IMPL_KW
+                | IN_KW
+                | LET_KW
+                | LOOP_KW
+                | MACRO_KW
+                | MATCH_KW
+                | MOD_KW
+                | MOVE_KW
+                | MUT_KW
+                | PUB_KW
+                | REF_KW
+                | RETURN_KW
+                | SELF_KW
+                | SELF_TYPE_KW
+                | STATIC_KW
+                | STRUCT_KW
+                | SUPER_KW
+                | TRAIT_KW
+                | TRUE_KW
+                | TRY_KW
+                | TYPE_KW
+                | UNSAFE_KW
+                | USE_KW
+                | WHERE_KW
+                | WHILE_KW
+                | YIELD_KW
+                | AUTO_KW
+                | DEFAULT_KW
+                | EXISTENTIAL_KW
+                | UNION_KW
+                | RAW_KW
+                | MACRO_RULES_KW
+        )
     }
     pub fn is_punct(self) -> bool {
-        match self {
-            SEMICOLON | COMMA | L_PAREN | R_PAREN | L_CURLY | R_CURLY | L_BRACK | R_BRACK
-            | L_ANGLE | R_ANGLE | AT | POUND | TILDE | QUESTION | DOLLAR | AMP | PIPE | PLUS
-            | STAR | SLASH | CARET | PERCENT | UNDERSCORE | DOT | DOT2 | DOT3 | DOT2EQ | COLON
-            | COLON2 | EQ | EQ2 | FAT_ARROW | BANG | NEQ | MINUS | THIN_ARROW | LTEQ | GTEQ
-            | PLUSEQ | MINUSEQ | PIPEEQ | AMPEQ | CARETEQ | SLASHEQ | STAREQ | PERCENTEQ | AMP2
-            | PIPE2 | SHL | SHR | SHLEQ | SHREQ => true,
-            _ => false,
-        }
+        matches!(
+            self,
+            SEMICOLON
+                | COMMA
+                | L_PAREN
+                | R_PAREN
+                | L_CURLY
+                | R_CURLY
+                | L_BRACK
+                | R_BRACK
+                | L_ANGLE
+                | R_ANGLE
+                | AT
+                | POUND
+                | TILDE
+                | QUESTION
+                | DOLLAR
+                | AMP
+                | PIPE
+                | PLUS
+                | STAR
+                | SLASH
+                | CARET
+                | PERCENT
+                | UNDERSCORE
+                | DOT
+                | DOT2
+                | DOT3
+                | DOT2EQ
+                | COLON
+                | COLON2
+                | EQ
+                | EQ2
+                | FAT_ARROW
+                | BANG
+                | NEQ
+                | MINUS
+                | THIN_ARROW
+                | LTEQ
+                | GTEQ
+                | PLUSEQ
+                | MINUSEQ
+                | PIPEEQ
+                | AMPEQ
+                | CARETEQ
+                | SLASHEQ
+                | STAREQ
+                | PERCENTEQ
+                | AMP2
+                | PIPE2
+                | SHL
+                | SHR
+                | SHLEQ
+                | SHREQ
+        )
     }
     pub fn is_literal(self) -> bool {
-        match self {
-            INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING => true,
-            _ => false,
-        }
+        matches!(self, INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING)
     }
     pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {
         let kw = match ident {
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast
new file mode 100644 (file)
index 0000000..b47a5a5
--- /dev/null
@@ -0,0 +1,43 @@
+SOURCE_FILE
+  TYPE_ALIAS
+    TYPE_KW "type"
+    WHITESPACE " "
+    NAME
+      IDENT "F"
+    WHITESPACE " "
+    EQ "="
+    WHITESPACE " "
+    PATH_TYPE
+      PATH
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "Start"
+            COLON2 "::"
+            PARAM_LIST
+              L_PAREN "("
+              PARAM
+                PATH_TYPE
+                  PATH
+                    PATH_SEGMENT
+                      NAME_REF
+                        IDENT "Middle"
+              R_PAREN ")"
+            WHITESPACE " "
+            RET_TYPE
+              THIN_ARROW "->"
+              WHITESPACE " "
+              PAREN_TYPE
+                L_PAREN "("
+                PATH_TYPE
+                  PATH
+                    PATH_SEGMENT
+                      NAME_REF
+                        IDENT "Middle"
+                R_PAREN ")"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "End"
+    SEMICOLON ";"
+  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs
new file mode 100644 (file)
index 0000000..8efd93a
--- /dev/null
@@ -0,0 +1 @@
+type F = Start::(Middle) -> (Middle)::End;
index 706e1742dffde38a695d9119413849ad8fb497ac..92df4d70fd9024edc3865ddd935ae62bee437389 100644 (file)
@@ -116,6 +116,7 @@ pub(crate) struct GlobalStateSnapshot {
     pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
     vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
     pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
+    pub(crate) proc_macros_loaded: bool,
 }
 
 impl std::panic::UnwindSafe for GlobalStateSnapshot {}
@@ -256,6 +257,7 @@ pub(crate) fn snapshot(&self) -> GlobalStateSnapshot {
             check_fixes: Arc::clone(&self.diagnostics.check_fixes),
             mem_docs: self.mem_docs.clone(),
             semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache),
+            proc_macros_loaded: !self.fetch_build_data_queue.last_op_result().0.is_empty(),
         }
     }
 
index d89f0f5a3cf456d24c7889deec9355b3098e7a34..d9b669afbe81cd3be1baea15b57d53788b842a9c 100644 (file)
@@ -1504,7 +1504,11 @@ pub(crate) fn handle_semantic_tokens_full(
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
 
-    let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
+    let mut highlight_config = snap.config.highlighting_config();
+    // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
+    highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded;
+
+    let highlights = snap.analysis.highlight(highlight_config, file_id)?;
     let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 
     // Unconditionally cache the tokens
@@ -1523,7 +1527,11 @@ pub(crate) fn handle_semantic_tokens_full_delta(
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
 
-    let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
+    let mut highlight_config = snap.config.highlighting_config();
+    // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
+    highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded;
+
+    let highlights = snap.analysis.highlight(highlight_config, file_id)?;
     let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 
     let mut cache = snap.semantic_tokens_cache.lock();
index ceb2a6d703d959ad819f422ae27d0e807f1d25d9..f23bbca6387659aa24d32e97036154883bea9a33 100644 (file)
@@ -347,8 +347,8 @@ fn eq_ignore_build_data<'a>(
                             error
                         })
                     })
-                    .collect();
-            }
+                    .collect()
+            };
         }
 
         let watch = match files_config.watcher {
index 62aa47839942a42b596723d7da9b241f128afc58..894795435451c8e2691fe805253987719cd80313 100644 (file)
@@ -343,7 +343,6 @@ Expr =
 | Literal
 | LoopExpr
 | MacroExpr
-| MacroStmts
 | MatchExpr
 | MethodCallExpr
 | ParenExpr
index 63309a155219e55ebec99bcfd3b416ede648df38..449402e5f5b30af4f6e69e3b26c27aa234a2b93c 100644 (file)
@@ -1526,7 +1526,6 @@ pub enum Expr {
     Literal(Literal),
     LoopExpr(LoopExpr),
     MacroExpr(MacroExpr),
-    MacroStmts(MacroStmts),
     MatchExpr(MatchExpr),
     MethodCallExpr(MethodCallExpr),
     ParenExpr(ParenExpr),
@@ -3169,10 +3168,7 @@ fn from(node: ConstArg) -> GenericArg { GenericArg::ConstArg(node) }
 }
 impl AstNode for GenericArg {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG => true,
-            _ => false,
-        }
+        matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG)
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
@@ -3237,12 +3233,23 @@ fn from(node: TupleType) -> Type { Type::TupleType(node) }
 }
 impl AstNode for Type {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            ARRAY_TYPE | DYN_TRAIT_TYPE | FN_PTR_TYPE | FOR_TYPE | IMPL_TRAIT_TYPE | INFER_TYPE
-            | MACRO_TYPE | NEVER_TYPE | PAREN_TYPE | PATH_TYPE | PTR_TYPE | REF_TYPE
-            | SLICE_TYPE | TUPLE_TYPE => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            ARRAY_TYPE
+                | DYN_TRAIT_TYPE
+                | FN_PTR_TYPE
+                | FOR_TYPE
+                | IMPL_TRAIT_TYPE
+                | INFER_TYPE
+                | MACRO_TYPE
+                | NEVER_TYPE
+                | PAREN_TYPE
+                | PATH_TYPE
+                | PTR_TYPE
+                | REF_TYPE
+                | SLICE_TYPE
+                | TUPLE_TYPE
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
@@ -3334,9 +3341,6 @@ fn from(node: LoopExpr) -> Expr { Expr::LoopExpr(node) }
 impl From<MacroExpr> for Expr {
     fn from(node: MacroExpr) -> Expr { Expr::MacroExpr(node) }
 }
-impl From<MacroStmts> for Expr {
-    fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) }
-}
 impl From<MatchExpr> for Expr {
     fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) }
 }
@@ -3384,15 +3388,41 @@ fn from(node: UnderscoreExpr) -> Expr { Expr::UnderscoreExpr(node) }
 }
 impl AstNode for Expr {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR
-            | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR
-            | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_EXPR | MACRO_STMTS | MATCH_EXPR
-            | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
-            | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
-            | YIELD_EXPR | LET_EXPR | UNDERSCORE_EXPR => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            ARRAY_EXPR
+                | AWAIT_EXPR
+                | BIN_EXPR
+                | BLOCK_EXPR
+                | BOX_EXPR
+                | BREAK_EXPR
+                | CALL_EXPR
+                | CAST_EXPR
+                | CLOSURE_EXPR
+                | CONTINUE_EXPR
+                | FIELD_EXPR
+                | FOR_EXPR
+                | IF_EXPR
+                | INDEX_EXPR
+                | LITERAL
+                | LOOP_EXPR
+                | MACRO_EXPR
+                | MATCH_EXPR
+                | METHOD_CALL_EXPR
+                | PAREN_EXPR
+                | PATH_EXPR
+                | PREFIX_EXPR
+                | RANGE_EXPR
+                | RECORD_EXPR
+                | REF_EXPR
+                | RETURN_EXPR
+                | TRY_EXPR
+                | TUPLE_EXPR
+                | WHILE_EXPR
+                | YIELD_EXPR
+                | LET_EXPR
+                | UNDERSCORE_EXPR
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
@@ -3413,7 +3443,6 @@ fn cast(syntax: SyntaxNode) -> Option<Self> {
             LITERAL => Expr::Literal(Literal { syntax }),
             LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }),
             MACRO_EXPR => Expr::MacroExpr(MacroExpr { syntax }),
-            MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }),
             MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
             METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
             PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }),
@@ -3452,7 +3481,6 @@ fn syntax(&self) -> &SyntaxNode {
             Expr::Literal(it) => &it.syntax,
             Expr::LoopExpr(it) => &it.syntax,
             Expr::MacroExpr(it) => &it.syntax,
-            Expr::MacroStmts(it) => &it.syntax,
             Expr::MatchExpr(it) => &it.syntax,
             Expr::MethodCallExpr(it) => &it.syntax,
             Expr::ParenExpr(it) => &it.syntax,
@@ -3521,11 +3549,25 @@ fn from(node: Use) -> Item { Item::Use(node) }
 }
 impl AstNode for Item {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MACRO_RULES
-            | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            CONST
+                | ENUM
+                | EXTERN_BLOCK
+                | EXTERN_CRATE
+                | FN
+                | IMPL
+                | MACRO_CALL
+                | MACRO_RULES
+                | MACRO_DEF
+                | MODULE
+                | STATIC
+                | STRUCT
+                | TRAIT
+                | TYPE_ALIAS
+                | UNION
+                | USE
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
@@ -3629,12 +3671,25 @@ fn from(node: ConstBlockPat) -> Pat { Pat::ConstBlockPat(node) }
 }
 impl AstNode for Pat {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            IDENT_PAT | BOX_PAT | REST_PAT | LITERAL_PAT | MACRO_PAT | OR_PAT | PAREN_PAT
-            | PATH_PAT | WILDCARD_PAT | RANGE_PAT | RECORD_PAT | REF_PAT | SLICE_PAT
-            | TUPLE_PAT | TUPLE_STRUCT_PAT | CONST_BLOCK_PAT => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            IDENT_PAT
+                | BOX_PAT
+                | REST_PAT
+                | LITERAL_PAT
+                | MACRO_PAT
+                | OR_PAT
+                | PAREN_PAT
+                | PATH_PAT
+                | WILDCARD_PAT
+                | RANGE_PAT
+                | RECORD_PAT
+                | REF_PAT
+                | SLICE_PAT
+                | TUPLE_PAT
+                | TUPLE_STRUCT_PAT
+                | CONST_BLOCK_PAT
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
@@ -3686,12 +3741,7 @@ impl From<TupleFieldList> for FieldList {
     fn from(node: TupleFieldList) -> FieldList { FieldList::TupleFieldList(node) }
 }
 impl AstNode for FieldList {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            RECORD_FIELD_LIST | TUPLE_FIELD_LIST => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, RECORD_FIELD_LIST | TUPLE_FIELD_LIST) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
             RECORD_FIELD_LIST => FieldList::RecordFieldList(RecordFieldList { syntax }),
@@ -3717,12 +3767,7 @@ impl From<Union> for Adt {
     fn from(node: Union) -> Adt { Adt::Union(node) }
 }
 impl AstNode for Adt {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            ENUM | STRUCT | UNION => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ENUM | STRUCT | UNION) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
             ENUM => Adt::Enum(Enum { syntax }),
@@ -3753,12 +3798,7 @@ impl From<TypeAlias> for AssocItem {
     fn from(node: TypeAlias) -> AssocItem { AssocItem::TypeAlias(node) }
 }
 impl AstNode for AssocItem {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            CONST | FN | MACRO_CALL | TYPE_ALIAS => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CONST | FN | MACRO_CALL | TYPE_ALIAS) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
             CONST => AssocItem::Const(Const { syntax }),
@@ -3791,12 +3831,7 @@ impl From<TypeAlias> for ExternItem {
     fn from(node: TypeAlias) -> ExternItem { ExternItem::TypeAlias(node) }
 }
 impl AstNode for ExternItem {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            FN | MACRO_CALL | STATIC | TYPE_ALIAS => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FN | MACRO_CALL | STATIC | TYPE_ALIAS) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
             FN => ExternItem::Fn(Fn { syntax }),
@@ -3827,10 +3862,7 @@ fn from(node: TypeParam) -> GenericParam { GenericParam::TypeParam(node) }
 }
 impl AstNode for GenericParam {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM => true,
-            _ => false,
-        }
+        matches!(kind, CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM)
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
@@ -3856,12 +3888,7 @@ pub fn new<T: ast::HasArgList>(node: T) -> AnyHasArgList {
     }
 }
 impl AstNode for AnyHasArgList {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            CALL_EXPR | METHOD_CALL_EXPR => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CALL_EXPR | METHOD_CALL_EXPR) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasArgList { syntax })
     }
@@ -3875,76 +3902,76 @@ pub fn new<T: ast::HasAttrs>(node: T) -> AnyHasAttrs {
 }
 impl AstNode for AnyHasAttrs {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
+        matches!(
+            kind,
             MACRO_CALL
-            | SOURCE_FILE
-            | CONST
-            | ENUM
-            | EXTERN_BLOCK
-            | EXTERN_CRATE
-            | FN
-            | IMPL
-            | MACRO_RULES
-            | MACRO_DEF
-            | MODULE
-            | STATIC
-            | STRUCT
-            | TRAIT
-            | TYPE_ALIAS
-            | UNION
-            | USE
-            | ITEM_LIST
-            | BLOCK_EXPR
-            | SELF_PARAM
-            | PARAM
-            | RECORD_FIELD
-            | TUPLE_FIELD
-            | VARIANT
-            | ASSOC_ITEM_LIST
-            | EXTERN_ITEM_LIST
-            | CONST_PARAM
-            | LIFETIME_PARAM
-            | TYPE_PARAM
-            | LET_STMT
-            | ARRAY_EXPR
-            | AWAIT_EXPR
-            | BIN_EXPR
-            | BOX_EXPR
-            | BREAK_EXPR
-            | CALL_EXPR
-            | CAST_EXPR
-            | CLOSURE_EXPR
-            | CONTINUE_EXPR
-            | FIELD_EXPR
-            | FOR_EXPR
-            | IF_EXPR
-            | INDEX_EXPR
-            | LITERAL
-            | LOOP_EXPR
-            | MATCH_EXPR
-            | METHOD_CALL_EXPR
-            | PAREN_EXPR
-            | PATH_EXPR
-            | PREFIX_EXPR
-            | RANGE_EXPR
-            | REF_EXPR
-            | RETURN_EXPR
-            | TRY_EXPR
-            | TUPLE_EXPR
-            | WHILE_EXPR
-            | YIELD_EXPR
-            | LET_EXPR
-            | UNDERSCORE_EXPR
-            | STMT_LIST
-            | RECORD_EXPR_FIELD_LIST
-            | RECORD_EXPR_FIELD
-            | MATCH_ARM_LIST
-            | MATCH_ARM
-            | IDENT_PAT
-            | REST_PAT
-            | RECORD_PAT_FIELD => true,
-            _ => false,
-        }
+                | SOURCE_FILE
+                | CONST
+                | ENUM
+                | EXTERN_BLOCK
+                | EXTERN_CRATE
+                | FN
+                | IMPL
+                | MACRO_RULES
+                | MACRO_DEF
+                | MODULE
+                | STATIC
+                | STRUCT
+                | TRAIT
+                | TYPE_ALIAS
+                | UNION
+                | USE
+                | ITEM_LIST
+                | BLOCK_EXPR
+                | SELF_PARAM
+                | PARAM
+                | RECORD_FIELD
+                | TUPLE_FIELD
+                | VARIANT
+                | ASSOC_ITEM_LIST
+                | EXTERN_ITEM_LIST
+                | CONST_PARAM
+                | LIFETIME_PARAM
+                | TYPE_PARAM
+                | LET_STMT
+                | ARRAY_EXPR
+                | AWAIT_EXPR
+                | BIN_EXPR
+                | BOX_EXPR
+                | BREAK_EXPR
+                | CALL_EXPR
+                | CAST_EXPR
+                | CLOSURE_EXPR
+                | CONTINUE_EXPR
+                | FIELD_EXPR
+                | FOR_EXPR
+                | IF_EXPR
+                | INDEX_EXPR
+                | LITERAL
+                | LOOP_EXPR
+                | MATCH_EXPR
+                | METHOD_CALL_EXPR
+                | PAREN_EXPR
+                | PATH_EXPR
+                | PREFIX_EXPR
+                | RANGE_EXPR
+                | REF_EXPR
+                | RETURN_EXPR
+                | TRY_EXPR
+                | TUPLE_EXPR
+                | WHILE_EXPR
+                | YIELD_EXPR
+                | LET_EXPR
+                | UNDERSCORE_EXPR
+                | STMT_LIST
+                | RECORD_EXPR_FIELD_LIST
+                | RECORD_EXPR_FIELD
+                | MATCH_ARM_LIST
+                | MATCH_ARM
+                | IDENT_PAT
+                | REST_PAT
+                | RECORD_PAT_FIELD
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasAttrs { syntax })
@@ -3959,12 +3986,29 @@ pub fn new<T: ast::HasDocComments>(node: T) -> AnyHasDocComments {
 }
 impl AstNode for AnyHasDocComments {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            MACRO_CALL | SOURCE_FILE | CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL
-            | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION
-            | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            MACRO_CALL
+                | SOURCE_FILE
+                | CONST
+                | ENUM
+                | EXTERN_BLOCK
+                | EXTERN_CRATE
+                | FN
+                | IMPL
+                | MACRO_RULES
+                | MACRO_DEF
+                | MODULE
+                | STATIC
+                | STRUCT
+                | TRAIT
+                | TYPE_ALIAS
+                | UNION
+                | USE
+                | RECORD_FIELD
+                | TUPLE_FIELD
+                | VARIANT
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasDocComments { syntax })
@@ -3979,10 +4023,7 @@ pub fn new<T: ast::HasGenericParams>(node: T) -> AnyHasGenericParams {
 }
 impl AstNode for AnyHasGenericParams {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION => true,
-            _ => false,
-        }
+        matches!(kind, ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION)
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasGenericParams { syntax })
@@ -3996,12 +4037,7 @@ pub fn new<T: ast::HasLoopBody>(node: T) -> AnyHasLoopBody {
     }
 }
 impl AstNode for AnyHasLoopBody {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            FOR_EXPR | LOOP_EXPR | WHILE_EXPR => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FOR_EXPR | LOOP_EXPR | WHILE_EXPR) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasLoopBody { syntax })
     }
@@ -4014,12 +4050,7 @@ pub fn new<T: ast::HasModuleItem>(node: T) -> AnyHasModuleItem {
     }
 }
 impl AstNode for AnyHasModuleItem {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, MACRO_ITEMS | SOURCE_FILE | ITEM_LIST) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasModuleItem { syntax })
     }
@@ -4033,12 +4064,27 @@ pub fn new<T: ast::HasName>(node: T) -> AnyHasName {
 }
 impl AstNode for AnyHasName {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            CONST | ENUM | FN | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT
-            | TYPE_ALIAS | UNION | RENAME | SELF_PARAM | RECORD_FIELD | VARIANT | CONST_PARAM
-            | TYPE_PARAM | IDENT_PAT => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            CONST
+                | ENUM
+                | FN
+                | MACRO_RULES
+                | MACRO_DEF
+                | MODULE
+                | STATIC
+                | STRUCT
+                | TRAIT
+                | TYPE_ALIAS
+                | UNION
+                | RENAME
+                | SELF_PARAM
+                | RECORD_FIELD
+                | VARIANT
+                | CONST_PARAM
+                | TYPE_PARAM
+                | IDENT_PAT
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasName { syntax })
@@ -4053,10 +4099,10 @@ pub fn new<T: ast::HasTypeBounds>(node: T) -> AnyHasTypeBounds {
 }
 impl AstNode for AnyHasTypeBounds {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasTypeBounds { syntax })
@@ -4071,13 +4117,26 @@ pub fn new<T: ast::HasVisibility>(node: T) -> AnyHasVisibility {
 }
 impl AstNode for AnyHasVisibility {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            CONST | ENUM | EXTERN_CRATE | FN | IMPL | MACRO_RULES | MACRO_DEF | MODULE | STATIC
-            | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => {
-                true
-            }
-            _ => false,
-        }
+        matches!(
+            kind,
+            CONST
+                | ENUM
+                | EXTERN_CRATE
+                | FN
+                | IMPL
+                | MACRO_RULES
+                | MACRO_DEF
+                | MODULE
+                | STATIC
+                | STRUCT
+                | TRAIT
+                | TYPE_ALIAS
+                | UNION
+                | USE
+                | RECORD_FIELD
+                | TUPLE_FIELD
+                | VARIANT
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasVisibility { syntax })
index 037de876d45c94f16955502621129bc2872b2b85..83f8bbac5880bfd5fa542f03e90af2110039d169 100644 (file)
@@ -25,7 +25,7 @@ pub fn simple_ident_pat(name: ast::Name) -> ast::IdentPat {
         return from_text(&name.text());
 
         fn from_text(text: &str) -> ast::IdentPat {
-            ast_from_text(&format!("fn f({}: ())", text))
+            ast_from_text(&format!("fn f({text}: ())"))
         }
     }
     pub fn ident_path(ident: &str) -> ast::Path {
@@ -60,10 +60,10 @@ pub fn expr_todo() -> ast::Expr {
         expr_from_text("todo!()")
     }
     pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr {
-        expr_from_text(&format!("{}::default()", ty))
+        expr_from_text(&format!("{ty}::default()"))
     }
     pub fn expr_ty_new(ty: &ast::Type) -> ast::Expr {
-        expr_from_text(&format!("{}::new()", ty))
+        expr_from_text(&format!("{ty}::new()"))
     }
 
     pub fn zero_number() -> ast::Expr {
@@ -92,18 +92,20 @@ pub fn ty_bool() -> ast::Type {
         ty_path(ident_path("bool"))
     }
     pub fn ty_option(t: ast::Type) -> ast::Type {
-        ty_from_text(&format!("Option<{}>", t))
+        ty_from_text(&format!("Option<{t}>"))
     }
     pub fn ty_result(t: ast::Type, e: ast::Type) -> ast::Type {
-        ty_from_text(&format!("Result<{}, {}>", t, e))
+        ty_from_text(&format!("Result<{t}, {e}>"))
     }
 }
 
-pub fn name(text: &str) -> ast::Name {
-    ast_from_text(&format!("mod {}{};", raw_ident_esc(text), text))
+pub fn name(name: &str) -> ast::Name {
+    let raw_escape = raw_ident_esc(name);
+    ast_from_text(&format!("mod {raw_escape}{name};"))
 }
-pub fn name_ref(text: &str) -> ast::NameRef {
-    ast_from_text(&format!("fn f() {{ {}{}; }}", raw_ident_esc(text), text))
+pub fn name_ref(name_ref: &str) -> ast::NameRef {
+    let raw_escape = raw_ident_esc(name_ref);
+    ast_from_text(&format!("fn f() {{ {raw_escape}{name_ref}; }}"))
 }
 fn raw_ident_esc(ident: &str) -> &'static str {
     let is_keyword = parser::SyntaxKind::from_keyword(ident).is_some();
@@ -118,10 +120,10 @@ pub fn lifetime(text: &str) -> ast::Lifetime {
     let mut text = text;
     let tmp;
     if never!(!text.starts_with('\'')) {
-        tmp = format!("'{}", text);
+        tmp = format!("'{text}");
         text = &tmp;
     }
-    ast_from_text(&format!("fn f<{}>() {{ }}", text))
+    ast_from_text(&format!("fn f<{text}>() {{ }}"))
 }
 
 // FIXME: replace stringly-typed constructor with a family of typed ctors, a-la
@@ -142,16 +144,16 @@ pub fn ty_tuple(types: impl IntoIterator<Item = ast::Type>) -> ast::Type {
         contents.push(',');
     }
 
-    ty_from_text(&format!("({})", contents))
+    ty_from_text(&format!("({contents})"))
 }
 pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type {
-    ty_from_text(&if exclusive { format!("&mut {}", target) } else { format!("&{}", target) })
+    ty_from_text(&if exclusive { format!("&mut {target}") } else { format!("&{target}") })
 }
 pub fn ty_path(path: ast::Path) -> ast::Type {
     ty_from_text(&path.to_string())
 }
 fn ty_from_text(text: &str) -> ast::Type {
-    ast_from_text(&format!("type _T = {};", text))
+    ast_from_text(&format!("type _T = {text};"))
 }
 
 pub fn assoc_item_list() -> ast::AssocItemList {
@@ -171,7 +173,7 @@ pub fn impl_(
         Some(params) => params.to_string(),
         None => String::new(),
     };
-    ast_from_text(&format!("impl{} {}{} {{}}", params, ty, ty_params))
+    ast_from_text(&format!("impl{params} {ty}{ty_params} {{}}"))
 }
 
 pub fn impl_trait(
@@ -180,7 +182,7 @@ pub fn impl_trait(
     ty_params: Option<ast::GenericParamList>,
 ) -> ast::Impl {
     let ty_params = ty_params.map_or_else(String::new, |params| params.to_string());
-    ast_from_text(&format!("impl{2} {} for {}{2} {{}}", trait_, ty, ty_params))
+    ast_from_text(&format!("impl{ty_params} {trait_} for {ty}{ty_params} {{}}"))
 }
 
 pub(crate) fn generic_arg_list() -> ast::GenericArgList {
@@ -188,13 +190,13 @@ pub(crate) fn generic_arg_list() -> ast::GenericArgList {
 }
 
 pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
-    ast_from_text(&format!("type __ = {};", name_ref))
+    ast_from_text(&format!("type __ = {name_ref};"))
 }
 
 pub fn path_segment_ty(type_ref: ast::Type, trait_ref: Option<ast::PathType>) -> ast::PathSegment {
     let text = match trait_ref {
-        Some(trait_ref) => format!("fn f(x: <{} as {}>) {{}}", type_ref, trait_ref),
-        None => format!("fn f(x: <{}>) {{}}", type_ref),
+        Some(trait_ref) => format!("fn f(x: <{type_ref} as {trait_ref}>) {{}}"),
+        None => format!("fn f(x: <{type_ref}>) {{}}"),
     };
     ast_from_text(&text)
 }
@@ -212,15 +214,15 @@ pub fn path_segment_crate() -> ast::PathSegment {
 }
 
 pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path {
-    ast_from_text(&format!("type __ = {};", segment))
+    ast_from_text(&format!("type __ = {segment};"))
 }
 
 pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path {
-    ast_from_text(&format!("{}::{}", qual, segment))
+    ast_from_text(&format!("{qual}::{segment}"))
 }
 // FIXME: path concatenation operation doesn't make sense as AST op.
 pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path {
-    ast_from_text(&format!("type __ = {}::{};", first, second))
+    ast_from_text(&format!("type __ = {first}::{second};"))
 }
 
 pub fn path_from_segments(
@@ -229,20 +231,20 @@ pub fn path_from_segments(
 ) -> ast::Path {
     let segments = segments.into_iter().map(|it| it.syntax().clone()).join("::");
     ast_from_text(&if is_abs {
-        format!("fn f(x: ::{}) {{}}", segments)
+        format!("fn f(x: ::{segments}) {{}}")
     } else {
-        format!("fn f(x: {}) {{}}", segments)
+        format!("fn f(x: {segments}) {{}}")
     })
 }
 
 pub fn join_paths(paths: impl IntoIterator<Item = ast::Path>) -> ast::Path {
     let paths = paths.into_iter().map(|it| it.syntax().clone()).join("::");
-    ast_from_text(&format!("type __ = {};", paths))
+    ast_from_text(&format!("type __ = {paths};"))
 }
 
 // FIXME: should not be pub
 pub fn path_from_text(text: &str) -> ast::Path {
-    ast_from_text(&format!("fn main() {{ let test = {}; }}", text))
+    ast_from_text(&format!("fn main() {{ let test = {text}; }}"))
 }
 
 pub fn use_tree_glob() -> ast::UseTree {
@@ -257,50 +259,50 @@ pub fn use_tree(
     let mut buf = "use ".to_string();
     buf += &path.syntax().to_string();
     if let Some(use_tree_list) = use_tree_list {
-        format_to!(buf, "::{}", use_tree_list);
+        format_to!(buf, "::{use_tree_list}");
     }
     if add_star {
         buf += "::*";
     }
 
     if let Some(alias) = alias {
-        format_to!(buf, " {}", alias);
+        format_to!(buf, " {alias}");
     }
     ast_from_text(&buf)
 }
 
 pub fn use_tree_list(use_trees: impl IntoIterator<Item = ast::UseTree>) -> ast::UseTreeList {
     let use_trees = use_trees.into_iter().map(|it| it.syntax().clone()).join(", ");
-    ast_from_text(&format!("use {{{}}};", use_trees))
+    ast_from_text(&format!("use {{{use_trees}}};"))
 }
 
 pub fn use_(visibility: Option<ast::Visibility>, use_tree: ast::UseTree) -> ast::Use {
     let visibility = match visibility {
         None => String::new(),
-        Some(it) => format!("{} ", it),
+        Some(it) => format!("{it} "),
     };
-    ast_from_text(&format!("{}use {};", visibility, use_tree))
+    ast_from_text(&format!("{visibility}use {use_tree};"))
 }
 
 pub fn record_expr(path: ast::Path, fields: ast::RecordExprFieldList) -> ast::RecordExpr {
-    ast_from_text(&format!("fn f() {{ {} {} }}", path, fields))
+    ast_from_text(&format!("fn f() {{ {path} {fields} }}"))
 }
 
 pub fn record_expr_field_list(
     fields: impl IntoIterator<Item = ast::RecordExprField>,
 ) -> ast::RecordExprFieldList {
     let fields = fields.into_iter().join(", ");
-    ast_from_text(&format!("fn f() {{ S {{ {} }} }}", fields))
+    ast_from_text(&format!("fn f() {{ S {{ {fields} }} }}"))
 }
 
 pub fn record_expr_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField {
     return match expr {
-        Some(expr) => from_text(&format!("{}: {}", name, expr)),
+        Some(expr) => from_text(&format!("{name}: {expr}")),
         None => from_text(&name.to_string()),
     };
 
     fn from_text(text: &str) -> ast::RecordExprField {
-        ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text))
+        ast_from_text(&format!("fn f() {{ S {{ {text}, }} }}"))
     }
 }
 
@@ -311,9 +313,9 @@ pub fn record_field(
 ) -> ast::RecordField {
     let visibility = match visibility {
         None => String::new(),
-        Some(it) => format!("{} ", it),
+        Some(it) => format!("{it} "),
     };
-    ast_from_text(&format!("struct S {{ {}{}: {}, }}", visibility, name, ty))
+    ast_from_text(&format!("struct S {{ {visibility}{name}: {ty}, }}"))
 }
 
 // TODO
@@ -323,13 +325,13 @@ pub fn block_expr(
 ) -> ast::BlockExpr {
     let mut buf = "{\n".to_string();
     for stmt in stmts.into_iter() {
-        format_to!(buf, "    {}\n", stmt);
+        format_to!(buf, "    {stmt}\n");
     }
     if let Some(tail_expr) = tail_expr {
-        format_to!(buf, "    {}\n", tail_expr);
+        format_to!(buf, "    {tail_expr}\n");
     }
     buf += "}";
-    ast_from_text(&format!("fn f() {}", buf))
+    ast_from_text(&format!("fn f() {buf}"))
 }
 
 /// Ideally this function wouldn't exist since it involves manual indenting.
@@ -343,18 +345,18 @@ pub fn hacky_block_expr_with_comments(
     let mut buf = "{\n".to_string();
     for node_or_token in elements.into_iter() {
         match node_or_token {
-            rowan::NodeOrToken::Node(n) => format_to!(buf, "    {}\n", n),
+            rowan::NodeOrToken::Node(n) => format_to!(buf, "    {n}\n"),
             rowan::NodeOrToken::Token(t) if t.kind() == SyntaxKind::COMMENT => {
-                format_to!(buf, "    {}\n", t)
+                format_to!(buf, "    {t}\n")
             }
             _ => (),
         }
     }
     if let Some(tail_expr) = tail_expr {
-        format_to!(buf, "    {}\n", tail_expr);
+        format_to!(buf, "    {tail_expr}\n");
     }
     buf += "}";
-    ast_from_text(&format!("fn f() {}", buf))
+    ast_from_text(&format!("fn f() {buf}"))
 }
 
 pub fn expr_unit() -> ast::Expr {
@@ -362,7 +364,7 @@ pub fn expr_unit() -> ast::Expr {
 }
 pub fn expr_literal(text: &str) -> ast::Literal {
     assert_eq!(text.trim(), text);
-    ast_from_text(&format!("fn f() {{ let _ = {}; }}", text))
+    ast_from_text(&format!("fn f() {{ let _ = {text}; }}"))
 }
 
 pub fn expr_empty_block() -> ast::Expr {
@@ -373,41 +375,41 @@ pub fn expr_path(path: ast::Path) -> ast::Expr {
 }
 pub fn expr_continue(label: Option<ast::Lifetime>) -> ast::Expr {
     match label {
-        Some(label) => expr_from_text(&format!("continue {}", label)),
+        Some(label) => expr_from_text(&format!("continue {label}")),
         None => expr_from_text("continue"),
     }
 }
 // Consider `op: SyntaxKind` instead for nicer syntax at the call-site?
 pub fn expr_bin_op(lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::Expr {
-    expr_from_text(&format!("{} {} {}", lhs, op, rhs))
+    expr_from_text(&format!("{lhs} {op} {rhs}"))
 }
 pub fn expr_break(label: Option<ast::Lifetime>, expr: Option<ast::Expr>) -> ast::Expr {
     let mut s = String::from("break");
 
     if let Some(label) = label {
-        format_to!(s, " {}", label);
+        format_to!(s, " {label}");
     }
 
     if let Some(expr) = expr {
-        format_to!(s, " {}", expr);
+        format_to!(s, " {expr}");
     }
 
     expr_from_text(&s)
 }
 pub fn expr_return(expr: Option<ast::Expr>) -> ast::Expr {
     match expr {
-        Some(expr) => expr_from_text(&format!("return {}", expr)),
+        Some(expr) => expr_from_text(&format!("return {expr}")),
         None => expr_from_text("return"),
     }
 }
 pub fn expr_try(expr: ast::Expr) -> ast::Expr {
-    expr_from_text(&format!("{}?", expr))
+    expr_from_text(&format!("{expr}?"))
 }
 pub fn expr_await(expr: ast::Expr) -> ast::Expr {
-    expr_from_text(&format!("{}.await", expr))
+    expr_from_text(&format!("{expr}.await"))
 }
 pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
-    expr_from_text(&format!("match {} {}", expr, match_arm_list))
+    expr_from_text(&format!("match {expr} {match_arm_list}"))
 }
 pub fn expr_if(
     condition: ast::Expr,
@@ -415,66 +417,67 @@ pub fn expr_if(
     else_branch: Option<ast::ElseBranch>,
 ) -> ast::Expr {
     let else_branch = match else_branch {
-        Some(ast::ElseBranch::Block(block)) => format!("else {}", block),
-        Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {}", if_expr),
+        Some(ast::ElseBranch::Block(block)) => format!("else {block}"),
+        Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"),
         None => String::new(),
     };
-    expr_from_text(&format!("if {} {} {}", condition, then_branch, else_branch))
+    expr_from_text(&format!("if {condition} {then_branch} {else_branch}"))
 }
 pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::Expr {
-    expr_from_text(&format!("for {} in {} {}", pat, expr, block))
+    expr_from_text(&format!("for {pat} in {expr} {block}"))
 }
 
 pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr {
-    expr_from_text(&format!("loop {}", block))
+    expr_from_text(&format!("loop {block}"))
 }
 
 pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
     let token = token(op);
-    expr_from_text(&format!("{}{}", token, expr))
+    expr_from_text(&format!("{token}{expr}"))
 }
 pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr {
-    expr_from_text(&format!("{}{}", f, arg_list))
+    expr_from_text(&format!("{f}{arg_list}"))
 }
 pub fn expr_method_call(
     receiver: ast::Expr,
     method: ast::NameRef,
     arg_list: ast::ArgList,
 ) -> ast::Expr {
-    expr_from_text(&format!("{}.{}{}", receiver, method, arg_list))
+    expr_from_text(&format!("{receiver}.{method}{arg_list}"))
 }
 pub fn expr_macro_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr {
-    expr_from_text(&format!("{}!{}", f, arg_list))
+    expr_from_text(&format!("{f}!{arg_list}"))
 }
 pub fn expr_ref(expr: ast::Expr, exclusive: bool) -> ast::Expr {
-    expr_from_text(&if exclusive { format!("&mut {}", expr) } else { format!("&{}", expr) })
+    expr_from_text(&if exclusive { format!("&mut {expr}") } else { format!("&{expr}") })
 }
 pub fn expr_closure(pats: impl IntoIterator<Item = ast::Param>, expr: ast::Expr) -> ast::Expr {
     let params = pats.into_iter().join(", ");
-    expr_from_text(&format!("|{}| {}", params, expr))
+    expr_from_text(&format!("|{params}| {expr}"))
 }
 pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr {
-    expr_from_text(&format!("{}.{}", receiver, field))
+    expr_from_text(&format!("{receiver}.{field}"))
 }
 pub fn expr_paren(expr: ast::Expr) -> ast::Expr {
-    expr_from_text(&format!("({})", expr))
+    expr_from_text(&format!("({expr})"))
 }
 pub fn expr_tuple(elements: impl IntoIterator<Item = ast::Expr>) -> ast::Expr {
     let expr = elements.into_iter().format(", ");
-    expr_from_text(&format!("({})", expr))
+    expr_from_text(&format!("({expr})"))
 }
 pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
-    expr_from_text(&format!("{} = {}", lhs, rhs))
+    expr_from_text(&format!("{lhs} = {rhs}"))
 }
 fn expr_from_text(text: &str) -> ast::Expr {
-    ast_from_text(&format!("const C: () = {};", text))
+    ast_from_text(&format!("const C: () = {text};"))
 }
 pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
-    ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr))
+    ast_from_text(&format!("const _: () = while let {pattern} = {expr} {{}};"))
 }
 
 pub fn arg_list(args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
-    ast_from_text(&format!("fn main() {{ ()({}) }}", args.into_iter().format(", ")))
+    let args = args.into_iter().format(", ");
+    ast_from_text(&format!("fn main() {{ ()({args}) }}"))
 }
 
 pub fn ident_pat(ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat {
@@ -485,7 +488,7 @@ pub fn ident_pat(ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat {
     if mut_ {
         s.push_str("mut ");
     }
-    format_to!(s, "{}", name);
+    format_to!(s, "{name}");
     s.push_str(": ())");
     ast_from_text(&s)
 }
@@ -494,7 +497,7 @@ pub fn wildcard_pat() -> ast::WildcardPat {
     return from_text("_");
 
     fn from_text(text: &str) -> ast::WildcardPat {
-        ast_from_text(&format!("fn f({}: ())", text))
+        ast_from_text(&format!("fn f({text}: ())"))
     }
 }
 
@@ -502,7 +505,7 @@ pub fn literal_pat(lit: &str) -> ast::LiteralPat {
     return from_text(lit);
 
     fn from_text(text: &str) -> ast::LiteralPat {
-        ast_from_text(&format!("fn f() {{ match x {{ {} => {{}} }} }}", text))
+        ast_from_text(&format!("fn f() {{ match x {{ {text} => {{}} }} }}"))
     }
 }
 
@@ -515,10 +518,10 @@ pub fn tuple_pat(pats: impl IntoIterator<Item = ast::Pat>) -> ast::TuplePat {
     if count == 1 {
         pats_str.push(',');
     }
-    return from_text(&format!("({})", pats_str));
+    return from_text(&format!("({pats_str})"));
 
     fn from_text(text: &str) -> ast::TuplePat {
-        ast_from_text(&format!("fn f({}: ())", text))
+        ast_from_text(&format!("fn f({text}: ())"))
     }
 }
 
@@ -527,46 +530,46 @@ pub fn tuple_struct_pat(
     pats: impl IntoIterator<Item = ast::Pat>,
 ) -> ast::TupleStructPat {
     let pats_str = pats.into_iter().join(", ");
-    return from_text(&format!("{}({})", path, pats_str));
+    return from_text(&format!("{path}({pats_str})"));
 
     fn from_text(text: &str) -> ast::TupleStructPat {
-        ast_from_text(&format!("fn f({}: ())", text))
+        ast_from_text(&format!("fn f({text}: ())"))
     }
 }
 
 pub fn record_pat(path: ast::Path, pats: impl IntoIterator<Item = ast::Pat>) -> ast::RecordPat {
     let pats_str = pats.into_iter().join(", ");
-    return from_text(&format!("{} {{ {} }}", path, pats_str));
+    return from_text(&format!("{path} {{ {pats_str} }}"));
 
     fn from_text(text: &str) -> ast::RecordPat {
-        ast_from_text(&format!("fn f({}: ())", text))
+        ast_from_text(&format!("fn f({text}: ())"))
     }
 }
 
 pub fn record_pat_with_fields(path: ast::Path, fields: ast::RecordPatFieldList) -> ast::RecordPat {
-    ast_from_text(&format!("fn f({} {}: ()))", path, fields))
+    ast_from_text(&format!("fn f({path} {fields}: ()))"))
 }
 
 pub fn record_pat_field_list(
     fields: impl IntoIterator<Item = ast::RecordPatField>,
 ) -> ast::RecordPatFieldList {
     let fields = fields.into_iter().join(", ");
-    ast_from_text(&format!("fn f(S {{ {} }}: ()))", fields))
+    ast_from_text(&format!("fn f(S {{ {fields} }}: ()))"))
 }
 
 pub fn record_pat_field(name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPatField {
-    ast_from_text(&format!("fn f(S {{ {}: {} }}: ()))", name_ref, pat))
+    ast_from_text(&format!("fn f(S {{ {name_ref}: {pat} }}: ()))"))
 }
 
 pub fn record_pat_field_shorthand(name_ref: ast::NameRef) -> ast::RecordPatField {
-    ast_from_text(&format!("fn f(S {{ {} }}: ()))", name_ref))
+    ast_from_text(&format!("fn f(S {{ {name_ref} }}: ()))"))
 }
 
 /// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise.
 pub fn path_pat(path: ast::Path) -> ast::Pat {
     return from_text(&path.to_string());
     fn from_text(text: &str) -> ast::Pat {
-        ast_from_text(&format!("fn f({}: ())", text))
+        ast_from_text(&format!("fn f({text}: ())"))
     }
 }
 
@@ -577,12 +580,12 @@ pub fn match_arm(
 ) -> ast::MatchArm {
     let pats_str = pats.into_iter().join(" | ");
     return match guard {
-        Some(guard) => from_text(&format!("{} if {} => {}", pats_str, guard, expr)),
-        None => from_text(&format!("{} => {}", pats_str, expr)),
+        Some(guard) => from_text(&format!("{pats_str} if {guard} => {expr}")),
+        None => from_text(&format!("{pats_str} => {expr}")),
     };
 
     fn from_text(text: &str) -> ast::MatchArm {
-        ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
+        ast_from_text(&format!("fn f() {{ match () {{{text}}} }}"))
     }
 }
 
@@ -592,10 +595,10 @@ pub fn match_arm_with_guard(
     expr: ast::Expr,
 ) -> ast::MatchArm {
     let pats_str = pats.into_iter().join(" | ");
-    return from_text(&format!("{} if {} => {}", pats_str, guard, expr));
+    return from_text(&format!("{pats_str} if {guard} => {expr}"));
 
     fn from_text(text: &str) -> ast::MatchArm {
-        ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
+        ast_from_text(&format!("fn f() {{ match () {{{text}}} }}"))
     }
 }
 
@@ -605,13 +608,14 @@ pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::Mat
         .map(|arm| {
             let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like());
             let comma = if needs_comma { "," } else { "" };
-            format!("    {}{}\n", arm.syntax(), comma)
+            let arm = arm.syntax();
+            format!("    {arm}{comma}\n")
         })
         .collect::<String>();
     return from_text(&arms_str);
 
     fn from_text(text: &str) -> ast::MatchArmList {
-        ast_from_text(&format!("fn f() {{ match () {{\n{}}} }}", text))
+        ast_from_text(&format!("fn f() {{ match () {{\n{text}}} }}"))
     }
 }
 
@@ -620,10 +624,10 @@ pub fn where_pred(
     bounds: impl IntoIterator<Item = ast::TypeBound>,
 ) -> ast::WherePred {
     let bounds = bounds.into_iter().join(" + ");
-    return from_text(&format!("{}: {}", path, bounds));
+    return from_text(&format!("{path}: {bounds}"));
 
     fn from_text(text: &str) -> ast::WherePred {
-        ast_from_text(&format!("fn f() where {} {{ }}", text))
+        ast_from_text(&format!("fn f() where {text} {{ }}"))
     }
 }
 
@@ -632,7 +636,7 @@ pub fn where_clause(preds: impl IntoIterator<Item = ast::WherePred>) -> ast::Whe
     return from_text(preds.as_str());
 
     fn from_text(text: &str) -> ast::WhereClause {
-        ast_from_text(&format!("fn f() where {} {{ }}", text))
+        ast_from_text(&format!("fn f() where {text} {{ }}"))
     }
 }
 
@@ -642,19 +646,19 @@ pub fn let_stmt(
     initializer: Option<ast::Expr>,
 ) -> ast::LetStmt {
     let mut text = String::new();
-    format_to!(text, "let {}", pattern);
+    format_to!(text, "let {pattern}");
     if let Some(ty) = ty {
-        format_to!(text, ": {}", ty);
+        format_to!(text, ": {ty}");
     }
     match initializer {
-        Some(it) => format_to!(text, " = {};", it),
+        Some(it) => format_to!(text, " = {it};"),
         None => format_to!(text, ";"),
     };
-    ast_from_text(&format!("fn f() {{ {} }}", text))
+    ast_from_text(&format!("fn f() {{ {text} }}"))
 }
 pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt {
     let semi = if expr.is_block_like() { "" } else { ";" };
-    ast_from_text(&format!("fn f() {{ {}{} (); }}", expr, semi))
+    ast_from_text(&format!("fn f() {{ {expr}{semi} (); }}"))
 }
 
 pub fn item_const(
@@ -665,13 +669,13 @@ pub fn item_const(
 ) -> ast::Const {
     let visibility = match visibility {
         None => String::new(),
-        Some(it) => format!("{} ", it),
+        Some(it) => format!("{it} "),
     };
-    ast_from_text(&format!("{} const {}: {} = {};", visibility, name, ty, expr))
+    ast_from_text(&format!("{visibility} const {name}: {ty} = {expr};"))
 }
 
 pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param {
-    ast_from_text(&format!("fn f({}: {}) {{ }}", pat, ty))
+    ast_from_text(&format!("fn f({pat}: {ty}) {{ }}"))
 }
 
 pub fn self_param() -> ast::SelfParam {
@@ -679,7 +683,7 @@ pub fn self_param() -> ast::SelfParam {
 }
 
 pub fn ret_type(ty: ast::Type) -> ast::RetType {
-    ast_from_text(&format!("fn f() -> {} {{ }}", ty))
+    ast_from_text(&format!("fn f() -> {ty} {{ }}"))
 }
 
 pub fn param_list(
@@ -688,30 +692,30 @@ pub fn param_list(
 ) -> ast::ParamList {
     let args = pats.into_iter().join(", ");
     let list = match self_param {
-        Some(self_param) if args.is_empty() => format!("fn f({}) {{ }}", self_param),
-        Some(self_param) => format!("fn f({}, {}) {{ }}", self_param, args),
-        None => format!("fn f({}) {{ }}", args),
+        Some(self_param) if args.is_empty() => format!("fn f({self_param}) {{ }}"),
+        Some(self_param) => format!("fn f({self_param}, {args}) {{ }}"),
+        None => format!("fn f({args}) {{ }}"),
     };
     ast_from_text(&list)
 }
 
 pub fn type_param(name: ast::Name, ty: Option<ast::TypeBoundList>) -> ast::TypeParam {
     let bound = match ty {
-        Some(it) => format!(": {}", it),
+        Some(it) => format!(": {it}"),
         None => String::new(),
     };
-    ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound))
+    ast_from_text(&format!("fn f<{name}{bound}>() {{ }}"))
 }
 
 pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam {
-    ast_from_text(&format!("fn f<{}>() {{ }}", lifetime))
+    ast_from_text(&format!("fn f<{lifetime}>() {{ }}"))
 }
 
 pub fn generic_param_list(
     pats: impl IntoIterator<Item = ast::GenericParam>,
 ) -> ast::GenericParamList {
     let args = pats.into_iter().join(", ");
-    ast_from_text(&format!("fn f<{}>() {{ }}", args))
+    ast_from_text(&format!("fn f<{args}>() {{ }}"))
 }
 
 pub fn visibility_pub_crate() -> ast::Visibility {
@@ -724,33 +728,33 @@ pub fn visibility_pub() -> ast::Visibility {
 
 pub fn tuple_field_list(fields: impl IntoIterator<Item = ast::TupleField>) -> ast::TupleFieldList {
     let fields = fields.into_iter().join(", ");
-    ast_from_text(&format!("struct f({});", fields))
+    ast_from_text(&format!("struct f({fields});"))
 }
 
 pub fn record_field_list(
     fields: impl IntoIterator<Item = ast::RecordField>,
 ) -> ast::RecordFieldList {
     let fields = fields.into_iter().join(", ");
-    ast_from_text(&format!("struct f {{ {} }}", fields))
+    ast_from_text(&format!("struct f {{ {fields} }}"))
 }
 
 pub fn tuple_field(visibility: Option<ast::Visibility>, ty: ast::Type) -> ast::TupleField {
     let visibility = match visibility {
         None => String::new(),
-        Some(it) => format!("{} ", it),
+        Some(it) => format!("{it} "),
     };
-    ast_from_text(&format!("struct f({}{});", visibility, ty))
+    ast_from_text(&format!("struct f({visibility}{ty});"))
 }
 
 pub fn variant(name: ast::Name, field_list: Option<ast::FieldList>) -> ast::Variant {
     let field_list = match field_list {
         None => String::new(),
         Some(it) => match it {
-            ast::FieldList::RecordFieldList(record) => format!(" {}", record),
-            ast::FieldList::TupleFieldList(tuple) => format!("{}", tuple),
+            ast::FieldList::RecordFieldList(record) => format!(" {record}"),
+            ast::FieldList::TupleFieldList(tuple) => format!("{tuple}"),
         },
     };
-    ast_from_text(&format!("enum f {{ {}{} }}", name, field_list))
+    ast_from_text(&format!("enum f {{ {name}{field_list} }}"))
 }
 
 pub fn fn_(
@@ -763,23 +767,22 @@ pub fn fn_(
     is_async: bool,
 ) -> ast::Fn {
     let type_params = match type_params {
-        Some(type_params) => format!("{}", type_params),
+        Some(type_params) => format!("{type_params}"),
         None => "".into(),
     };
     let ret_type = match ret_type {
-        Some(ret_type) => format!("{} ", ret_type),
+        Some(ret_type) => format!("{ret_type} "),
         None => "".into(),
     };
     let visibility = match visibility {
         None => String::new(),
-        Some(it) => format!("{} ", it),
+        Some(it) => format!("{it} "),
     };
 
     let async_literal = if is_async { "async " } else { "" };
 
     ast_from_text(&format!(
-        "{}{}fn {}{}{} {}{}",
-        visibility, async_literal, fn_name, type_params, params, ret_type, body
+        "{visibility}{async_literal}fn {fn_name}{type_params}{params} {ret_type}{body}",
     ))
 }
 
@@ -793,13 +796,10 @@ pub fn struct_(
     let type_params = generic_param_list.map_or_else(String::new, |it| it.to_string());
     let visibility = match visibility {
         None => String::new(),
-        Some(it) => format!("{} ", it),
+        Some(it) => format!("{it} "),
     };
 
-    ast_from_text(&format!(
-        "{}struct {}{}{}{}",
-        visibility, strukt_name, type_params, field_list, semicolon
-    ))
+    ast_from_text(&format!("{visibility}struct {strukt_name}{type_params}{field_list}{semicolon}",))
 }
 
 #[track_caller]
@@ -808,7 +808,8 @@ fn ast_from_text<N: AstNode>(text: &str) -> N {
     let node = match parse.tree().syntax().descendants().find_map(N::cast) {
         Some(it) => it,
         None => {
-            panic!("Failed to make ast node `{}` from text {}", std::any::type_name::<N>(), text)
+            let node = std::any::type_name::<N>();
+            panic!("Failed to make ast node `{node}` from text {text}")
         }
     };
     let node = node.clone_subtree();
@@ -824,7 +825,7 @@ pub fn token(kind: SyntaxKind) -> SyntaxToken {
         .descendants_with_tokens()
         .filter_map(|it| it.into_token())
         .find(|it| it.kind() == kind)
-        .unwrap_or_else(|| panic!("unhandled token: {:?}", kind))
+        .unwrap_or_else(|| panic!("unhandled token: {kind:?}"))
 }
 
 pub mod tokens {
@@ -863,7 +864,7 @@ pub fn doc_comment(text: &str) -> SyntaxToken {
 
     pub fn literal(text: &str) -> SyntaxToken {
         assert_eq!(text.trim(), text);
-        let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {}; }}", text));
+        let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {text}; }}"));
         lit.syntax().first_child_or_token().unwrap().into_token().unwrap()
     }
 
index 28976d837b88a142e44d26c06a11d2108606d24c..ba72e64425b23c095063a54e3aa7cf1edef2e618 100644 (file)
@@ -322,7 +322,7 @@ pub fn suffix(&self) -> Option<&str> {
 
     pub fn float_value(&self) -> Option<f64> {
         let (_, text, _) = self.split_into_parts();
-        text.parse::<f64>().ok()
+        text.replace('_', "").parse::<f64>().ok()
     }
 }
 
@@ -361,7 +361,7 @@ pub fn suffix(&self) -> Option<&str> {
 
     pub fn value(&self) -> Option<f64> {
         let (text, _) = self.split_into_parts();
-        text.parse::<f64>().ok()
+        text.replace('_', "").parse::<f64>().ok()
     }
 }
 
@@ -397,6 +397,15 @@ fn check_int_suffix<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
         assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into());
     }
 
+    fn check_float_value(lit: &str, expected: impl Into<Option<f64>> + Copy) {
+        assert_eq!(FloatNumber { syntax: make::tokens::literal(lit) }.value(), expected.into());
+        assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.float_value(), expected.into());
+    }
+
+    fn check_int_value(lit: &str, expected: impl Into<Option<u128>>) {
+        assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.value(), expected.into());
+    }
+
     #[test]
     fn test_float_number_suffix() {
         check_float_suffix("123.0", None);
@@ -437,6 +446,14 @@ fn test_string_escape() {
         check_string_value(r"\nfoobar", "\nfoobar");
         check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\");
     }
+
+    #[test]
+    fn test_value_underscores() {
+        check_float_value("3.141592653589793_f64", 3.141592653589793_f64);
+        check_float_value("1__0.__0__f32", 10.0);
+        check_int_value("0b__1_0_", 2);
+        check_int_value("1_1_1_1_1_1", 111111);
+    }
 }
 
 impl ast::Char {
index 6d2766225103f7b0aa2406a99939031a973b7274..70b54843dbaab5d6f328d18546e8cac979fd25f6 100644 (file)
@@ -169,10 +169,7 @@ fn syntax(&self) -> &SyntaxNode { &self.syntax }
                 quote! {
                     impl AstNode for #name {
                         fn can_cast(kind: SyntaxKind) -> bool {
-                            match kind {
-                                #(#kinds)|* => true,
-                                _ => false,
-                            }
+                            matches!(kind, #(#kinds)|*)
                         }
                         fn cast(syntax: SyntaxNode) -> Option<Self> {
                             let res = match syntax.kind() {
@@ -253,10 +250,7 @@ pub fn new<T: ast::#trait_name>(node: T) -> #name {
                     }
                     impl AstNode for #name {
                         fn can_cast(kind: SyntaxKind) -> bool {
-                            match kind {
-                                #(#kinds)|* => true,
-                                _ => false,
-                            }
+                            matches!(kind, #(#kinds)|*)
                         }
                         fn cast(syntax: SyntaxNode) -> Option<Self> {
                             Self::can_cast(syntax.kind()).then(|| #name { syntax })
@@ -410,24 +404,17 @@ pub enum SyntaxKind {
 
         impl SyntaxKind {
             pub fn is_keyword(self) -> bool {
-                match self {
-                    #(#all_keywords)|* => true,
-                    _ => false,
-                }
+                matches!(self, #(#all_keywords)|*)
             }
 
             pub fn is_punct(self) -> bool {
-                match self {
-                    #(#punctuation)|* => true,
-                    _ => false,
-                }
+
+                matches!(self, #(#punctuation)|*)
+
             }
 
             pub fn is_literal(self) -> bool {
-                match self {
-                    #(#literals)|* => true,
-                    _ => false,
-                }
+                matches!(self, #(#literals)|*)
             }
 
             pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {
index 50e8d06b66049795bedc69b320bad4be62d7a811..ccaaf3991769ec737833da7eb0bec769d36a501a 100644 (file)
@@ -322,6 +322,43 @@ pub fn iter_mut(
             .map(|(idx, value)| (Idx::from_raw(RawIdx(idx as u32)), value))
     }
 
+    /// Returns an iterator over the arena’s values.
+    ///
+    /// ```
+    /// let mut arena = la_arena::Arena::new();
+    /// let idx1 = arena.alloc(20);
+    /// let idx2 = arena.alloc(40);
+    /// let idx3 = arena.alloc(60);
+    ///
+    /// let mut iterator = arena.values();
+    /// assert_eq!(iterator.next(), Some(&20));
+    /// assert_eq!(iterator.next(), Some(&40));
+    /// assert_eq!(iterator.next(), Some(&60));
+    /// ```
+    pub fn values(&mut self) -> impl Iterator<Item = &T> + ExactSizeIterator + DoubleEndedIterator {
+        self.data.iter()
+    }
+
+    /// Returns an iterator over the arena’s mutable values.
+    ///
+    /// ```
+    /// let mut arena = la_arena::Arena::new();
+    /// let idx1 = arena.alloc(20);
+    ///
+    /// assert_eq!(arena[idx1], 20);
+    ///
+    /// let mut iterator = arena.values_mut();
+    /// *iterator.next().unwrap() = 10;
+    /// drop(iterator);
+    ///
+    /// assert_eq!(arena[idx1], 10);
+    /// ```
+    pub fn values_mut(
+        &mut self,
+    ) -> impl Iterator<Item = &mut T> + ExactSizeIterator + DoubleEndedIterator {
+        self.data.iter_mut()
+    }
+
     /// Reallocates the arena to make it take up as little space as possible.
     pub fn shrink_to_fit(&mut self) {
         self.data.shrink_to_fit();
index de292d3305db812cd5113b444dda39b32eff8e55..b306a527a7ce11f74e9de546a99f870e02f8ff29 100644 (file)
@@ -199,8 +199,7 @@ pub fn check(
         if channel != "nightly" && since == Version::CurrentPlaceholder {
             tidy_error!(
                 bad,
-                "The placeholder use of {kind} feature `{feature_name}` is not allowed on the {} channel",
-                version::VERSION_PLACEHOLDER
+                "The placeholder use of {kind} feature `{feature_name}` is not allowed on the {channel} channel",
             );
         }
     }