]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #101154 - RalfJung:validation-perf, r=oli-obk
authorbors <bors@rust-lang.org>
Sat, 3 Sep 2022 09:20:54 +0000 (09:20 +0000)
committerbors <bors@rust-lang.org>
Sat, 3 Sep 2022 09:20:54 +0000 (09:20 +0000)
interpret: fix unnecessary allocation in validation visitor

Should fix the perf regression introduced by https://github.com/rust-lang/rust/pull/100043.

r? `@oli-obk`

1252 files changed:
.gitignore
Cargo.lock
RELEASES.md
compiler/rustc_arena/src/lib.rs
compiler/rustc_ast/Cargo.toml
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/ast_traits.rs
compiler/rustc_ast/src/lib.rs
compiler/rustc_ast/src/tokenstream.rs
compiler/rustc_ast/src/util/literal.rs
compiler/rustc_ast_lowering/Cargo.toml
compiler/rustc_ast_lowering/src/errors.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/index.rs
compiler/rustc_ast_lowering/src/lib.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_ast_passes/src/feature_gate.rs
compiler/rustc_ast_passes/src/lib.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_attr/src/lib.rs
compiler/rustc_borrowck/src/constraints/mod.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_name.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/places_conflict.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/region_infer/opaque_types.rs
compiler/rustc_borrowck/src/type_check/canonical.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_borrowck/src/universal_regions.rs
compiler/rustc_builtin_macros/Cargo.toml
compiler/rustc_builtin_macros/src/assert/context.rs
compiler/rustc_builtin_macros/src/deriving/clone.rs
compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
compiler/rustc_builtin_macros/src/deriving/default.rs
compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_builtin_macros/src/global_allocator.rs
compiler/rustc_builtin_macros/src/lib.rs
compiler/rustc_builtin_macros/src/standard_library_imports.rs
compiler/rustc_builtin_macros/src/test.rs
compiler/rustc_builtin_macros/src/test_harness.rs
compiler/rustc_codegen_cranelift/src/abi/mod.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
compiler/rustc_codegen_cranelift/src/main_shim.rs
compiler/rustc_codegen_gcc/src/builder.rs
compiler/rustc_codegen_gcc/src/consts.rs
compiler/rustc_codegen_gcc/src/lib.rs
compiler/rustc_codegen_llvm/Cargo.toml
compiler/rustc_codegen_llvm/src/asm.rs
compiler/rustc_codegen_llvm/src/back/archive.rs
compiler/rustc_codegen_llvm/src/back/lto.rs
compiler/rustc_codegen_llvm/src/back/write.rs
compiler/rustc_codegen_llvm/src/builder.rs
compiler/rustc_codegen_llvm/src/callee.rs
compiler/rustc_codegen_llvm/src/common.rs
compiler/rustc_codegen_llvm/src/consts.rs
compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
compiler/rustc_codegen_llvm/src/declare.rs
compiler/rustc_codegen_llvm/src/lib.rs
compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs
compiler/rustc_codegen_llvm/src/llvm/ffi.rs
compiler/rustc_codegen_llvm/src/llvm_util.rs
compiler/rustc_codegen_llvm/src/mono_item.rs
compiler/rustc_codegen_llvm/src/type_of.rs
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/linker.rs
compiler/rustc_codegen_ssa/src/back/symbol_export.rs
compiler/rustc_codegen_ssa/src/back/write.rs
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/meth.rs
compiler/rustc_codegen_ssa/src/mir/mod.rs
compiler/rustc_codegen_ssa/src/mir/place.rs
compiler/rustc_codegen_ssa/src/traits/builder.rs
compiler/rustc_const_eval/src/const_eval/error.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/const_eval/machine.rs
compiler/rustc_const_eval/src/const_eval/valtrees.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/intern.rs
compiler/rustc_const_eval/src/interpret/intrinsics.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/interpret/projection.rs
compiler/rustc_const_eval/src/interpret/step.rs
compiler/rustc_const_eval/src/interpret/terminator.rs
compiler/rustc_const_eval/src/interpret/traits.rs
compiler/rustc_const_eval/src/interpret/validity.rs
compiler/rustc_const_eval/src/lib.rs
compiler/rustc_const_eval/src/transform/promote_consts.rs
compiler/rustc_const_eval/src/transform/validate.rs
compiler/rustc_data_structures/Cargo.toml
compiler/rustc_data_structures/src/fingerprint.rs
compiler/rustc_data_structures/src/lib.rs
compiler/rustc_data_structures/src/map_in_place.rs
compiler/rustc_data_structures/src/sorted_map.rs
compiler/rustc_data_structures/src/thin_vec.rs [deleted file]
compiler/rustc_data_structures/src/thin_vec/tests.rs [deleted file]
compiler/rustc_driver/Cargo.toml
compiler/rustc_driver/src/pretty.rs
compiler/rustc_driver/src/session_diagnostics.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/driver.ftl
compiler/rustc_error_messages/locales/en-US/metadata.ftl [new file with mode: 0644]
compiler/rustc_error_messages/locales/en-US/monomorphize.ftl [new file with mode: 0644]
compiler/rustc_error_messages/locales/en-US/privacy.ftl
compiler/rustc_error_messages/locales/en-US/query_system.ftl [new file with mode: 0644]
compiler/rustc_error_messages/locales/en-US/session.ftl [new file with mode: 0644]
compiler/rustc_error_messages/locales/en-US/symbol_mangling.ftl [new file with mode: 0644]
compiler/rustc_error_messages/locales/en-US/trait_selection.ftl [new file with mode: 0644]
compiler/rustc_error_messages/src/lib.rs
compiler/rustc_errors/Cargo.toml
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/diagnostic_builder.rs
compiler/rustc_errors/src/emitter.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_errors/src/translation.rs
compiler/rustc_expand/src/lib.rs
compiler/rustc_expand/src/mbe/macro_parser.rs
compiler/rustc_expand/src/mbe/macro_rules.rs
compiler/rustc_expand/src/proc_macro_server.rs
compiler/rustc_feature/src/accepted.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_feature/src/removed.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_hir/src/definitions.rs
compiler/rustc_hir/src/errors.rs [new file with mode: 0644]
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir/src/lib.rs
compiler/rustc_infer/src/infer/at.rs
compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
compiler/rustc_infer/src/infer/canonical/query_response.rs
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/find_anon_type.rs
compiler/rustc_infer/src/infer/higher_ranked/mod.rs
compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/nll_relate/mod.rs
compiler/rustc_infer/src/infer/opaque_types.rs
compiler/rustc_infer/src/infer/opaque_types/table.rs
compiler/rustc_infer/src/infer/outlives/mod.rs
compiler/rustc_infer/src/infer/outlives/obligations.rs
compiler/rustc_infer/src/infer/outlives/test_type_match.rs
compiler/rustc_infer/src/infer/sub.rs
compiler/rustc_infer/src/infer/undo_log.rs
compiler/rustc_infer/src/lib.rs
compiler/rustc_interface/src/interface.rs
compiler/rustc_interface/src/lib.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/queries.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_interface/src/util.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/early.rs
compiler/rustc_lint/src/internal.rs
compiler/rustc_lint/src/late.rs
compiler/rustc_lint/src/let_underscore.rs [new file with mode: 0644]
compiler/rustc_lint/src/levels.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint/src/passes.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_lint_defs/src/lib.rs
compiler/rustc_llvm/build.rs
compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
compiler/rustc_macros/src/lib.rs
compiler/rustc_metadata/src/creader.rs
compiler/rustc_metadata/src/dependency_format.rs
compiler/rustc_metadata/src/errors.rs [new file with mode: 0644]
compiler/rustc_metadata/src/fs.rs
compiler/rustc_metadata/src/lib.rs
compiler/rustc_metadata/src/locator.rs
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/Cargo.toml
compiler/rustc_middle/src/arena.rs
compiler/rustc_middle/src/dep_graph/dep_node.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/middle/lang_items.rs
compiler/rustc_middle/src/middle/resolve_lifetime.rs
compiler/rustc_middle/src/mir/basic_blocks.rs
compiler/rustc_middle/src/mir/interpret/allocation.rs
compiler/rustc_middle/src/mir/interpret/error.rs
compiler/rustc_middle/src/mir/interpret/mod.rs
compiler/rustc_middle/src/mir/interpret/pointer.rs
compiler/rustc_middle/src/mir/interpret/value.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/pretty.rs
compiler/rustc_middle/src/mir/syntax.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/thir/visit.rs
compiler/rustc_middle/src/traits/specialization_graph.rs
compiler/rustc_middle/src/ty/consts.rs
compiler/rustc_middle/src/ty/consts/kind.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/fold.rs
compiler/rustc_middle/src/ty/generics.rs
compiler/rustc_middle/src/ty/impls_ty.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
compiler/rustc_middle/src/ty/parameterized.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/trait_def.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_middle/src/ty/visit.rs
compiler/rustc_mir_build/src/build/block.rs
compiler/rustc_mir_build/src/build/expr/as_constant.rs
compiler/rustc_mir_build/src/build/expr/as_place.rs
compiler/rustc_mir_build/src/build/expr/into.rs
compiler/rustc_mir_build/src/build/matches/mod.rs
compiler/rustc_mir_build/src/build/matches/simplify.rs
compiler/rustc_mir_build/src/build/matches/test.rs
compiler/rustc_mir_build/src/build/matches/util.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/check_unsafety.rs
compiler/rustc_mir_build/src/lib.rs
compiler/rustc_mir_build/src/thir/cx/block.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_mir_build/src/thir/cx/mod.rs
compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
compiler/rustc_mir_build/src/thir/pattern/mod.rs
compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/const_prop_lint.rs
compiler/rustc_mir_transform/src/deaggregator.rs
compiler/rustc_mir_transform/src/deref_separator.rs
compiler/rustc_mir_transform/src/elaborate_drops.rs
compiler/rustc_mir_transform/src/generator.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/pass_manager.rs
compiler/rustc_mir_transform/src/shim.rs
compiler/rustc_monomorphize/Cargo.toml
compiler/rustc_monomorphize/src/collector.rs
compiler/rustc_monomorphize/src/errors.rs [new file with mode: 0644]
compiler/rustc_monomorphize/src/lib.rs
compiler/rustc_monomorphize/src/partitioning/mod.rs
compiler/rustc_monomorphize/src/polymorphize.rs
compiler/rustc_monomorphize/src/util.rs
compiler/rustc_parse/src/lexer/mod.rs
compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
compiler/rustc_parse/src/lib.rs
compiler/rustc_parse/src/parser/attr.rs
compiler/rustc_parse/src/parser/attr_wrapper.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/path.rs
compiler/rustc_parse_format/src/lib.rs
compiler/rustc_parse_format/src/tests.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/entry.rs
compiler/rustc_passes/src/hir_stats.rs
compiler/rustc_passes/src/lib.rs
compiler/rustc_passes/src/lib_features.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_privacy/src/errors.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_impl/Cargo.toml
compiler/rustc_query_impl/src/plumbing.rs
compiler/rustc_query_system/Cargo.toml
compiler/rustc_query_system/src/error.rs [new file with mode: 0644]
compiler/rustc_query_system/src/lib.rs
compiler/rustc_query_system/src/query/config.rs
compiler/rustc_query_system/src/query/job.rs
compiler/rustc_query_system/src/query/mod.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_resolve/src/access_levels.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/def_collector.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/ident.rs
compiler/rustc_resolve/src/imports.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_resolve/src/macros.rs
compiler/rustc_save_analysis/src/dump_visitor.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_serialize/Cargo.toml
compiler/rustc_serialize/src/collection_impls.rs
compiler/rustc_session/src/cgu_reuse_tracker.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/config/sigpipe.rs [new file with mode: 0644]
compiler/rustc_session/src/errors.rs [new file with mode: 0644]
compiler/rustc_session/src/filesearch.rs
compiler/rustc_session/src/lib.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/parse.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/Cargo.toml
compiler/rustc_symbol_mangling/src/errors.rs [new file with mode: 0644]
compiler/rustc_symbol_mangling/src/legacy.rs
compiler/rustc_symbol_mangling/src/lib.rs
compiler/rustc_symbol_mangling/src/test.rs
compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs
compiler/rustc_target/src/spec/android_base.rs
compiler/rustc_target/src/spec/apple_base.rs
compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
compiler/rustc_target/src/spec/avr_gnu_base.rs
compiler/rustc_target/src/spec/bpf_base.rs
compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
compiler/rustc_target/src/spec/l4re_base.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/msvc_base.rs
compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
compiler/rustc_target/src/spec/riscv64gc_unknown_openbsd.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/tests/tests_impl.rs
compiler/rustc_target/src/spec/uefi_msvc_base.rs
compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
compiler/rustc_target/src/spec/windows_gnullvm_base.rs
compiler/rustc_target/src/spec/windows_msvc_base.rs
compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
compiler/rustc_target/src/spec/x86_64_unknown_none.rs
compiler/rustc_trait_selection/src/autoderef.rs
compiler/rustc_trait_selection/src/errors.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/lib.rs
compiler/rustc_trait_selection/src/traits/auto_trait.rs
compiler/rustc_trait_selection/src/traits/codegen.rs
compiler/rustc_trait_selection/src/traits/engine.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/fulfill.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_trait_selection/src/traits/specialize/mod.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_traits/src/chalk/lowering.rs
compiler/rustc_traits/src/type_op.rs
compiler/rustc_transmute/src/layout/tree.rs
compiler/rustc_transmute/src/maybe_transmutable/mod.rs
compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
compiler/rustc_ty_utils/src/consts.rs
compiler/rustc_ty_utils/src/instance.rs
compiler/rustc_ty_utils/src/ty.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/_match.rs
compiler/rustc_typeck/src/check/check.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/fn_ctxt/checks.rs
compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
compiler/rustc_typeck/src/check/generator_interior.rs
compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
compiler/rustc_typeck/src/check/inherited.rs
compiler/rustc_typeck/src/check/method/mod.rs
compiler/rustc_typeck/src/check/method/probe.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/wfcheck.rs
compiler/rustc_typeck/src/check/writeback.rs
compiler/rustc_typeck/src/coherence/builtin.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
compiler/rustc_typeck/src/errors.rs
compiler/rustc_typeck/src/expr_use_visitor.rs
compiler/rustc_typeck/src/hir_wf_check.rs
compiler/rustc_typeck/src/lib.rs
compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
config.toml.example
library/alloc/src/collections/linked_list.rs
library/alloc/src/vec/drain.rs
library/alloc/src/vec/drain_filter.rs
library/alloc/src/vec/into_iter.rs
library/alloc/src/vec/mod.rs
library/alloc/tests/lib.rs
library/alloc/tests/vec.rs
library/core/src/any.rs
library/core/src/fmt/builders.rs
library/core/src/hint.rs
library/core/src/intrinsics.rs
library/core/src/macros/mod.rs
library/core/src/mem/maybe_uninit.rs
library/core/src/mem/mod.rs
library/core/src/num/nonzero.rs
library/core/src/ops/range.rs
library/core/src/primitive_docs.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mod.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/slice/iter.rs
library/core/src/slice/iter/macros.rs
library/core/src/slice/mod.rs
library/core/src/time.rs
library/core/tests/any.rs
library/core/tests/atomic.rs
library/core/tests/ptr.rs
library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs
library/proc_macro/src/bridge/client.rs
library/proc_macro/src/bridge/mod.rs
library/proc_macro/src/bridge/server.rs
library/proc_macro/src/diagnostic.rs
library/std/src/collections/hash/set.rs
library/std/src/fs.rs
library/std/src/io/error/repr_bitpacked.rs
library/std/src/io/mod.rs
library/std/src/io/stdio.rs
library/std/src/keyword_docs.rs
library/std/src/lib.rs
library/std/src/primitive_docs.rs
library/std/src/rt.rs
library/std/src/sync/mutex.rs
library/std/src/sync/rwlock.rs
library/std/src/sys/hermit/mod.rs
library/std/src/sys/sgx/mod.rs
library/std/src/sys/solid/mod.rs
library/std/src/sys/unix/locks/fuchsia_mutex.rs
library/std/src/sys/unix/locks/futex_mutex.rs
library/std/src/sys/unix/locks/futex_rwlock.rs
library/std/src/sys/unix/mod.rs
library/std/src/sys/unix/rand.rs
library/std/src/sys/unsupported/common.rs
library/std/src/sys/wasi/stdio.rs
library/std/src/sys/windows/c.rs
library/std/src/sys/windows/cmath.rs
library/std/src/sys/windows/compat.rs
library/std/src/sys/windows/fs.rs
library/std/src/sys/windows/mod.rs
library/std/src/sys/windows/path/tests.rs
library/std/src/sys/windows/rand.rs
library/std/src/sys/windows/stdio.rs
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/test.rs
src/ci/docker/host-x86_64/arm-android/Dockerfile
src/ci/docker/host-x86_64/dist-android/Dockerfile
src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
src/ci/docker/host-x86_64/i686-gnu/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
src/ci/docker/scripts/android-base-apt-get.sh
src/doc/book
src/doc/nomicon
src/doc/reference
src/doc/rustc-dev-guide
src/doc/rustc/src/platform-support.md
src/doc/rustc/src/platform-support/armv4t-none-eabi.md [new file with mode: 0644]
src/doc/rustc/src/platform-support/armv4t_none_eabi.md [deleted file]
src/doc/rustc/src/platform-support/fuchsia.md
src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md
src/doc/rustc/src/platform-support/openbsd.md
src/doc/rustc/src/platform-support/pc-windows-gnullvm.md
src/doc/rustc/src/platform-support/unknown-uefi.md
src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md
src/doc/unstable-book/src/compiler-flags/check-cfg.md
src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md
src/doc/unstable-book/src/compiler-flags/sanitizer.md
src/doc/unstable-book/src/language-features/unix-sigpipe.md [new file with mode: 0644]
src/etc/check_missing_items.py
src/etc/cpu-usage-over-time-plot.sh
src/etc/htmldocck.py
src/etc/pre-push.sh
src/librustdoc/Cargo.toml
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/blanket_impl.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/html/format.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.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/json/conversions.rs
src/librustdoc/json/import_finder.rs [new file with mode: 0644]
src/librustdoc/json/mod.rs
src/librustdoc/lib.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/propagate_doc_cfg.rs
src/librustdoc/passes/stripper.rs
src/stage0.json
src/test/codegen/abi-efiapi.rs
src/test/codegen/avr/avr-func-addrspace.rs
src/test/codegen/issue-34634.rs
src/test/codegen/issue-85872-multiple-reverse.rs [new file with mode: 0644]
src/test/codegen/issue-96274.rs [new file with mode: 0644]
src/test/codegen/unwind-abis/aapcs-unwind-abi.rs
src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs
src/test/codegen/unwind-abis/c-unwind-abi.rs
src/test/codegen/unwind-abis/cdecl-unwind-abi.rs
src/test/codegen/unwind-abis/fastcall-unwind-abi.rs
src/test/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs
src/test/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs
src/test/codegen/unwind-abis/nounwind.rs
src/test/codegen/unwind-abis/stdcall-unwind-abi.rs
src/test/codegen/unwind-abis/system-unwind-abi.rs
src/test/codegen/unwind-abis/sysv64-unwind-abi.rs
src/test/codegen/unwind-abis/thiscall-unwind-abi.rs
src/test/codegen/unwind-abis/vectorcall-unwind-abi.rs
src/test/codegen/unwind-abis/win64-unwind-abi.rs
src/test/codegen/unwind-extern-exports.rs
src/test/incremental/const-generics/hash-tyvid-regression-1.rs
src/test/incremental/hashes/enum_defs.rs
src/test/incremental/hashes/trait_defs.rs
src/test/incremental/hygiene/load_cached_hygiene.rs
src/test/incremental/issue-49043.rs
src/test/incremental/thinlto/cgu_invalidated_when_export_added.rs
src/test/incremental/thinlto/cgu_invalidated_when_export_removed.rs
src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
src/test/mir-opt/dest-prop/union.rs
src/test/mir-opt/early_otherwise_branch_68867.rs
src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff [deleted file]
src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
src/test/mir-opt/issue-73223.rs
src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff [deleted file]
src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff [deleted file]
src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff [deleted file]
src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff [deleted file]
src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff [deleted file]
src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff [deleted file]
src/test/mir-opt/lower_array_len.array_len.InstCombine.diff [deleted file]
src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff [deleted file]
src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff [deleted file]
src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff [deleted file]
src/test/mir-opt/lower_array_len.rs
src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/lower_array_len_e2e.rs [new file with mode: 0644]
src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir [deleted file]
src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir [deleted file]
src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.rs
src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
src/test/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/lower_intrinsics_e2e.rs [new file with mode: 0644]
src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff
src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.32bit.mir [deleted file]
src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.64bit.mir [deleted file]
src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff
src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff
src/test/mir-opt/matches_reduce_branches.rs
src/test/mir-opt/matches_u8.rs
src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir
src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir
src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
src/test/mir-opt/separate_const_switch.rs
src/test/mir-opt/simplify-arm-identity.rs
src/test/mir-opt/simplify-arm.rs
src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs
src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff [deleted file]
src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff [deleted file]
src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff [deleted file]
src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff [deleted file]
src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff [deleted file]
src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff [deleted file]
src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff
src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff
src/test/mir-opt/simplify_try.rs [deleted file]
src/test/mir-opt/try_identity_e2e.new.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/try_identity_e2e.old.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/try_identity_e2e.rs [new file with mode: 0644]
src/test/run-make-fulldeps/issue-64153/Makefile
src/test/run-make/coverage-reports/Makefile
src/test/run-make/coverage-reports/expected_show_coverage.async.txt
src/test/run-make/coverage/async.rs
src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh
src/test/rustdoc-gui/search-form-elements.goml
src/test/rustdoc-gui/search-input.goml
src/test/rustdoc-gui/search-result-color.goml
src/test/rustdoc-gui/src/lib2/lib.rs
src/test/rustdoc-gui/type-declation-overflow.goml
src/test/rustdoc-gui/where-whitespace.goml [new file with mode: 0644]
src/test/rustdoc-json/fns/async_return.rs [new file with mode: 0644]
src/test/rustdoc-json/reexport/glob_collision.rs [new file with mode: 0644]
src/test/rustdoc-json/reexport/glob_empty_mod.rs [new file with mode: 0644]
src/test/rustdoc-json/reexport/in_root_and_mod.rs
src/test/rustdoc-json/reexport/mod_not_included.rs [new file with mode: 0644]
src/test/rustdoc-json/reexport/private_two_names.rs
src/test/rustdoc-json/reexport/rename_private.rs
src/test/rustdoc-json/reexport/simple_private.rs
src/test/rustdoc-json/stripped_modules.rs
src/test/rustdoc-ui/normalize-cycle.rs
src/test/rustdoc/const-generics/const-generics-docs.rs
src/test/rustdoc/doc_auto_cfg_nested_impl.rs [new file with mode: 0644]
src/test/rustdoc/elided-lifetime.rs
src/test/rustdoc/generic-associated-types/gats.rs
src/test/rustdoc/higher-ranked-trait-bounds.rs
src/test/rustdoc/impl-parts.rs
src/test/rustdoc/infinite-redirection.rs
src/test/rustdoc/issue-20727-4.rs
src/test/rustdoc/issue-21801.rs
src/test/rustdoc/issue-29503.rs
src/test/rustdoc/issue-34928.rs
src/test/rustdoc/issue-50159.rs
src/test/rustdoc/issue-51236.rs
src/test/rustdoc/issue-54705.rs
src/test/rustdoc/issue-98697.rs
src/test/rustdoc/macro-document-private-duplicate.rs
src/test/rustdoc/primitive-reference.rs [new file with mode: 0644]
src/test/rustdoc/primitive-slice-auto-trait.rs
src/test/rustdoc/synthetic_auto/basic.rs
src/test/rustdoc/synthetic_auto/complex.rs
src/test/rustdoc/synthetic_auto/lifetimes.rs
src/test/rustdoc/synthetic_auto/manual.rs
src/test/rustdoc/synthetic_auto/nested.rs
src/test/rustdoc/synthetic_auto/no-redundancy.rs
src/test/rustdoc/synthetic_auto/project.rs
src/test/rustdoc/synthetic_auto/self-referential.rs
src/test/rustdoc/synthetic_auto/static-region.rs
src/test/rustdoc/where-clause-order.rs
src/test/rustdoc/where.rs
src/test/ui-fulldeps/internal-lints/diagnostics.rs
src/test/ui-fulldeps/internal-lints/diagnostics.stderr
src/test/ui-fulldeps/issue-15778-pass.rs [deleted file]
src/test/ui-fulldeps/issue-15778-pass.stderr [deleted file]
src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
src/test/ui/allocator/no_std-alloc-error-handler-custom.rs
src/test/ui/allocator/no_std-alloc-error-handler-default.rs
src/test/ui/asm/type-check-1.stderr
src/test/ui/associated-type-bounds/elision.rs
src/test/ui/associated-types/associated-types-path-2.rs
src/test/ui/associated-types/associated-types-path-2.stderr
src/test/ui/associated-types/substs-ppaux.normal.stderr
src/test/ui/associated-types/substs-ppaux.verbose.stderr
src/test/ui/async-await/issue-73137.rs
src/test/ui/attributes/register-attr-tool-fail.rs [deleted file]
src/test/ui/attributes/register-attr-tool-fail.stderr [deleted file]
src/test/ui/attributes/register-attr-tool-import.rs [deleted file]
src/test/ui/attributes/register-attr-tool-import.stderr [deleted file]
src/test/ui/attributes/register-attr-tool-prelude.rs [deleted file]
src/test/ui/attributes/register-attr-tool-prelude.stderr [deleted file]
src/test/ui/attributes/register-attr-tool-unused.rs [deleted file]
src/test/ui/attributes/register-attr-tool-unused.stderr [deleted file]
src/test/ui/attributes/register-attr-tool.rs [deleted file]
src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-crate.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-crate.stderr [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.stderr [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-error.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-list.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-list.stderr [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.stderr [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.stderr [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-not-used.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-only-feature.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-rustc_main.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-sig_dfl.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-start.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-start.stderr [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-struct.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-struct.stderr [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.stderr [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe.rs [new file with mode: 0644]
src/test/ui/attributes/unix_sigpipe/unix_sigpipe.stderr [new file with mode: 0644]
src/test/ui/binop/issue-77910-2.stderr
src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs [new file with mode: 0644]
src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr [new file with mode: 0644]
src/test/ui/borrowck/two-phase-nonrecv-autoref.rs
src/test/ui/borrowck/two-phase-reservation-sharing-interference.rs
src/test/ui/check-cfg/invalid-arguments.names_simple_ident.stderr
src/test/ui/check-cfg/invalid-arguments.values_simple_ident.stderr
src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs
src/test/ui/closures/2229_closure_analysis/repr_packed.rs
src/test/ui/closures/2229_closure_analysis/run_pass/by_value.rs
src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs
src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs
src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs
src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs
src/test/ui/closures/issue-84128.rs
src/test/ui/coercion/issue-101066.rs [new file with mode: 0644]
src/test/ui/command/command-current-dir.rs
src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr
src/test/ui/const-generics/issues/issue-83466.rs
src/test/ui/const-ptr/forbidden_slices.32bit.stderr
src/test/ui/const-ptr/forbidden_slices.64bit.stderr
src/test/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr
src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr
src/test/ui/consts/const-eval/ref_to_int_match.32bit.stderr
src/test/ui/consts/const-eval/ref_to_int_match.64bit.stderr
src/test/ui/consts/const-eval/ub-enum.32bit.stderr
src/test/ui/consts/const-eval/ub-enum.64bit.stderr
src/test/ui/consts/const-eval/ub-enum.rs
src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
src/test/ui/consts/extra-const-ub/detect-extra-ub.rs
src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr
src/test/ui/consts/issue-83182.32bit.stderr
src/test/ui/consts/issue-83182.64bit.stderr
src/test/ui/consts/issue-83182.rs
src/test/ui/consts/issue-miri-1910.rs
src/test/ui/consts/issue-miri-1910.stderr
src/test/ui/consts/miri_unleashed/ptr_arith.rs
src/test/ui/consts/miri_unleashed/ptr_arith.stderr
src/test/ui/consts/ptr_comparisons.stderr
src/test/ui/copy-a-resource.stderr
src/test/ui/dst/dst-bad-coercions.stderr
src/test/ui/expr/if/attrs/let-chains-attr.rs
src/test/ui/expr/if/bad-if-let-suggestion.rs
src/test/ui/expr/if/bad-if-let-suggestion.stderr
src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr
src/test/ui/feature-gates/feature-gate-register_attr.rs [deleted file]
src/test/ui/feature-gates/feature-gate-register_attr.stderr [deleted file]
src/test/ui/feature-gates/feature-gate-unix_sigpipe.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-unix_sigpipe.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr
src/test/ui/fmt/ifmt-bad-arg.rs
src/test/ui/fmt/ifmt-bad-arg.stderr
src/test/ui/fn/fn-compare-mismatch.stderr
src/test/ui/fn/fn-trait-formatting.stderr
src/test/ui/functions-closures/fn-help-with-err.rs
src/test/ui/functions-closures/fn-help-with-err.stderr
src/test/ui/generic-associated-types/issue-101020.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-101020.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs
src/test/ui/impl-trait/issue-100075-2.rs [new file with mode: 0644]
src/test/ui/impl-trait/issue-100075-2.stderr [new file with mode: 0644]
src/test/ui/impl-trait/issue-100075.rs [new file with mode: 0644]
src/test/ui/impl-trait/issue-100075.stderr [new file with mode: 0644]
src/test/ui/impl-trait/issue-99914.rs [new file with mode: 0644]
src/test/ui/impl-trait/issue-99914.stderr [new file with mode: 0644]
src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr
src/test/ui/impl-trait/suggest-calling-rpit-closure.stderr
src/test/ui/issues/issue-23611-enum-swap-in-drop.rs
src/test/ui/issues/issue-2823.stderr
src/test/ui/issues/issue-35241.stderr
src/test/ui/issues/issue-57362-1.stderr
src/test/ui/issues/issue-59488.stderr
src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr
src/test/ui/iterators/issue-28098.rs
src/test/ui/iterators/issue-28098.stderr
src/test/ui/iterators/issue-58952-filter-type-length.rs
src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs
src/test/ui/lint/let_underscore/let_underscore_drop.rs [new file with mode: 0644]
src/test/ui/lint/let_underscore/let_underscore_drop.stderr [new file with mode: 0644]
src/test/ui/lint/let_underscore/let_underscore_lock.rs [new file with mode: 0644]
src/test/ui/lint/let_underscore/let_underscore_lock.stderr [new file with mode: 0644]
src/test/ui/lint/uninitialized-zeroed.rs
src/test/ui/lint/uninitialized-zeroed.stderr
src/test/ui/mir/issue-92893.rs
src/test/ui/mir/issue-92893.stderr
src/test/ui/mir/issue-99866.rs [new file with mode: 0644]
src/test/ui/mir/mir_let_chains_drop_order.rs
src/test/ui/mismatched_types/issue-19109.stderr
src/test/ui/mismatched_types/normalize-fn-sig.rs [new file with mode: 0644]
src/test/ui/mismatched_types/normalize-fn-sig.stderr [new file with mode: 0644]
src/test/ui/modules/auxiliary/dummy_lib.rs [new file with mode: 0644]
src/test/ui/modules/special_module_name.rs [new file with mode: 0644]
src/test/ui/modules/special_module_name.stderr [new file with mode: 0644]
src/test/ui/modules/special_module_name_ignore.rs [new file with mode: 0644]
src/test/ui/never_type/fallback-closure-wrap.rs
src/test/ui/nll/issue-21232-partial-init-and-use.rs
src/test/ui/nll/polonius/assignment-kills-loans.rs
src/test/ui/noncopyable-class.stderr
src/test/ui/object-safety/object-safety-associated-consts.curr.stderr
src/test/ui/object-safety/object-safety-bounds.stderr
src/test/ui/object-safety/object-safety-generics.curr.stderr
src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr
src/test/ui/object-safety/object-safety-no-static.curr.stderr
src/test/ui/object-safety/object-safety-sized-2.curr.stderr
src/test/ui/object-safety/object-safety-sized.curr.stderr
src/test/ui/on-unimplemented/multiple-impls.rs
src/test/ui/on-unimplemented/multiple-impls.stderr
src/test/ui/on-unimplemented/on-impl.rs
src/test/ui/on-unimplemented/on-impl.stderr
src/test/ui/pattern/rest-pat-semantic-disallowed.rs
src/test/ui/privacy/access_levels.rs [new file with mode: 0644]
src/test/ui/privacy/access_levels.stderr [new file with mode: 0644]
src/test/ui/proc-macro/crt-static.rs
src/test/ui/proc-macro/expand-to-unstable-2.rs [deleted file]
src/test/ui/proc-macro/expand-to-unstable-2.stderr [deleted file]
src/test/ui/proc-macro/inner-attrs.rs
src/test/ui/proc-macro/inner-attrs.stderr
src/test/ui/proc-macro/inner-attrs.stdout
src/test/ui/proc-macro/issue-41211.rs [deleted file]
src/test/ui/proc-macro/issue-41211.stderr [deleted file]
src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs
src/test/ui/resolve/issue-73427.rs
src/test/ui/resolve/issue-73427.stderr
src/test/ui/resolve/privacy-enum-ctor.stderr
src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
src/test/ui/rfc-2497-if-let-chains/allowed-syntax.rs [deleted file]
src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs
src/test/ui/rfc-2497-if-let-chains/feature-gate.rs [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs
src/test/ui/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr
src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs
src/test/ui/rfc-2497-if-let-chains/issue-90722.rs
src/test/ui/rfc-2497-if-let-chains/issue-92145.rs
src/test/ui/rfc-2497-if-let-chains/issue-93150.rs
src/test/ui/rfc-2497-if-let-chains/issue-93150.stderr
src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs
src/test/ui/sanitize/memory.rs
src/test/ui/span/issue-36530.rs [deleted file]
src/test/ui/span/issue-36530.stderr [deleted file]
src/test/ui/specialization/issue-33017.rs
src/test/ui/suggestions/call-boxed.rs [new file with mode: 0644]
src/test/ui/suggestions/call-boxed.stderr [new file with mode: 0644]
src/test/ui/suggestions/call-on-missing.rs [new file with mode: 0644]
src/test/ui/suggestions/call-on-missing.stderr [new file with mode: 0644]
src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
src/test/ui/suggestions/issue-89064.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-89064.stderr [new file with mode: 0644]
src/test/ui/suggestions/return-closures.rs [new file with mode: 0644]
src/test/ui/suggestions/return-closures.stderr [new file with mode: 0644]
src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs
src/test/ui/suggestions/too-many-field-suggestions.rs [new file with mode: 0644]
src/test/ui/suggestions/too-many-field-suggestions.stderr [new file with mode: 0644]
src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs
src/test/ui/type/issue-100584.rs [new file with mode: 0644]
src/test/ui/type/issue-100584.stderr [new file with mode: 0644]
src/test/ui/type/type-alias-bounds.rs
src/test/ui/type/type-check-defaults.stderr
src/test/ui/type_length_limit.stderr
src/test/ui/typeck/issue-29124.stderr
src/test/ui/typeck/issue-87181/empty-tuple-method.rs
src/test/ui/typeck/issue-87181/empty-tuple-method.stderr
src/test/ui/typeck/issue-87181/enum-variant.rs
src/test/ui/typeck/issue-87181/enum-variant.stderr
src/test/ui/typeck/issue-87181/tuple-field.stderr
src/test/ui/typeck/issue-87181/tuple-method.stderr
src/test/ui/typeck/issue-96738.stderr
src/test/ui/ufcs/ufcs-qpath-self-mismatch.rs
src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr
src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr
src/test/ui/unpretty/avoid-crash.rs [new file with mode: 0644]
src/test/ui/unpretty/avoid-crash.stderr [new file with mode: 0644]
src/test/ui/unsized/issue-30355.stderr
src/test/ui/variance/variance-use-contravariant-struct-1.rs
src/test/ui/variance/variance-use-contravariant-struct-2.rs
src/test/ui/variance/variance-use-invariant-struct-1.rs
src/test/ui/wf/wf-trait-fn-ret.stderr
src/tools/cargo
src/tools/clippy/.github/workflows/clippy.yml
src/tools/clippy/.github/workflows/clippy_bors.yml
src/tools/clippy/CHANGELOG.md
src/tools/clippy/clippy_dev/src/bless.rs
src/tools/clippy/clippy_dev/src/fmt.rs
src/tools/clippy/clippy_dev/src/lib.rs
src/tools/clippy/clippy_dev/src/new_lint.rs
src/tools/clippy/clippy_dev/src/update_lints.rs
src/tools/clippy/clippy_lints/src/as_underscore.rs [deleted file]
src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs [deleted file]
src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
src/tools/clippy/clippy_lints/src/bytecount.rs [deleted file]
src/tools/clippy/clippy_lints/src/bytes_count_to_len.rs [deleted file]
src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs [deleted file]
src/tools/clippy/clippy_lints/src/casts/as_underscore.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/casts/mod.rs
src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/derive.rs
src/tools/clippy/clippy_lints/src/doc_link_with_quotes.rs
src/tools/clippy/clippy_lints/src/duplicate_mod.rs
src/tools/clippy/clippy_lints/src/escape.rs
src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
src/tools/clippy/clippy_lints/src/format.rs
src/tools/clippy/clippy_lints/src/format_args.rs
src/tools/clippy/clippy_lints/src/format_impl.rs
src/tools/clippy/clippy_lints/src/functions/mod.rs
src/tools/clippy/clippy_lints/src/functions/result.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs [deleted file]
src/tools/clippy/clippy_lints/src/get_first.rs [deleted file]
src/tools/clippy/clippy_lints/src/if_let_mutex.rs
src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
src/tools/clippy/clippy_lints/src/lib.register_all.rs
src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
src/tools/clippy/clippy_lints/src/lib.register_lints.rs
src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
src/tools/clippy/clippy_lints/src/lib.register_perf.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.register_suspicious.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
src/tools/clippy/clippy_lints/src/manual_async_fn.rs
src/tools/clippy/clippy_lints/src/manual_ok_or.rs [deleted file]
src/tools/clippy/clippy_lints/src/manual_string_new.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/map_clone.rs [deleted file]
src/tools/clippy/clippy_lints/src/map_err_ignore.rs [deleted file]
src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
src/tools/clippy/clippy_lints/src/matches/needless_match.rs
src/tools/clippy/clippy_lints/src/methods/bytecount.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/expect_used.rs
src/tools/clippy/clippy_lints/src/methods/get_first.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/map_clone.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/open_options.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/repeat_once.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
src/tools/clippy/clippy_lints/src/methods/unit_hash.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
src/tools/clippy/clippy_lints/src/multi_assignments.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs [deleted file]
src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
src/tools/clippy/clippy_lints/src/open_options.rs [deleted file]
src/tools/clippy/clippy_lints/src/option_if_let_else.rs
src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs [deleted file]
src/tools/clippy/clippy_lints/src/question_mark.rs
src/tools/clippy/clippy_lints/src/ranges.rs
src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
src/tools/clippy/clippy_lints/src/redundant_slicing.rs
src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
src/tools/clippy/clippy_lints/src/repeat_once.rs [deleted file]
src/tools/clippy/clippy_lints/src/returns.rs
src/tools/clippy/clippy_lints/src/self_named_constructors.rs
src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs [deleted file]
src/tools/clippy/clippy_lints/src/trait_bounds.rs
src/tools/clippy/clippy_lints/src/transmute/mod.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/transmuting_null.rs [deleted file]
src/tools/clippy/clippy_lints/src/unicode.rs
src/tools/clippy/clippy_lints/src/uninit_vec.rs
src/tools/clippy/clippy_lints/src/unit_hash.rs [deleted file]
src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs [deleted file]
src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
src/tools/clippy/clippy_lints/src/unused_peekable.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/unused_rounding.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_resize_to_zero.rs [deleted file]
src/tools/clippy/clippy_lints/src/verbose_file_reads.rs [deleted file]
src/tools/clippy/clippy_lints/src/write.rs
src/tools/clippy/clippy_utils/Cargo.toml
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/macros.rs
src/tools/clippy/clippy_utils/src/msrvs.rs
src/tools/clippy/clippy_utils/src/paths.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/rust-toolchain
src/tools/clippy/rustc_tools_util/src/lib.rs
src/tools/clippy/tests/check-fmt.rs
src/tools/clippy/tests/compile-test.rs
src/tools/clippy/tests/dogfood.rs
src/tools/clippy/tests/integration.rs
src/tools/clippy/tests/lint_message_convention.rs
src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/collapsible_str_replace.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/collapsible_str_replace.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/collapsible_str_replace.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/expect.rs
src/tools/clippy/tests/ui/expect.stderr
src/tools/clippy/tests/ui/floating_point_exp.fixed
src/tools/clippy/tests/ui/floating_point_exp.rs
src/tools/clippy/tests/ui/floating_point_exp.stderr
src/tools/clippy/tests/ui/floating_point_log.fixed
src/tools/clippy/tests/ui/floating_point_log.rs
src/tools/clippy/tests/ui/floating_point_log.stderr
src/tools/clippy/tests/ui/floating_point_logbase.fixed
src/tools/clippy/tests/ui/floating_point_logbase.rs
src/tools/clippy/tests/ui/floating_point_logbase.stderr
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/floating_point_powi.fixed
src/tools/clippy/tests/ui/floating_point_powi.rs
src/tools/clippy/tests/ui/floating_point_powi.stderr
src/tools/clippy/tests/ui/floating_point_rad.fixed
src/tools/clippy/tests/ui/floating_point_rad.rs
src/tools/clippy/tests/ui/floating_point_rad.stderr
src/tools/clippy/tests/ui/format.fixed
src/tools/clippy/tests/ui/format.rs
src/tools/clippy/tests/ui/format_args.fixed
src/tools/clippy/tests/ui/format_args.rs
src/tools/clippy/tests/ui/format_args.stderr
src/tools/clippy/tests/ui/identity_op.fixed
src/tools/clippy/tests/ui/identity_op.rs
src/tools/clippy/tests/ui/if_let_mutex.rs
src/tools/clippy/tests/ui/if_let_mutex.stderr
src/tools/clippy/tests/ui/if_then_some_else_none.stderr
src/tools/clippy/tests/ui/indexing_slicing_index.rs
src/tools/clippy/tests/ui/iter_on_empty_collections.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/iter_on_empty_collections.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/iter_on_empty_collections.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/iter_on_single_items.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/iter_on_single_items.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/iter_on_single_items.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_string_new.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_string_new.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_string_new.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
src/tools/clippy/tests/ui/multi_assignments.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/multi_assignments.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/needless_borrow.fixed
src/tools/clippy/tests/ui/needless_borrow.rs
src/tools/clippy/tests/ui/needless_borrow.stderr
src/tools/clippy/tests/ui/needless_collect_indirect.rs
src/tools/clippy/tests/ui/needless_collect_indirect.stderr
src/tools/clippy/tests/ui/needless_late_init.fixed
src/tools/clippy/tests/ui/needless_late_init.rs
src/tools/clippy/tests/ui/needless_late_init.stderr
src/tools/clippy/tests/ui/needless_match.fixed
src/tools/clippy/tests/ui/needless_match.rs
src/tools/clippy/tests/ui/needless_match.stderr
src/tools/clippy/tests/ui/needless_return.fixed
src/tools/clippy/tests/ui/needless_return.rs
src/tools/clippy/tests/ui/only_used_in_recursion.rs
src/tools/clippy/tests/ui/only_used_in_recursion.stderr
src/tools/clippy/tests/ui/only_used_in_recursion2.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/only_used_in_recursion2.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/option_if_let_else.fixed
src/tools/clippy/tests/ui/option_if_let_else.rs
src/tools/clippy/tests/ui/option_if_let_else.stderr
src/tools/clippy/tests/ui/or_fun_call.fixed
src/tools/clippy/tests/ui/or_fun_call.rs
src/tools/clippy/tests/ui/or_fun_call.stderr
src/tools/clippy/tests/ui/partialeq_to_none.fixed
src/tools/clippy/tests/ui/partialeq_to_none.rs
src/tools/clippy/tests/ui/partialeq_to_none.stderr
src/tools/clippy/tests/ui/positional_named_format_parameters.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/positional_named_format_parameters.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/positional_named_format_parameters.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/question_mark.fixed
src/tools/clippy/tests/ui/question_mark.rs
src/tools/clippy/tests/ui/regex.rs
src/tools/clippy/tests/ui/result_large_err.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/result_large_err.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/same_item_push.rs
src/tools/clippy/tests/ui/string_add.rs
src/tools/clippy/tests/ui/string_add_assign.fixed
src/tools/clippy/tests/ui/string_add_assign.rs
src/tools/clippy/tests/ui/suspicious_to_owned.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/suspicious_to_owned.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/transmute_undefined_repr.rs
src/tools/clippy/tests/ui/transmute_undefined_repr.stderr
src/tools/clippy/tests/ui/unicode.fixed
src/tools/clippy/tests/ui/unicode.rs
src/tools/clippy/tests/ui/unicode.stderr
src/tools/clippy/tests/ui/uninit.rs
src/tools/clippy/tests/ui/unnecessary_cast.fixed
src/tools/clippy/tests/ui/unnecessary_cast.rs
src/tools/clippy/tests/ui/unnecessary_cast.stderr
src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed
src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs
src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr
src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
src/tools/clippy/tests/ui/unnecessary_to_owned.rs
src/tools/clippy/tests/ui/unused_peekable.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/unused_peekable.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/unwrap.rs
src/tools/clippy/tests/ui/unwrap.stderr
src/tools/clippy/tests/ui/unwrap_expect_used.rs
src/tools/clippy/tests/ui/unwrap_expect_used.stderr
src/tools/clippy/tests/ui/useless_conversion_try.rs
src/tools/clippy/tests/ui/useless_conversion_try.stderr
src/tools/clippy/tests/ui/vec_resize_to_zero.rs
src/tools/clippy/tests/ui/vec_resize_to_zero.stderr
src/tools/clippy/tests/ui/verbose_file_reads.rs
src/tools/clippy/tests/workspace.rs
src/tools/error_index_generator/Cargo.toml
src/tools/error_index_generator/book_config.toml [new file with mode: 0644]
src/tools/error_index_generator/error-index.css [new file with mode: 0644]
src/tools/error_index_generator/error-index.js [new file with mode: 0644]
src/tools/error_index_generator/main.rs
src/tools/error_index_generator/redirect.js [new file with mode: 0644]
src/tools/lint-docs/src/groups.rs
src/tools/lld-wrapper/src/main.rs
src/tools/miri
src/tools/replace-version-placeholder/src/main.rs
src/tools/rust-analyzer/Cargo.lock
src/tools/rust-analyzer/crates/base-db/src/input.rs
src/tools/rust-analyzer/crates/base-db/src/lib.rs
src/tools/rust-analyzer/crates/flycheck/src/lib.rs
src/tools/rust-analyzer/crates/hir-def/src/data.rs
src/tools/rust-analyzer/crates/hir-def/src/db.rs
src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
src/tools/rust-analyzer/crates/hir/src/lib.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs
src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
src/tools/rust-analyzer/crates/ide-completion/src/context.rs
src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
src/tools/rust-analyzer/crates/ide-completion/src/render.rs
src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
src/tools/rust-analyzer/crates/ide-db/src/lib.rs
src/tools/rust-analyzer/crates/ide-db/src/line_index.rs
src/tools/rust-analyzer/crates/ide-db/src/search.rs
src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
src/tools/rust-analyzer/crates/ide/src/doc_links.rs
src/tools/rust-analyzer/crates/ide/src/lib.rs
src/tools/rust-analyzer/crates/ide/src/moniker.rs
src/tools/rust-analyzer/crates/ide/src/prime_caches.rs
src/tools/rust-analyzer/crates/ide/src/references.rs
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs
src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs
src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
src/tools/rust-analyzer/crates/project-model/src/tests.rs
src/tools/rust-analyzer/crates/project-model/src/workspace.rs
src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs [new file with mode: 0644]
src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
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/main_loop.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/semantic_tokens.rs
src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs
src/tools/rust-analyzer/crates/stdx/src/hash.rs [new file with mode: 0644]
src/tools/rust-analyzer/crates/stdx/src/lib.rs
src/tools/rust-analyzer/crates/vfs/Cargo.toml
src/tools/rust-analyzer/crates/vfs/src/file_set.rs
src/tools/rust-analyzer/crates/vfs/src/lib.rs
src/tools/rust-analyzer/docs/user/generated_config.adoc
src/tools/rust-analyzer/docs/user/manual.adoc
src/tools/rust-analyzer/editors/code/package.json
src/tools/rust-analyzer/editors/code/src/client.ts
src/tools/rust-analyzer/editors/code/src/config.ts
src/tools/rust-analyzer/editors/code/src/main.ts
src/tools/rust-analyzer/lib/lsp-server/src/socket.rs
src/tools/tidy/src/deps.rs
triagebot.toml

index b16fb6341c2e50a2f37f04e563017a588365a4d7..37972532b361429f281f8d52f34ea4d1ca621540 100644 (file)
@@ -46,6 +46,7 @@ no_llvm_build
 /dist/
 /unicode-downloads
 /target
+/src/bootstrap/target
 /src/tools/x/target
 # Created by default with `src/ci/docker/run.sh`
 /obj/
index 7c3879fdd98d41c25ab8be243218d8ea1980a5b9..2d143025241ee92051483a16dfb74464c99339bf 100644 (file)
@@ -727,6 +727,7 @@ version = "0.1.65"
 dependencies = [
  "arrayvec",
  "if_chain",
+ "itertools",
  "rustc-semver",
 ]
 
@@ -1035,16 +1036,6 @@ dependencies = [
  "quote",
 ]
 
-[[package]]
-name = "ctor"
-version = "0.1.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c"
-dependencies = [
- "quote",
- "syn",
-]
-
 [[package]]
 name = "curl"
 version = "0.4.43"
@@ -1268,7 +1259,7 @@ dependencies = [
 name = "error_index_generator"
 version = "0.0.0"
 dependencies = [
- "rustdoc",
+ "mdbook",
 ]
 
 [[package]]
@@ -1626,9 +1617,9 @@ dependencies = [
 
 [[package]]
 name = "git2"
-version = "0.14.2"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3826a6e0e2215d7a41c2bfc7c9244123969273f3476b939a226aac0ab56e9e3c"
+checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1"
 dependencies = [
  "bitflags",
  "libc",
@@ -1641,9 +1632,9 @@ dependencies = [
 
 [[package]]
 name = "git2-curl"
-version = "0.15.0"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ee51709364c341fbb6fe2a385a290fb9196753bdde2fc45447d27cd31b11b13"
+checksum = "ed817a00721e2f8037ba722e60358d4956dae9cca10315fc982f967907d3b0cd"
 dependencies = [
  "curl",
  "git2",
@@ -1999,11 +1990,30 @@ dependencies = [
  "rustc-std-workspace-core",
 ]
 
+[[package]]
+name = "libffi"
+version = "3.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e454b3efb16fba3b17810ae5e41df02b649e564ab3c5a34b3b93ed07ad287e6"
+dependencies = [
+ "libc",
+ "libffi-sys",
+]
+
+[[package]]
+name = "libffi-sys"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab4106b7f09d7b87d021334d5618fac1dfcfb824d4c5fe111ff0074dfd242e15"
+dependencies = [
+ "cc",
+]
+
 [[package]]
 name = "libgit2-sys"
-version = "0.13.2+1.4.2"
+version = "0.14.0+1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b"
+checksum = "47a00859c70c8a4f7218e6d1cc32875c4b55f6799445b842b0d8ed5e4c3d959b"
 dependencies = [
  "cc",
  "libc",
@@ -2293,6 +2303,8 @@ dependencies = [
  "getrandom 0.2.0",
  "lazy_static",
  "libc",
+ "libffi",
+ "libloading",
  "log",
  "measureme",
  "rand 0.8.5",
@@ -2471,15 +2483,6 @@ version = "6.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
 
-[[package]]
-name = "output_vt100"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
-dependencies = [
- "winapi",
-]
-
 [[package]]
 name = "owo-colors"
 version = "3.4.0"
@@ -2720,18 +2723,6 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 
-[[package]]
-name = "pretty_assertions"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563"
-dependencies = [
- "ansi_term",
- "ctor",
- "diff",
- "output_vt100",
-]
-
 [[package]]
 name = "pretty_env_logger"
 version = "0.4.0"
@@ -3207,6 +3198,7 @@ dependencies = [
  "rustc_serialize",
  "rustc_span",
  "smallvec",
+ "thin-vec",
  "tracing",
 ]
 
@@ -3228,6 +3220,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "smallvec",
+ "thin-vec",
  "tracing",
 ]
 
@@ -3322,6 +3315,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "smallvec",
+ "thin-vec",
  "tracing",
 ]
 
@@ -3334,6 +3328,7 @@ dependencies = [
  "libc",
  "libloading",
  "measureme",
+ "object 0.29.0",
  "rustc-demangle",
  "rustc_ast",
  "rustc_attr",
@@ -3369,7 +3364,6 @@ dependencies = [
  "object 0.29.0",
  "pathdiff",
  "regex",
- "rustc_apfloat",
  "rustc_arena",
  "rustc_ast",
  "rustc_attr",
@@ -3446,6 +3440,7 @@ dependencies = [
  "stable_deref_trait",
  "stacker",
  "tempfile",
+ "thin-vec",
  "tracing",
  "winapi",
 ]
@@ -3514,6 +3509,7 @@ dependencies = [
  "rustc_macros",
  "rustc_serialize",
  "rustc_span",
+ "rustc_target",
  "serde",
  "serde_json",
  "termcolor",
@@ -3828,6 +3824,7 @@ dependencies = [
  "rustc_target",
  "rustc_type_ir",
  "smallvec",
+ "thin-vec",
  "tracing",
 ]
 
@@ -3905,8 +3902,10 @@ name = "rustc_monomorphize"
 version = "0.0.0"
 dependencies = [
  "rustc_data_structures",
+ "rustc_errors",
  "rustc_hir",
  "rustc_index",
+ "rustc_macros",
  "rustc_middle",
  "rustc_session",
  "rustc_span",
@@ -4015,6 +4014,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
+ "thin-vec",
  "tracing",
 ]
 
@@ -4037,6 +4037,7 @@ dependencies = [
  "rustc_span",
  "rustc_target",
  "smallvec",
+ "thin-vec",
  "tracing",
 ]
 
@@ -4092,6 +4093,7 @@ dependencies = [
  "indexmap",
  "rustc_macros",
  "smallvec",
+ "thin-vec",
 ]
 
 [[package]]
@@ -4154,7 +4156,9 @@ dependencies = [
  "punycode",
  "rustc-demangle",
  "rustc_data_structures",
+ "rustc_errors",
  "rustc_hir",
+ "rustc_macros",
  "rustc_middle",
  "rustc_session",
  "rustc_span",
@@ -4326,6 +4330,7 @@ dependencies = [
  "serde_json",
  "smallvec",
  "tempfile",
+ "thin-vec",
  "tracing",
  "tracing-subscriber",
  "tracing-tree",
@@ -4879,6 +4884,12 @@ version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
 
+[[package]]
+name = "thin-vec"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "104c2cb3180b6fb6d5b2278768e9b88b578d32ba751ea6e8d026688a40d7ed87"
+
 [[package]]
 name = "thiserror"
 version = "1.0.30"
@@ -4998,9 +5009,9 @@ checksum = "aa7c7f42dea4b1b99439786f5633aeb9c14c1b53f75e282803c2ec2ad545873c"
 
 [[package]]
 name = "tracing"
-version = "0.1.29"
+version = "0.1.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
+checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
 dependencies = [
  "cfg-if 1.0.0",
  "pin-project-lite",
@@ -5010,9 +5021,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.18"
+version = "0.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e"
+checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5021,11 +5032,12 @@ dependencies = [
 
 [[package]]
 name = "tracing-core"
-version = "0.1.21"
+version = "0.1.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4"
+checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7"
 dependencies = [
- "lazy_static",
+ "once_cell",
+ "valuable",
 ]
 
 [[package]]
@@ -5114,14 +5126,16 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
 [[package]]
 name = "ui_test"
-version = "0.1.0"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d1f546a5883ae78da735bba529ec1116661e2f73582f23920d994dc97da3a22"
 dependencies = [
  "cargo_metadata 0.15.0",
  "color-eyre",
  "colored",
  "crossbeam",
+ "diff",
  "lazy_static",
- "pretty_assertions",
  "regex",
  "rustc_version",
  "serde",
@@ -5344,6 +5358,12 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
 
+[[package]]
+name = "valuable"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+
 [[package]]
 name = "vcpkg"
 version = "0.2.10"
index 147ff3561a30bbac29174727bfb3b5a189e05b6b..72b2c16a01f83b63ce9d1f448ab652c21aeb5450 100644 (file)
@@ -1442,7 +1442,7 @@ Compatibility Notes
 - [Mixing Option and Result via `?` is no longer permitted in closures for inferred types.][86831]
 - [Previously unsound code is no longer permitted where different constructors in branches
   could require different lifetimes.][85574]
-- As previously mentioned the [`std::arch` instrinsics now uses stricter const checking][83278]
+- As previously mentioned the [`std::arch` intrinsics now uses stricter const checking][83278]
   than before and may reject some previously accepted code.
 - [`i128` multiplication on Cortex M0+ platforms currently unconditionally causes overflow
    when compiled with `codegen-units = 1`.][86063]
@@ -2520,7 +2520,7 @@ Compatibility Notes
 - [Fixed a regression parsing `{} && false` in tail expressions.][74650]
 - [Added changes to how proc-macros are expanded in `macro_rules!` that should
   help to preserve more span information.][73084] These changes may cause
-  compiliation errors if your macro was unhygenic or didn't correctly handle
+  compilation errors if your macro was unhygenic or didn't correctly handle
   `Delimiter::None`.
 - [Moved support for the CloudABI target to tier 3.][75568]
 - [`linux-gnu` targets now require minimum kernel 2.6.32 and glibc 2.11.][74163]
index d2f8ef8eaae7dbc3904c4cd8cb03fa2df4195a4e..46dbbd83d19054e2c2aaf8e4751c68a9aaf974d0 100644 (file)
@@ -16,6 +16,7 @@
 #![feature(maybe_uninit_slice)]
 #![feature(min_specialization)]
 #![feature(decl_macro)]
+#![feature(pointer_byte_offsets)]
 #![feature(rustc_attrs)]
 #![cfg_attr(test, feature(test))]
 #![feature(strict_provenance)]
@@ -211,7 +212,7 @@ pub fn alloc(&self, object: T) -> &mut T {
 
         unsafe {
             if mem::size_of::<T>() == 0 {
-                self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T);
+                self.ptr.set(self.ptr.get().wrapping_byte_add(1));
                 let ptr = ptr::NonNull::<T>::dangling().as_ptr();
                 // Don't drop the object. This `write` is equivalent to `forget`.
                 ptr::write(ptr, object);
index 9822e9864e2103774c7cf92baa8bf5d05ffad23f..c24180bacfc1b05207ebfbc0b7ccbfd06a558678 100644 (file)
@@ -7,12 +7,13 @@ edition = "2021"
 doctest = false
 
 [dependencies]
-rustc_serialize = { path = "../rustc_serialize" }
-tracing = "0.1"
-rustc_span = { path = "../rustc_span" }
+bitflags = "1.2.1"
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_index = { path = "../rustc_index" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_macros = { path = "../rustc_macros" }
+rustc_serialize = { path = "../rustc_serialize" }
+rustc_span = { path = "../rustc_span" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-bitflags = "1.2.1"
+thin-vec = "0.2.8"
+tracing = "0.1"
index fb521073a428d2802bfe0fe994ecd16edce9c8e3..3af6dee9e43f7fb888e6d5f5a95c1babc17b33a4 100644 (file)
 use crate::ptr::P;
 use crate::token::{self, CommentKind, Delimiter};
 use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream};
-
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::thin_vec::ThinVec;
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 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;
+use thin_vec::ThinVec;
 
 /// A "Label" is an identifier of some point in sources,
 /// e.g. in the following code:
index 0947a71b8243261a7e7efad25f1599b7a92fb943..79f5820230ed67b597111d7f7df406c10122be91 100644 (file)
@@ -279,6 +279,7 @@ macro_rules! impl_has_attrs {
             impl HasAttrs for $T {
                 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner;
 
+                #[inline]
                 fn attrs(&self) -> &[Attribute] {
                     &self.attrs
                 }
index f9b4d76f28f8a6a03ab6352b722defa246301c5a..e5435e3a3d4fad4037927e7eaae246f1d8652f7e 100644 (file)
@@ -14,6 +14,7 @@
 #![feature(const_trait_impl)]
 #![feature(if_let_guard)]
 #![cfg_attr(bootstrap, feature(label_break_value))]
+#![feature(let_chains)]
 #![feature(min_specialization)]
 #![feature(negative_impls)]
 #![feature(slice_internals)]
@@ -25,6 +26,9 @@
 #[macro_use]
 extern crate rustc_macros;
 
+#[macro_use]
+extern crate tracing;
+
 pub mod util {
     pub mod classify;
     pub mod comments;
index 9e4a22e1fa3cd19551ddeda23c2609dc172f4953..b6684c0669b4cd87737155d3004697b4a2704b1d 100644 (file)
@@ -426,7 +426,8 @@ fn opt_from_ast(node: &(impl HasAttrs + HasTokens)) -> Option<TokenStream> {
         let attr_annotated = if attrs.is_empty() {
             tokens.create_token_stream()
         } else {
-            let attr_data = AttributesData { attrs: attrs.to_vec().into(), tokens: tokens.clone() };
+            let attr_data =
+                AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() };
             AttrAnnotatedTokenStream::new(vec![(
                 AttrAnnotatedTokenTree::Attributes(attr_data),
                 Spacing::Alone,
@@ -555,7 +556,7 @@ pub fn build(self) -> TokenStream {
 
                 // Get the first stream, which will become the result stream.
                 // If it's `None`, create an empty stream.
-                let mut iter = streams.drain(..);
+                let mut iter = streams.into_iter();
                 let mut res_stream_lrc = iter.next().unwrap().0;
 
                 // Append the subsequent elements to the result stream, after
index 69a78d165ef5895ad654b51103bd6efa21f5d016..6a1578498e6894468552c4729ecb0cf2c4b9531e 100644 (file)
@@ -9,7 +9,6 @@
 use rustc_span::Span;
 
 use std::ascii;
-use tracing::debug;
 
 pub enum LitError {
     NotLiteral,
index 474aff2e2aac06fabc947ac8c733fa227c732e65..ce1c8d4997d745b3c4760649db7786ef48bfccef 100644 (file)
@@ -8,17 +8,18 @@ doctest = false
 
 [dependencies]
 rustc_arena = { path = "../rustc_arena" }
-tracing = "0.1"
+rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
-rustc_hir = { path = "../rustc_hir" }
-rustc_target = { path = "../rustc_target" }
 rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_errors = { path = "../rustc_errors" }
+rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_query_system = { path = "../rustc_query_system" }
-rustc_span = { path = "../rustc_span" }
-rustc_errors = { path = "../rustc_errors" }
 rustc_session = { path = "../rustc_session" }
-rustc_ast = { path = "../rustc_ast" }
+rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+thin-vec = "0.2.8"
+tracing = "0.1"
index 59f1b7180e4f4c5eb02c551ebb143208c9990642..4adeaef9bbfa832d708a5275c5209229c105c37f 100644 (file)
@@ -327,3 +327,10 @@ pub struct ArbitraryExpressionInPattern {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(SessionDiagnostic, Clone, Copy)]
+#[diag(ast_lowering::inclusive_range_with_no_end)]
+pub struct InclusiveRangeWithNoEnd {
+    #[primary_span]
+    pub span: Span,
+}
index 61f8c0216f1cf91c2f6d7ef65e4c6667bbde5a0e..7df3520422c18b38cb14cb1ba979eb0024d487c3 100644 (file)
@@ -1,13 +1,12 @@
 use super::errors::{
     AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
     BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt,
-    GeneratorTooManyParameters, NotSupportedForLifetimeBinderAsyncClosure, RustcBoxAttributeError,
-    UnderscoreExprLhsAssign,
+    GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure,
+    RustcBoxAttributeError, UnderscoreExprLhsAssign,
 };
 use super::ResolverAstLoweringExt;
 use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
 use crate::{FnDeclKind, ImplTraitPosition};
-
 use rustc_ast::attr;
 use rustc_ast::ptr::P as AstP;
 use rustc_ast::*;
@@ -18,6 +17,7 @@
 use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::DUMMY_SP;
+use thin_vec::thin_vec;
 
 impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
@@ -1264,7 +1264,13 @@ fn lower_expr_range(
             (Some(..), Some(..), HalfOpen) => hir::LangItem::Range,
             (None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
             (Some(..), Some(..), Closed) => unreachable!(),
-            (_, None, Closed) => self.diagnostic().span_fatal(span, "inclusive range with no end"),
+            (start, None, Closed) => {
+                self.tcx.sess.emit_err(InclusiveRangeWithNoEnd { span });
+                match start {
+                    Some(..) => hir::LangItem::RangeFrom,
+                    None => hir::LangItem::RangeFull,
+                }
+            }
         };
 
         let fields = self.arena.alloc_from_iter(
@@ -1535,7 +1541,7 @@ fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir>
             };
             attr::mk_attr_outer(allow)
         };
-        let attrs: AttrVec = vec![attr].into();
+        let attrs: AttrVec = thin_vec![attr];
 
         // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
         let continue_arm = {
index 2b7431f0990570a004902099db789a36f65cd989..219e1b81d1ea64d3226d9eb93787b1ed2d98fe4d 100644 (file)
@@ -11,8 +11,6 @@
 use rustc_span::source_map::SourceMap;
 use rustc_span::{Span, DUMMY_SP};
 
-use tracing::debug;
-
 /// A visitor that walks over the HIR and collects `Node`s into a HIR map.
 pub(super) struct NodeCollector<'a, 'hir> {
     /// Source map
@@ -31,7 +29,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
     definitions: &'a definitions::Definitions,
 }
 
-#[tracing::instrument(level = "debug", skip(sess, definitions, bodies))]
+#[instrument(level = "debug", skip(sess, definitions, bodies))]
 pub(super) fn index_hir<'hir>(
     sess: &Session,
     definitions: &definitions::Definitions,
@@ -67,7 +65,7 @@ pub(super) fn index_hir<'hir>(
 }
 
 impl<'a, 'hir> NodeCollector<'a, 'hir> {
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
         debug_assert_eq!(self.owner, hir_id.owner);
         debug_assert_ne!(hir_id.local_id.as_u32(), 0);
@@ -142,7 +140,7 @@ fn visit_param(&mut self, param: &'hir Param<'hir>) {
         });
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_item(&mut self, i: &'hir Item<'hir>) {
         debug_assert_eq!(i.def_id, self.owner);
         self.with_parent(i.hir_id(), |this| {
@@ -156,7 +154,7 @@ fn visit_item(&mut self, i: &'hir Item<'hir>) {
         });
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
         debug_assert_eq!(fi.def_id, self.owner);
         self.with_parent(fi.hir_id(), |this| {
@@ -175,7 +173,7 @@ fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
         })
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
         debug_assert_eq!(ti.def_id, self.owner);
         self.with_parent(ti.hir_id(), |this| {
@@ -183,7 +181,7 @@ fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
         });
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
         debug_assert_eq!(ii.def_id, self.owner);
         self.with_parent(ii.hir_id(), |this| {
index becb67d116546993df6ab13ea21db8e870529b79..9a960356a85f4066f628ea59a101e29c4b6dc306 100644 (file)
 //! in the HIR, especially for multiple identifiers.
 
 #![feature(box_patterns)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 
 #[macro_use]
 extern crate tracing;
@@ -217,7 +220,7 @@ fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind {
     /// Panics if no map has been pushed.
     /// Remapping is used when creating lowering `-> impl Trait` return
     /// types to create the resulting opaque type.
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId) {
         self.generics_def_id_map.last_mut().expect("no map pushed").insert(from, to);
     }
@@ -768,7 +771,7 @@ fn lower_ident(&self, ident: Ident) -> Ident {
     }
 
     /// Converts a lifetime into a new generic parameter.
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn lifetime_res_to_generic_param(
         &mut self,
         ident: Ident,
@@ -812,7 +815,7 @@ 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.
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     #[inline]
     fn lower_lifetime_binder(
         &mut self,
@@ -1176,7 +1179,7 @@ fn lower_path_ty(
     ) -> 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
-        // the rare occurence we need to lower `Fresh` anonymous lifetimes.
+        // the rare occurrence we need to lower `Fresh` anonymous lifetimes.
         // The other cases when a qpath should be opportunistically made a trait object are handled
         // by `ty_path`.
         if qself.is_none()
@@ -1382,7 +1385,7 @@ 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.
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn lower_opaque_impl_trait(
         &mut self,
         span: Span,
@@ -1618,7 +1621,7 @@ fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
     // `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.
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn lower_fn_decl(
         &mut self,
         decl: &FnDecl,
@@ -1727,7 +1730,7 @@ fn lower_fn_decl(
     // `output`: unlowered output type (`T` in `-> T`)
     // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition)
     // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn lower_async_fn_ret_ty(
         &mut self,
         output: &FnRetTy,
@@ -2010,7 +2013,7 @@ fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
         self.new_named_lifetime(l.id, l.id, span, ident)
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn new_named_lifetime_with_res(
         &mut self,
         id: NodeId,
@@ -2041,7 +2044,7 @@ fn new_named_lifetime_with_res(
         hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn new_named_lifetime(
         &mut self,
         id: NodeId,
@@ -2129,7 +2132,7 @@ fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::Tra
         hir::TraitRef { path, hir_ref_id: self.lower_node_id(p.ref_id) }
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn lower_poly_trait_ref(
         &mut self,
         p: &PolyTraitRef,
index 5874d08a94fe06bac55a516e8abef538f386aa58..897c7215805e0753e784601eb16518b94e9556bc 100644 (file)
@@ -13,7 +13,6 @@
 use rustc_span::{BytePos, Span, DUMMY_SP};
 
 use smallvec::smallvec;
-use tracing::debug;
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
     #[instrument(level = "trace", skip(self))]
index b337e5328c5df6af4c75ae61acfd3739ca616360..23464bf0a5a283e50039bf38ba77f2e9e741d673 100644 (file)
@@ -119,7 +119,12 @@ fn with_let_management(
 
     /// Emits an error banning the `let` expression provided in the given location.
     fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
-        self.session.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
+        let sess = &self.session;
+        if sess.opts.unstable_features.is_nightly_build() {
+            sess.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
+        } else {
+            sess.emit_err(ForbiddenLetStable { span: expr.span });
+        }
     }
 
     fn check_gat_where(
@@ -1795,7 +1800,7 @@ pub(crate) enum ForbiddenLetReason {
     NotSupportedOr(Span),
     /// A let chain with invalid parentheses
     ///
-    /// For exemple, `let 1 = 1 && (expr && expr)` is allowed
+    /// For example, `let 1 = 1 && (expr && expr)` is allowed
     /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
     NotSupportedParentheses(Span),
 }
index 16ba14e9092168fda7ddcc2d768f1d9dbb176dff..21467e57651983fc78b918370d749af62bb78372 100644 (file)
@@ -30,6 +30,14 @@ fn add_to_diagnostic(self, diag: &mut Diagnostic) {
     }
 }
 
+#[derive(SessionDiagnostic)]
+#[diag(ast_passes::forbidden_let_stable)]
+#[note]
+pub struct ForbiddenLetStable {
+    #[primary_span]
+    pub span: Span,
+}
+
 #[derive(SessionDiagnostic)]
 #[diag(ast_passes::forbidden_assoc_constraint)]
 pub struct ForbiddenAssocConstraint {
index 4ac96ec8b609c82dbfd98c0b8dc527e0741e8a53..ca5b7a64155157f80c250cd9e8c8e07b9897ebbe 100644 (file)
@@ -11,8 +11,6 @@
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
-use tracing::debug;
-
 macro_rules! gate_feature_fn {
     ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
         let (visitor, has_feature, span, name, explain, help) =
@@ -777,6 +775,7 @@ macro_rules! gate_all {
         "`if let` guards are experimental",
         "you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`"
     );
+    gate_all!(let_chains, "`let` expressions in this position are unstable");
     gate_all!(
         async_closure,
         "async closures are unstable",
index 6a8262989850cb23d6417bba225117c062d45547..af25982e2887bb33656b99017083f8c460d7a619 100644 (file)
@@ -8,9 +8,13 @@
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
 #![feature(iter_is_partitioned)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![recursion_limit = "256"]
 
+#[macro_use]
+extern crate tracing;
+
 pub mod ast_validation;
 mod errors;
 pub mod feature_gate;
index 65edab78ce74ece4c3b2cb1098b7db250851346b..a8ed510866d89832fed560be07bf534f2fbfda84 100644 (file)
 
 use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
 
+/// The version placeholder that recently stabilized features contain inside the
+/// `since` field of the `#[stable]` attribute.
+///
+/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
+pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
+
 pub fn is_builtin_attr(attr: &Attribute) -> bool {
     attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
 }
@@ -483,6 +489,12 @@ fn find_stability_generic<'a, I>(
                         }
                     }
 
+                    if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
+                        let version = option_env!("CFG_VERSION").unwrap_or("<current>");
+                        let version = version.split(' ').next().unwrap();
+                        since = Some(Symbol::intern(&version));
+                    }
+
                     match (feature, since) {
                         (Some(feature), Some(since)) => {
                             let level = Stable { since, allowed_through_unstable_modules: false };
index 3a43f1aad02d63c40262b5c2f38640014669ef74..053f848aacbf73351cd2d1bcc99d4663fbad6fa9 100644 (file)
@@ -4,6 +4,7 @@
 //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
 //! to this crate.
 
+#![feature(let_chains)]
 #![feature(let_else)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
index a504d0c91222e39b1a419b3b59db80ac778d94ef..c94dfe39b6903aea57a90c87d3871358e04531a1 100644 (file)
@@ -105,8 +105,8 @@ impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> {
     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(
             formatter,
-            "({:?}: {:?}) due to {:?} ({:?})",
-            self.sup, self.sub, self.locations, self.variance_info
+            "({:?}: {:?}) due to {:?} ({:?}) ({:?})",
+            self.sup, self.sub, self.locations, self.variance_info, self.category,
         )
     }
 }
index 84a0d4ba7ba10b67fea7fe8f95cc21270bb20a33..5971f7623f215a4c3ed8c1a1832d8b31f32ba134 100644 (file)
@@ -1119,6 +1119,7 @@ pub(crate) fn describe_place_for_conflicting_borrow(
     /// short a lifetime. (But sometimes it is more useful to report
     /// it as a more direct conflict between the execution of a
     /// `Drop::drop` with an aliasing borrow.)
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn report_borrowed_value_does_not_live_long_enough(
         &mut self,
         location: Location,
@@ -1126,13 +1127,6 @@ pub(crate) fn report_borrowed_value_does_not_live_long_enough(
         place_span: (Place<'tcx>, Span),
         kind: Option<WriteKind>,
     ) {
-        debug!(
-            "report_borrowed_value_does_not_live_long_enough(\
-             {:?}, {:?}, {:?}, {:?}\
-             )",
-            location, borrow, place_span, kind
-        );
-
         let drop_span = place_span.1;
         let root_place =
             self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
@@ -1189,10 +1183,8 @@ pub(crate) fn report_borrowed_value_does_not_live_long_enough(
         let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
         let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
 
-        debug!(
-            "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})",
-            place_desc, explanation
-        );
+        debug!(?place_desc, ?explanation);
+
         let err = match (place_desc, explanation) {
             // If the outlives constraint comes from inside the closure,
             // for example:
@@ -1464,6 +1456,7 @@ fn report_thread_local_value_does_not_live_long_enough(
         err
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn report_temporary_value_does_not_live_long_enough(
         &mut self,
         location: Location,
@@ -1473,13 +1466,6 @@ fn report_temporary_value_does_not_live_long_enough(
         proper_span: Span,
         explanation: BorrowExplanation<'tcx>,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
-        debug!(
-            "report_temporary_value_does_not_live_long_enough(\
-             {:?}, {:?}, {:?}, {:?}\
-             )",
-            location, borrow, drop_span, proper_span
-        );
-
         if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
             explanation
         {
index a6b8c6057e05ee0f9be50a4357652e4d599e2167..2f61849c383c528ea3c62e2e08062e26e2b13aff 100644 (file)
@@ -336,26 +336,22 @@ fn free_region_constraint_info(
     ///   - second half is the place being accessed
     ///
     /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn explain_why_borrow_contains_point(
         &self,
         location: Location,
         borrow: &BorrowData<'tcx>,
         kind_place: Option<(WriteKind, Place<'tcx>)>,
     ) -> BorrowExplanation<'tcx> {
-        debug!(
-            "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
-            location, borrow, kind_place
-        );
-
         let regioncx = &self.regioncx;
         let body: &Body<'_> = &self.body;
         let tcx = self.infcx.tcx;
 
         let borrow_region_vid = borrow.region;
-        debug!("explain_why_borrow_contains_point: borrow_region_vid={:?}", borrow_region_vid);
+        debug!(?borrow_region_vid);
 
         let region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
-        debug!("explain_why_borrow_contains_point: region_sub={:?}", region_sub);
+        debug!(?region_sub);
 
         match find_use::find(body, regioncx, tcx, region_sub, location) {
             Some(Cause::LiveVar(local, location)) => {
@@ -408,17 +404,11 @@ pub(crate) fn explain_why_borrow_contains_point(
                             opt_place_desc,
                         }
                     } else {
-                        debug!(
-                            "explain_why_borrow_contains_point: \
-                             Could not generate a region name"
-                        );
+                        debug!("Could not generate a region name");
                         BorrowExplanation::Unexplained
                     }
                 } else {
-                    debug!(
-                        "explain_why_borrow_contains_point: \
-                         Could not generate an error region vid"
-                    );
+                    debug!("Could not generate an error region vid");
                     BorrowExplanation::Unexplained
                 }
             }
index d359d7efb626801905958a91c983f866105a1fce..35c3df768995a0d2907db1cb174122666596a9cc 100644 (file)
@@ -6,7 +6,6 @@
 use rustc_middle::ty::RegionVid;
 use smallvec::SmallVec;
 use std::collections::BTreeMap;
-use tracing::debug;
 
 use crate::MirBorrowckCtxt;
 
index 00fdf331ca60ce8c270a3ce98ec6a41d35baafa6..082dd86902354843822df54b8cee1b6dd56b63a3 100644 (file)
@@ -902,7 +902,11 @@ fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
             hir::ExprKind::MethodCall(.., args, _) => {
                 // only the first closre parameter of the method. args[0] is MethodCall PathSegment
                 for i in 1..args.len() {
-                    if let hir::ExprKind::Closure(..) = args[i].kind {
+                    if let hir::ExprKind::Closure(hir::Closure {
+                        capture_clause: hir::CaptureBy::Ref,
+                        ..
+                    }) = args[i].kind
+                    {
                         closure_span = Some(args[i].span.shrink_to_lo());
                         break;
                     }
@@ -911,7 +915,11 @@ fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
             hir::ExprKind::Block(blk, _) => {
                 if let Some(ref expr) = blk.expr {
                     // only when the block is a closure
-                    if let hir::ExprKind::Closure(..) = expr.kind {
+                    if let hir::ExprKind::Closure(hir::Closure {
+                        capture_clause: hir::CaptureBy::Ref,
+                        ..
+                    }) = expr.kind
+                    {
                         closure_span = Some(expr.span.shrink_to_lo());
                     }
                 }
@@ -921,7 +929,7 @@ fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
         if let Some(closure_span) = closure_span {
             diag.span_suggestion_verbose(
                 closure_span,
-                format!("consider adding 'move' keyword before the nested closure"),
+                "consider adding 'move' keyword before the nested closure",
                 "move ",
                 Applicability::MaybeIncorrect,
             );
index a87e8bd5ba16fc276183bc1366a121107141dd94..75fde53b6cdecd24452e0293db2118ad598f9620 100644 (file)
@@ -265,7 +265,7 @@ pub(crate) fn give_region_a_name(&self, fr: RegionVid) -> Option<RegionName> {
     /// *user* has a name for. In that case, we'll be able to map
     /// `fr` to a `Region<'tcx>`, and that region will be one of
     /// named variants.
-    #[tracing::instrument(level = "trace", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
         let error_region = self.to_error_region(fr)?;
 
@@ -373,7 +373,7 @@ fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
     ///  | fn foo(x: &u32) { .. }
     ///           ------- fully elaborated type of `x` is `&'1 u32`
     /// ```
-    #[tracing::instrument(level = "trace", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     fn give_name_if_anonymous_region_appears_in_arguments(
         &self,
         fr: RegionVid,
@@ -662,7 +662,7 @@ fn try_match_adt_and_generic_args<'hir>(
     ///  | let x = Some(&22);
     ///        - fully elaborated type of `x` is `Option<&'1 u32>`
     /// ```
-    #[tracing::instrument(level = "trace", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
         let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
         let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
@@ -682,7 +682,7 @@ fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Opti
     /// must be a closure since, in a free fn, such an argument would
     /// have to either also appear in an argument (if using elision)
     /// or be early bound (named, not in argument).
-    #[tracing::instrument(level = "trace", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> {
         let tcx = self.infcx.tcx;
         let hir = tcx.hir();
@@ -814,7 +814,7 @@ fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::
         }
     }
 
-    #[tracing::instrument(level = "trace", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     fn give_name_if_anonymous_region_appears_in_yield_ty(
         &self,
         fr: RegionVid,
index 0f8afb038f455c8393b671a4a05ff97976d81916..20c22575bd1fadcd27e20412204801a0f34184d0 100644 (file)
@@ -2,6 +2,7 @@
 
 #![allow(rustc::potential_query_instability)]
 #![feature(box_patterns)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(never_type)]
@@ -975,6 +976,7 @@ fn access_place(
         }
     }
 
+    #[instrument(level = "debug", skip(self, flow_state))]
     fn check_access_for_conflict(
         &mut self,
         location: Location,
@@ -983,11 +985,6 @@ fn check_access_for_conflict(
         rw: ReadOrWrite,
         flow_state: &Flows<'cx, 'tcx>,
     ) -> bool {
-        debug!(
-            "check_access_for_conflict(location={:?}, place_span={:?}, sd={:?}, rw={:?})",
-            location, place_span, sd, rw,
-        );
-
         let mut error_reported = false;
         let tcx = self.infcx.tcx;
         let body = self.body;
@@ -1451,13 +1448,13 @@ fn consume_operand(
 
     /// Checks whether a borrow of this place is invalidated when the function
     /// exits
+    #[instrument(level = "debug", skip(self))]
     fn check_for_invalidation_at_exit(
         &mut self,
         location: Location,
         borrow: &BorrowData<'tcx>,
         span: Span,
     ) {
-        debug!("check_for_invalidation_at_exit({:?})", borrow);
         let place = borrow.borrowed_place;
         let mut root_place = PlaceRef { local: place.local, projection: &[] };
 
index 97335fd0dffaeb4d28205c7adfd76654f4e4706e..6e5a96bee97e69031aebbf99662632eb9807249b 100644 (file)
@@ -44,6 +44,7 @@ pub(crate) fn places_conflict<'tcx>(
 /// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime
 /// array indices, for example) should be interpreted - this depends on what the caller wants in
 /// order to make the conservative choice and preserve soundness.
+#[instrument(level = "debug", skip(tcx, body))]
 pub(super) fn borrow_conflicts_with_place<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
@@ -53,11 +54,6 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
     access: AccessDepth,
     bias: PlaceConflictBias,
 ) -> bool {
-    debug!(
-        "borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})",
-        borrow_place, access_place, access, bias,
-    );
-
     // This Local/Local case is handled by the more general code below, but
     // it's so common that it's a speed win to check for it first.
     if let Some(l1) = borrow_place.as_local() && let Some(l2) = access_place.as_local() {
@@ -140,10 +136,9 @@ fn place_components_conflict<'tcx>(
     for (i, (borrow_c, &access_c)) in
         iter::zip(borrow_place.projection, access_place.projection).enumerate()
     {
-        debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
-        let borrow_proj_base = &borrow_place.projection[..i];
+        debug!(?borrow_c, ?access_c);
 
-        debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
+        let borrow_proj_base = &borrow_place.projection[..i];
 
         // Borrow and access path both have more components.
         //
@@ -180,7 +175,7 @@ fn place_components_conflict<'tcx>(
                 // idea, at least for now, so just give up and
                 // report a conflict. This is unsafe code anyway so
                 // the user could always use raw pointers.
-                debug!("borrow_conflicts_with_place: arbitrary -> conflict");
+                debug!("arbitrary -> conflict");
                 return true;
             }
             Overlap::EqualOrDisjoint => {
@@ -189,7 +184,7 @@ fn place_components_conflict<'tcx>(
             Overlap::Disjoint => {
                 // We have proven the borrow disjoint - further
                 // projections will remain disjoint.
-                debug!("borrow_conflicts_with_place: disjoint");
+                debug!("disjoint");
                 return false;
             }
         }
index 2894c6d29ec43978ec1e5fac7ee3de67e8e1cb56..8dc9368a0b994d197943ea914fa19b6578b554dc 100644 (file)
@@ -1139,7 +1139,7 @@ fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
     ///   include the CFG anyhow.
     /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
     ///   a result `'y`.
-    #[instrument(skip(self), level = "debug")]
+    #[instrument(skip(self), level = "debug", ret)]
     pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
         debug!(r = %self.region_value_str(r));
 
@@ -1151,8 +1151,6 @@ pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
             lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
         }
 
-        debug!(?lub);
-
         lub
     }
 
@@ -1167,8 +1165,9 @@ pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
     /// Therefore, this method should only be used in diagnostic code,
     /// where displaying *some* named universal region is better than
     /// falling back to 'static.
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
-        debug!("approx_universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
+        debug!("{}", self.region_value_str(r));
 
         // Find the smallest universal region that contains all other
         // universal regions within `region`.
@@ -1177,7 +1176,7 @@ pub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
         let static_r = self.universal_regions.fr_static;
         for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
             let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
-            debug!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub);
+            debug!(?ur, ?lub, ?new_lub);
             // The upper bound of two non-static regions is static: this
             // means we know nothing about the relationship between these
             // two regions. Pick a 'better' one to use when constructing
@@ -1201,7 +1200,7 @@ pub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
             }
         }
 
-        debug!("approx_universal_upper_bound: r={:?} lub={:?}", r, lub);
+        debug!(?r, ?lub);
 
         lub
     }
@@ -1332,15 +1331,15 @@ fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool {
     }
 
     // Evaluate whether `sup_region: sub_region`.
-    #[instrument(skip(self), level = "debug")]
+    #[instrument(skip(self), level = "debug", ret)]
     fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
         debug!(
-            "eval_outlives: sup_region's value = {:?} universal={:?}",
+            "sup_region's value = {:?} universal={:?}",
             self.region_value_str(sup_region),
             self.universal_regions.is_universal_region(sup_region),
         );
         debug!(
-            "eval_outlives: sub_region's value = {:?} universal={:?}",
+            "sub_region's value = {:?} universal={:?}",
             self.region_value_str(sub_region),
             self.universal_regions.is_universal_region(sub_region),
         );
@@ -1353,7 +1352,7 @@ fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
         // true if `'sup` outlives static.
         if !self.universe_compatible(sub_region_scc, sup_region_scc) {
             debug!(
-                "eval_outlives: sub universe `{sub_region_scc:?}` is not nameable \
+                "sub universe `{sub_region_scc:?}` is not nameable \
                 by super `{sup_region_scc:?}`, promoting to static",
             );
 
@@ -1374,9 +1373,7 @@ fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
             });
 
         if !universal_outlives {
-            debug!(
-                "eval_outlives: returning false because sub region contains a universal region not present in super"
-            );
+            debug!("sub region contains a universal region not present in super");
             return false;
         }
 
@@ -1385,15 +1382,13 @@ fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
 
         if self.universal_regions.is_universal_region(sup_region) {
             // Micro-opt: universal regions contain all points.
-            debug!(
-                "eval_outlives: returning true because super is universal and hence contains all points"
-            );
+            debug!("super is universal and hence contains all points");
             return true;
         }
 
-        let result = self.scc_values.contains_points(sup_region_scc, sub_region_scc);
-        debug!("returning {} because of comparison between points in sup/sub", result);
-        result
+        debug!("comparison between points in sup/sub");
+
+        self.scc_values.contains_points(sup_region_scc, sub_region_scc)
     }
 
     /// Once regions have been propagated, this method is used to see
@@ -1970,7 +1965,7 @@ pub(crate) fn find_constraint_paths_between_regions(
     }
 
     /// Finds some region R such that `fr1: R` and `R` is live at `elem`.
-    #[instrument(skip(self), level = "trace")]
+    #[instrument(skip(self), level = "trace", ret)]
     pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
         trace!(scc = ?self.constraint_sccs.scc(fr1));
         trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]);
@@ -2048,6 +2043,7 @@ pub(crate) fn universal_regions(&self) -> &UniversalRegions<'tcx> {
     /// creating a constraint path that forces `R` to outlive
     /// `from_region`, and then finding the best choices within that
     /// path to blame.
+    #[instrument(level = "debug", skip(self, target_test))]
     pub(crate) fn best_blame_constraint(
         &self,
         body: &Body<'tcx>,
@@ -2055,16 +2051,11 @@ pub(crate) fn best_blame_constraint(
         from_region_origin: NllRegionVariableOrigin,
         target_test: impl Fn(RegionVid) -> bool,
     ) -> BlameConstraint<'tcx> {
-        debug!(
-            "best_blame_constraint(from_region={:?}, from_region_origin={:?})",
-            from_region, from_region_origin
-        );
-
         // Find all paths
         let (path, target_region) =
             self.find_constraint_paths_between_regions(from_region, target_test).unwrap();
         debug!(
-            "best_blame_constraint: path={:#?}",
+            "path={:#?}",
             path.iter()
                 .map(|c| format!(
                     "{:?} ({:?}: {:?})",
@@ -2116,7 +2107,7 @@ pub(crate) fn best_blame_constraint(
                 }
             })
             .collect();
-        debug!("best_blame_constraint: categorized_path={:#?}", categorized_path);
+        debug!("categorized_path={:#?}", categorized_path);
 
         // To find the best span to cite, we first try to look for the
         // final constraint that is interesting and where the `sup` is
@@ -2214,10 +2205,7 @@ pub(crate) fn best_blame_constraint(
         let best_choice =
             if blame_source { range.rev().find(find_region) } else { range.find(find_region) };
 
-        debug!(
-            "best_blame_constraint: best_choice={:?} blame_source={}",
-            best_choice, blame_source
-        );
+        debug!(?best_choice, ?blame_source);
 
         if let Some(i) = best_choice {
             if let Some(next) = categorized_path.get(i + 1) {
@@ -2254,7 +2242,7 @@ pub(crate) fn best_blame_constraint(
         // appears to be the most interesting point to report to the
         // user via an even more ad-hoc guess.
         categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
-        debug!("best_blame_constraint: sorted_path={:#?}", categorized_path);
+        debug!("sorted_path={:#?}", categorized_path);
 
         categorized_path.remove(0)
     }
index 127cb4e408372e800e9ef7380f04c8ee59cf9e8d..0392367288c40544cad175913f68626a3ca9684d 100644 (file)
@@ -60,7 +60,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
     /// which has no `external_name` in which case we use `'empty` as the
     /// region to pass to `infer_opaque_definition_from_instantiation`.
-    #[instrument(level = "debug", skip(self, infcx))]
+    #[instrument(level = "debug", skip(self, infcx), ret)]
     pub(crate) fn infer_opaque_types(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
index 451b82c5c18700f07f1967ab571f604ebc9cf584..29195b3922fcdb24dc8734caa8f03dcb5f9ce230 100644 (file)
@@ -24,7 +24,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     /// **Any `rustc_infer::infer` operations that might generate region
     /// constraints should occur within this method so that those
     /// constraints can be properly localized!**
-    #[instrument(skip(self, category, op), level = "trace")]
+    #[instrument(skip(self, op), level = "trace")]
     pub(super) fn fully_perform_op<R, Op>(
         &mut self,
         locations: Locations,
index c1812aa4bbab65fda259c44278df2cba74debdba..a620c987052ba0b987175df02e70fc9e5d3b9cd6 100644 (file)
@@ -1043,6 +1043,7 @@ fn check_user_type_annotations(&mut self) {
             let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
             let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
             let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
+            debug!(?annotation);
             match annotation {
                 UserType::Ty(mut ty) => {
                     ty = self.normalize(ty, Locations::All(span));
index 2a7713bc4df3b6d1e8be939ef07799a5c412f820..b9b181681ec4b7495cf63f925799d205cdaff281 100644 (file)
@@ -768,10 +768,9 @@ fn replace_late_bound_regions_with_nll_infer_vars(
         mir_def_id: LocalDefId,
         indices: &mut UniversalRegionIndices<'tcx>,
     ) {
-        debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
         let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
         for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
-            debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
+            debug!(?r);
             if !indices.indices.contains_key(&r) {
                 let region_vid = self.next_nll_region_var(FR);
                 debug!(?region_vid);
index 8d8e9d9b5ff4e03a5b8496f36b406a1a7746da3b..6469d0d7b88a68440c2b27735de6aede13a93f39 100644 (file)
@@ -7,20 +7,21 @@ edition = "2021"
 doctest = false
 
 [dependencies]
-rustc_parse_format = { path = "../rustc_parse_format" }
-tracing = "0.1"
+rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
+rustc_expand = { path = "../rustc_expand" }
 rustc_feature = { path = "../rustc_feature" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_lint_defs = { path = "../rustc_lint_defs" }
 rustc_macros = { path = "../rustc_macros" }
+rustc_parse_format = { path = "../rustc_parse_format" }
 rustc_parse = { path = "../rustc_parse" }
-rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
-smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-rustc_ast = { path = "../rustc_ast" }
-rustc_expand = { path = "../rustc_expand" }
 rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
+smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+thin-vec = "0.2.8"
+tracing = "0.1"
index d2ee4249989ee396a8195ae9030b70be35b55564..973a8cb85c2b9c12b652f8f60e81cda603377550 100644 (file)
@@ -13,6 +13,7 @@
     symbol::{sym, Ident, Symbol},
     Span,
 };
+use thin_vec::thin_vec;
 
 pub(super) struct Context<'cx, 'a> {
     // An optimization.
@@ -116,11 +117,10 @@ fn build_initial_imports(&self) -> Stmt {
             self.cx.item(
                 self.span,
                 Ident::empty(),
-                vec![self.cx.attribute(attr::mk_list_item(
+                thin_vec![self.cx.attribute(attr::mk_list_item(
                     Ident::new(sym::allow, self.span),
                     vec![attr::mk_nested_word_item(Ident::new(sym::unused_imports, self.span))],
-                ))]
-                .into(),
+                ))],
                 ItemKind::Use(UseTree {
                     prefix: self.cx.path(self.span, self.cx.std_path(&[sym::asserting])),
                     kind: UseTreeKind::Nested(vec![
index dd7989cf48c37b784cd37fdc7020e71bcea334bc..c7f2d95e72f0c45e817a06b5e149ecdd0f1ec1cf 100644 (file)
@@ -1,12 +1,12 @@
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::path_std;
-
 use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, VariantData};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
+use thin_vec::thin_vec;
 
 pub fn expand_deriving_clone(
     cx: &mut ExtCtxt<'_>,
@@ -68,7 +68,7 @@ pub fn expand_deriving_clone(
     }
 
     let inline = cx.meta_word(span, sym::inline);
-    let attrs = vec![cx.attribute(inline)].into();
+    let attrs = thin_vec![cx.attribute(inline)];
     let trait_def = TraitDef {
         span,
         path: path_std!(clone::Clone),
index 9b6d3e5032f9495f92caad1231e79e01680e7d05..5b556c5c9b9d1848c25193dcc1ecb64d0010c0a8 100644 (file)
@@ -7,6 +7,7 @@
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
+use thin_vec::thin_vec;
 
 pub fn expand_deriving_eq(
     cx: &mut ExtCtxt<'_>,
@@ -20,7 +21,7 @@ pub fn expand_deriving_eq(
     let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span));
     let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]);
     let no_coverage = cx.meta_word(span, sym::no_coverage);
-    let attrs = vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)].into();
+    let attrs = thin_vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)];
     let trait_def = TraitDef {
         span,
         path: path_std!(cmp::Eq),
index 0e17b95178759368b59147dfca1fda6751b78066..72625869558119ec908051a5e21ca8d9e718c574 100644 (file)
@@ -1,11 +1,11 @@
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::path_std;
-
 use rustc_ast::MetaItem;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
+use thin_vec::thin_vec;
 
 pub fn expand_deriving_ord(
     cx: &mut ExtCtxt<'_>,
@@ -15,7 +15,7 @@ pub fn expand_deriving_ord(
     push: &mut dyn FnMut(Annotatable),
 ) {
     let inline = cx.meta_word(span, sym::inline);
-    let attrs = vec![cx.attribute(inline)].into();
+    let attrs = thin_vec![cx.attribute(inline)];
     let trait_def = TraitDef {
         span,
         path: path_std!(cmp::Ord),
index ac1325b92a6f38ed38acd385baded5839cdb076f..42ee65b570a2a95a2fff7ee0f6ffe794661673ae 100644 (file)
@@ -1,12 +1,12 @@
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::{path_local, path_std};
-
 use rustc_ast::ptr::P;
 use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use thin_vec::thin_vec;
 
 pub fn expand_deriving_partial_eq(
     cx: &mut ExtCtxt<'_>,
@@ -68,7 +68,7 @@ fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOr
     // No need to generate `ne`, the default suffices, and not generating it is
     // faster.
     let inline = cx.meta_word(span, sym::inline);
-    let attrs = vec![cx.attribute(inline)].into();
+    let attrs = thin_vec![cx.attribute(inline)];
     let methods = vec![MethodDef {
         name: sym::eq,
         generics: Bounds::empty(),
index 7763e55401783b19670703c070c72fa418e2117f..516892aeda96f9da303e693e041542bf6ab8916b 100644 (file)
@@ -1,11 +1,11 @@
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::{path_std, pathvec_std};
-
 use rustc_ast::MetaItem;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
+use thin_vec::thin_vec;
 
 pub fn expand_deriving_partial_ord(
     cx: &mut ExtCtxt<'_>,
@@ -19,7 +19,7 @@ pub fn expand_deriving_partial_ord(
         Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));
 
     let inline = cx.meta_word(span, sym::inline);
-    let attrs = vec![cx.attribute(inline)].into();
+    let attrs = thin_vec![cx.attribute(inline)];
 
     let partial_cmp_def = MethodDef {
         name: sym::partial_cmp,
index f316f01ef66152e7bb1b3308ce9c924b0d80b6e2..a94c8a996e6423fbf1151ace70f135a89f6cd6f0 100644 (file)
@@ -1,6 +1,5 @@
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
-
 use rustc_ast as ast;
 use rustc_ast::{walk_list, EnumDef, VariantData};
 use rustc_errors::Applicability;
@@ -9,6 +8,7 @@
 use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
 use smallvec::SmallVec;
+use thin_vec::thin_vec;
 
 pub fn expand_deriving_default(
     cx: &mut ExtCtxt<'_>,
@@ -20,7 +20,7 @@ pub fn expand_deriving_default(
     item.visit_with(&mut DetectNonVariantDefaultAttr { cx });
 
     let inline = cx.meta_word(span, sym::inline);
-    let attrs = vec![cx.attribute(inline)].into();
+    let attrs = thin_vec![cx.attribute(inline)];
     let trait_def = TraitDef {
         span,
         path: Path::new(vec![kw::Default, sym::Default]),
index ecaafd0fc2652946fd2afb73a79b1d4592477b77..adffebd3fd2850af0f0206ac03391d12940270a7 100644 (file)
 pub use StaticFields::*;
 pub use SubstructureFields::*;
 
-use std::cell::RefCell;
-use std::iter;
-use std::vec;
-
+use crate::deriving;
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, EnumDef, Expr, Generics, PatKind};
 use rustc_ast::{GenericArg, GenericParamKind, VariantData};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
-
+use std::cell::RefCell;
+use std::iter;
+use std::vec;
+use thin_vec::thin_vec;
 use ty::{Bounds, Path, Ref, Self_, Ty};
 
-use crate::deriving;
-
 pub mod ty;
 
 pub struct TraitDef<'a> {
@@ -715,7 +713,7 @@ fn create_derived_impl(
         let self_type = cx.ty_path(path);
 
         let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived));
-        let attrs = vec![attr].into();
+        let attrs = thin_vec![attr];
         let opt_trait_ref = Some(trait_ref);
 
         cx.item(
index 2816f81fef1218a9a5aa7f5de81d4ea675d135ee..210048710751702a4c278b844536e16a85c97968 100644 (file)
@@ -541,7 +541,7 @@ fn verify_count(
     ) {
         match c {
             parse::CountImplied | parse::CountIs(..) => {}
-            parse::CountIsParam(i) => {
+            parse::CountIsParam(i) | parse::CountIsStar(i) => {
                 self.unused_names_lint.maybe_add_positional_named_arg(
                     self.args.get(i),
                     named_arg_type,
@@ -589,7 +589,7 @@ fn report_invalid_references(&self, numbered_position_args: bool) {
             + self
                 .arg_with_formatting
                 .iter()
-                .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
+                .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
                 .count();
         if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
             e = self.ecx.struct_span_err(
@@ -639,7 +639,7 @@ fn report_invalid_references(&self, numbered_position_args: bool) {
             if let Some(span) = fmt.precision_span {
                 let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
                 match fmt.precision {
-                    parse::CountIsParam(pos) if pos > self.num_args() => {
+                    parse::CountIsParam(pos) if pos >= self.num_args() => {
                         e.span_label(
                             span,
                             &format!(
@@ -651,12 +651,12 @@ fn report_invalid_references(&self, numbered_position_args: bool) {
                         );
                         zero_based_note = true;
                     }
-                    parse::CountIsParam(pos) => {
+                    parse::CountIsStar(pos) => {
                         let count = self.pieces.len()
                             + self
                                 .arg_with_formatting
                                 .iter()
-                                .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
+                                .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
                                 .count();
                         e.span_label(
                             span,
@@ -837,7 +837,7 @@ fn build_count(&self, c: parse::Count<'_>) -> P<ast::Expr> {
         };
         match c {
             parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))),
-            parse::CountIsParam(i) => {
+            parse::CountIsParam(i) | parse::CountIsStar(i) => {
                 // This needs mapping too, as `i` is referring to a macro
                 // argument. If `i` is not found in `count_positions` then
                 // the error had already been emitted elsewhere.
index 2bad9bbce6650b30af53e970bd90a0ae21287552..45b9b8ab6b6410e0034793b06f8f77cfc4888504 100644 (file)
@@ -9,6 +9,7 @@
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
+use thin_vec::thin_vec;
 
 pub fn expand(
     ecx: &mut ExtCtxt<'_>,
@@ -116,7 +117,7 @@ fn call_allocator(&self, method: Symbol, mut args: Vec<P<Expr>>) -> P<Expr> {
     fn attrs(&self) -> AttrVec {
         let special = sym::rustc_std_internal_symbol;
         let special = self.cx.meta_word(self.span, special);
-        vec![self.cx.attribute(special)].into()
+        thin_vec![self.cx.attribute(special)]
     }
 
     fn arg_ty(
index 48e81eb13c0c6a6bf675b62428eff8f05864d573..280fa70451141f85f821c2f2b02e0f87f82d5a83 100644 (file)
@@ -8,6 +8,7 @@
 #![feature(decl_macro)]
 #![feature(if_let_guard)]
 #![feature(is_sorted)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_quote)]
@@ -15,6 +16,9 @@
 
 extern crate proc_macro;
 
+#[macro_use]
+extern crate tracing;
+
 use crate::deriving::*;
 
 use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
index 90ea1e457ba8031885f3941cb605e00e52590c0f..49ef538f04e14ab83ffe4ed173e5646b7ca40d30 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_span::hygiene::AstPass;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::DUMMY_SP;
+use thin_vec::thin_vec;
 
 pub fn inject(
     mut krate: ast::Crate,
@@ -51,7 +52,7 @@ pub fn inject(
             cx.item(
                 span,
                 ident,
-                vec![cx.attribute(cx.meta_word(span, sym::macro_use))].into(),
+                thin_vec![cx.attribute(cx.meta_word(span, sym::macro_use))],
                 ast::ItemKind::ExternCrate(None),
             ),
         );
@@ -78,7 +79,7 @@ pub fn inject(
     let use_item = cx.item(
         span,
         Ident::empty(),
-        vec![cx.attribute(cx.meta_word(span, sym::prelude_import))].into(),
+        thin_vec![cx.attribute(cx.meta_word(span, sym::prelude_import))],
         ast::ItemKind::Use(ast::UseTree {
             prefix: cx.path(span, import_path),
             kind: ast::UseTreeKind::Glob,
index 03c84f5ec2a740fe1f158099885719b5369477c6..7efb6cc61eecbb2325525c4696b5b5b7c9040c8a 100644 (file)
@@ -1,7 +1,6 @@
 /// The expansion from a test function to the appropriate test struct for libtest
 /// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
 use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
-
 use rustc_ast as ast;
 use rustc_ast::attr;
 use rustc_ast::ptr::P;
@@ -11,8 +10,8 @@
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
-
 use std::iter;
+use thin_vec::thin_vec;
 
 // #[test_case] is used by custom test authors to mark tests
 // When building for test, it needs to make the item public and gensym the name
@@ -219,7 +218,7 @@ pub fn expand_test_or_bench(
     let mut test_const = cx.item(
         sp,
         Ident::new(item.ident.name, sp),
-        vec![
+        thin_vec![
             // #[cfg(test)]
             cx.attribute(attr::mk_list_item(
                 Ident::new(sym::cfg, attr_sp),
@@ -227,8 +226,7 @@ pub fn expand_test_or_bench(
             )),
             // #[rustc_test_marker]
             cx.attribute(cx.meta_word(attr_sp, sym::rustc_test_marker)),
-        ]
-        .into(),
+        ],
         // const $ident: test::TestDescAndFn =
         ast::ItemKind::Const(
             ast::Defaultness::Final,
@@ -337,7 +335,7 @@ pub fn expand_test_or_bench(
     // extern crate test
     let test_extern = cx.item(sp, test_id, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None));
 
-    tracing::debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
+    debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
 
     if is_stmt {
         vec![
index 093f0f10a3867e591108604f1547841a960ff125..079c6ff37cfb53222caeaf79014ebda64fa65716 100644 (file)
@@ -14,7 +14,7 @@
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::PanicStrategy;
 use smallvec::{smallvec, SmallVec};
-use tracing::debug;
+use thin_vec::thin_vec;
 
 use std::{iter, mem};
 
@@ -335,7 +335,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
 
     let main = P(ast::Item {
         ident: main_id,
-        attrs: vec![main_attr].into(),
+        attrs: thin_vec![main_attr],
         id: ast::DUMMY_NODE_ID,
         kind: main,
         vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None },
index 815450f689e4ab50c4957a35d5ee90faf22ca7e9..0497c2570e6228b3984b639805ebbdef0bd6d07b 100644 (file)
@@ -342,7 +342,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
 
     let ret_place = codegen_place(fx, destination);
 
-    // Handle special calls like instrinsics and empty drop glue.
+    // Handle special calls like intrinsics and empty drop glue.
     let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
         let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs)
             .unwrap()
index 3011813c7035b56ae39bbc80fd1852fbae466154..c412e451a033e9619f2630e5362b5e0c12b4e08c 100644 (file)
@@ -925,8 +925,11 @@ pub(crate) fn codegen_panic_inner<'tcx>(
     args: &[Value],
     span: Span,
 ) {
-    let def_id =
-        fx.tcx.lang_items().require(lang_item).unwrap_or_else(|s| fx.tcx.sess.span_fatal(span, &s));
+    let def_id = fx
+        .tcx
+        .lang_items()
+        .require(lang_item)
+        .unwrap_or_else(|e| fx.tcx.sess.span_fatal(span, e.to_string()));
 
     let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
     let symbol_name = fx.tcx.symbol_name(instance).name;
index e2b68f24a21dc699becffd75ff9afec81c8fa8ef..9224f499339cbd8e14cf6d5d75e8adaf608362a0 100644 (file)
@@ -59,7 +59,7 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
                         ErrorHandled::TooGeneric => {
                             span_bug!(
                                 constant.span,
-                                "codgen encountered polymorphic constant: {:?}",
+                                "codegen encountered polymorphic constant: {:?}",
                                 err
                             );
                         }
@@ -430,7 +430,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
         let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec();
         data_ctx.define(bytes.into_boxed_slice());
 
-        for &(offset, alloc_id) in alloc.relocations().iter() {
+        for &(offset, alloc_id) in alloc.provenance().iter() {
             let addend = {
                 let endianness = tcx.data_layout.endian;
                 let offset = offset.bytes() as usize;
index 95239f415a99b5e88c965b37aab3cc860cdf97a3..39e9e784a478b12a68268e2fa6c0b6209f864365 100644 (file)
@@ -203,7 +203,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             sym::transmute => {
                 crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info);
             }
-            _ => unimplemented!("unsupported instrinsic {}", intrinsic),
+            _ => unimplemented!("unsupported intrinsic {}", intrinsic),
         }
         return;
     };
index a32b413d45f938d093f7f4efcae7e3a8fc2a240a..1f358b1bbb96edb89a2893cf9bc526f6dbcc79b9 100644 (file)
@@ -186,7 +186,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                         let size = Size::from_bytes(
                             4 * ret_lane_count, /* size_of([u32; ret_lane_count]) */
                         );
-                        alloc.inner().get_bytes(fx, alloc_range(offset, size)).unwrap()
+                        alloc
+                            .inner()
+                            .get_bytes_strip_provenance(fx, alloc_range(offset, size))
+                            .unwrap()
                     }
                     _ => unreachable!("{:?}", idx_const),
                 };
index c67b6e98b32c7daeeca8558ed2882f082cd0b103..3c024a84d9091f1fb3bf1533443d4ed5bed5a27d 100644 (file)
@@ -1,7 +1,7 @@
 use rustc_hir::LangItem;
 use rustc_middle::ty::subst::GenericArg;
 use rustc_middle::ty::AssocKind;
-use rustc_session::config::EntryFnType;
+use rustc_session::config::{sigpipe, EntryFnType};
 use rustc_span::symbol::Ident;
 
 use crate::prelude::*;
@@ -15,12 +15,12 @@ pub(crate) fn maybe_create_entry_wrapper(
     is_jit: bool,
     is_primary_cgu: bool,
 ) {
-    let (main_def_id, is_main_fn) = match tcx.entry_fn(()) {
+    let (main_def_id, (is_main_fn, sigpipe)) = match tcx.entry_fn(()) {
         Some((def_id, entry_ty)) => (
             def_id,
             match entry_ty {
-                EntryFnType::Main => true,
-                EntryFnType::Start => false,
+                EntryFnType::Main { sigpipe } => (true, sigpipe),
+                EntryFnType::Start => (false, sigpipe::DEFAULT),
             },
         ),
         None => return,
@@ -35,7 +35,7 @@ pub(crate) fn maybe_create_entry_wrapper(
         return;
     }
 
-    create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn);
+    create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn, sigpipe);
 
     fn create_entry_fn(
         tcx: TyCtxt<'_>,
@@ -44,6 +44,7 @@ fn create_entry_fn(
         rust_main_def_id: DefId,
         ignore_lang_start_wrapper: bool,
         is_main_fn: bool,
+        sigpipe: u8,
     ) {
         let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
         // Given that `main()` has no arguments,
@@ -83,6 +84,7 @@ fn create_entry_fn(
             bcx.switch_to_block(block);
             let arg_argc = bcx.append_block_param(block, m.target_config().pointer_type());
             let arg_argv = bcx.append_block_param(block, m.target_config().pointer_type());
+            let arg_sigpipe = bcx.ins().iconst(types::I8, sigpipe as i64);
 
             let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);
 
@@ -143,7 +145,8 @@ fn create_entry_fn(
                 let main_val = bcx.ins().func_addr(m.target_config().pointer_type(), main_func_ref);
 
                 let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
-                let call_inst = bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv]);
+                let call_inst =
+                    bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv, arg_sigpipe]);
                 bcx.inst_results(call_inst)[0]
             } else {
                 // using user-defined start fn
index 4d40dd0994dd23057089a47241e36ce0f4f3ecd7..6994eeb00c3e2e6de92639e6039d5e00e8d0c63a 100644 (file)
     Type,
     UnaryOp,
 };
+use rustc_apfloat::{ieee, Float, Round, Status};
 use rustc_codegen_ssa::MemFlags;
-use rustc_codegen_ssa::common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope};
+use rustc_codegen_ssa::common::{
+    AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
+};
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::{
@@ -31,6 +34,7 @@
     StaticBuilderMethods,
 };
 use rustc_data_structures::fx::FxHashSet;
+use rustc_middle::bug;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_span::Span;
@@ -1271,12 +1275,12 @@ fn to_immediate_scalar(&mut self, val: Self::Value, scalar: abi::Scalar) -> Self
         val
     }
 
-    fn fptoui_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option<RValue<'gcc>> {
-        None
+    fn fptoui_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.fptoint_sat(false, val, dest_ty)
     }
 
-    fn fptosi_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option<RValue<'gcc>> {
-        None
+    fn fptosi_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.fptoint_sat(true, val, dest_ty)
     }
 
     fn instrprof_increment(&mut self, _fn_name: RValue<'gcc>, _hash: RValue<'gcc>, _num_counters: RValue<'gcc>, _index: RValue<'gcc>) {
@@ -1285,6 +1289,166 @@ fn instrprof_increment(&mut self, _fn_name: RValue<'gcc>, _hash: RValue<'gcc>, _
 }
 
 impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
+    fn fptoint_sat(&mut self, signed: bool, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        let src_ty = self.cx.val_ty(val);
+        let (float_ty, int_ty) = if self.cx.type_kind(src_ty) == TypeKind::Vector {
+            assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty));
+            (self.cx.element_type(src_ty), self.cx.element_type(dest_ty))
+        } else {
+            (src_ty, dest_ty)
+        };
+
+        // FIXME(jistone): the following was originally the fallback SSA implementation, before LLVM 13
+        // added native `fptosi.sat` and `fptoui.sat` conversions, but it was used by GCC as well.
+        // Now that LLVM always relies on its own, the code has been moved to GCC, but the comments are
+        // still LLVM-specific. This should be updated, and use better GCC specifics if possible.
+
+        let int_width = self.cx.int_width(int_ty);
+        let float_width = self.cx.float_width(float_ty);
+        // LLVM's fpto[su]i returns undef when the input val is infinite, NaN, or does not fit into the
+        // destination integer type after rounding towards zero. This `undef` value can cause UB in
+        // safe code (see issue #10184), so we implement a saturating conversion on top of it:
+        // Semantically, the mathematical value of the input is rounded towards zero to the next
+        // mathematical integer, and then the result is clamped into the range of the destination
+        // integer type. Positive and negative infinity are mapped to the maximum and minimum value of
+        // the destination integer type. NaN is mapped to 0.
+        //
+        // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to
+        // a value representable in int_ty.
+        // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits.
+        // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two.
+        // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly
+        // representable. Note that this only works if float_ty's exponent range is sufficiently large.
+        // f16 or 256 bit integers would break this property. Right now the smallest float type is f32
+        // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127.
+        // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
+        // we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
+        // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
+        let int_max = |signed: bool, int_width: u64| -> u128 {
+            let shift_amount = 128 - int_width;
+            if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
+        };
+        let int_min = |signed: bool, int_width: u64| -> i128 {
+            if signed { i128::MIN >> (128 - int_width) } else { 0 }
+        };
+
+        let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
+            let rounded_min =
+                ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);
+            assert_eq!(rounded_min.status, Status::OK);
+            let rounded_max =
+                ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero);
+            assert!(rounded_max.value.is_finite());
+            (rounded_min.value.to_bits(), rounded_max.value.to_bits())
+        };
+        let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) {
+            let rounded_min =
+                ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
+            assert_eq!(rounded_min.status, Status::OK);
+            let rounded_max =
+                ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
+            assert!(rounded_max.value.is_finite());
+            (rounded_min.value.to_bits(), rounded_max.value.to_bits())
+        };
+        // To implement saturation, we perform the following steps:
+        //
+        // 1. Cast val to an integer with fpto[su]i. This may result in undef.
+        // 2. Compare val to f_min and f_max, and use the comparison results to select:
+        //  a) int_ty::MIN if val < f_min or val is NaN
+        //  b) int_ty::MAX if val > f_max
+        //  c) the result of fpto[su]i otherwise
+        // 3. If val is NaN, return 0.0, otherwise return the result of step 2.
+        //
+        // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the
+        // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of
+        // undef does not introduce any non-determinism either.
+        // More importantly, the above procedure correctly implements saturating conversion.
+        // Proof (sketch):
+        // If val is NaN, 0 is returned by definition.
+        // Otherwise, val is finite or infinite and thus can be compared with f_min and f_max.
+        // This yields three cases to consider:
+        // (1) if val in [f_min, f_max], the result of fpto[su]i is returned, which agrees with
+        //     saturating conversion for inputs in that range.
+        // (2) if val > f_max, then val is larger than int_ty::MAX. This holds even if f_max is rounded
+        //     (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger
+        //     than int_ty::MAX. Because val is larger than int_ty::MAX, the return value of int_ty::MAX
+        //     is correct.
+        // (3) if val < f_min, then val is smaller than int_ty::MIN. As shown earlier, f_min exactly equals
+        //     int_ty::MIN and therefore the return value of int_ty::MIN is correct.
+        // QED.
+
+        let float_bits_to_llval = |bx: &mut Self, bits| {
+            let bits_llval = match float_width {
+                32 => bx.cx().const_u32(bits as u32),
+                64 => bx.cx().const_u64(bits as u64),
+                n => bug!("unsupported float width {}", n),
+            };
+            bx.bitcast(bits_llval, float_ty)
+        };
+        let (f_min, f_max) = match float_width {
+            32 => compute_clamp_bounds_single(signed, int_width),
+            64 => compute_clamp_bounds_double(signed, int_width),
+            n => bug!("unsupported float width {}", n),
+        };
+        let f_min = float_bits_to_llval(self, f_min);
+        let f_max = float_bits_to_llval(self, f_max);
+        let int_max = self.cx.const_uint_big(int_ty, int_max(signed, int_width));
+        let int_min = self.cx.const_uint_big(int_ty, int_min(signed, int_width) as u128);
+        let zero = self.cx.const_uint(int_ty, 0);
+
+        // If we're working with vectors, constants must be "splatted": the constant is duplicated
+        // into each lane of the vector.  The algorithm stays the same, we are just using the
+        // same constant across all lanes.
+        let maybe_splat = |bx: &mut Self, val| {
+            if bx.cx().type_kind(dest_ty) == TypeKind::Vector {
+                bx.vector_splat(bx.vector_length(dest_ty), val)
+            } else {
+                val
+            }
+        };
+        let f_min = maybe_splat(self, f_min);
+        let f_max = maybe_splat(self, f_max);
+        let int_max = maybe_splat(self, int_max);
+        let int_min = maybe_splat(self, int_min);
+        let zero = maybe_splat(self, zero);
+
+        // Step 1 ...
+        let fptosui_result = if signed { self.fptosi(val, dest_ty) } else { self.fptoui(val, dest_ty) };
+        let less_or_nan = self.fcmp(RealPredicate::RealULT, val, f_min);
+        let greater = self.fcmp(RealPredicate::RealOGT, val, f_max);
+
+        // Step 2: We use two comparisons and two selects, with %s1 being the
+        // result:
+        //     %less_or_nan = fcmp ult %val, %f_min
+        //     %greater = fcmp olt %val, %f_max
+        //     %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
+        //     %s1 = select %greater, int_ty::MAX, %s0
+        // Note that %less_or_nan uses an *unordered* comparison. This
+        // comparison is true if the operands are not comparable (i.e., if val is
+        // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
+        // val is NaN.
+        //
+        // Performance note: Unordered comparison can be lowered to a "flipped"
+        // comparison and a negation, and the negation can be merged into the
+        // select. Therefore, it not necessarily any more expensive than an
+        // ordered ("normal") comparison. Whether these optimizations will be
+        // performed is ultimately up to the backend, but at least x86 does
+        // perform them.
+        let s0 = self.select(less_or_nan, int_min, fptosui_result);
+        let s1 = self.select(greater, int_max, s0);
+
+        // Step 3: NaN replacement.
+        // For unsigned types, the above step already yielded int_ty::MIN == 0 if val is NaN.
+        // Therefore we only need to execute this step for signed integer types.
+        if signed {
+            // LLVM has no isNaN predicate, so we use (val == val) instead
+            let cmp = self.fcmp(RealPredicate::RealOEQ, val, val);
+            self.select(cmp, s1, zero)
+        } else {
+            s1
+        }
+    }
+
     #[cfg(feature="master")]
     pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> {
         let struct_type = mask.get_type().is_struct().expect("mask of struct type");
index c0b8d21818f854cbbea2529ed6cf81ec3efe863f..356c03ee3c189cadeacc111f37403d29911ba704 100644 (file)
@@ -127,7 +127,7 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
             //
             // We could remove this hack whenever we decide to drop macOS 10.10 support.
             if self.tcx.sess.target.options.is_like_osx {
-                // The `inspect` method is okay here because we checked relocations, and
+                // The `inspect` method is okay here because we checked for provenance, and
                 // because we are doing this access to inspect the final interpreter state
                 // (not as part of the interpreter execution).
                 //
@@ -296,17 +296,17 @@ pub fn get_static(&self, def_id: DefId) -> LValue<'gcc> {
 
 pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAllocation<'tcx>) -> RValue<'gcc> {
     let alloc = alloc.inner();
-    let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
+    let mut llvals = Vec::with_capacity(alloc.provenance().len() + 1);
     let dl = cx.data_layout();
     let pointer_size = dl.pointer_size.bytes() as usize;
 
     let mut next_offset = 0;
-    for &(offset, alloc_id) in alloc.relocations().iter() {
+    for &(offset, alloc_id) in alloc.provenance().iter() {
         let offset = offset.bytes();
         assert_eq!(offset as usize as u64, offset);
         let offset = offset as usize;
         if offset > next_offset {
-            // This `inspect` is okay since we have checked that it is not within a relocation, it
+            // This `inspect` is okay since we have checked that it is not within a pointer with provenance, it
             // is within the bounds of the allocation, and it doesn't affect interpreter execution
             // (we inspect the result after interpreter execution). Any undef byte is replaced with
             // some arbitrary byte value.
@@ -319,7 +319,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
             read_target_uint( dl.endian,
                 // This `inspect` is okay since it is within the bounds of the allocation, it doesn't
                 // affect interpreter execution (we inspect the result after interpreter execution),
-                // and we properly interpret the relocation as a relocation pointer offset.
+                // and we properly interpret the provenance as a relocation pointer offset.
                 alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)),
             )
             .expect("const_alloc_to_llvm: could not read relocation pointer")
@@ -336,7 +336,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
     }
     if alloc.len() >= next_offset {
         let range = next_offset..alloc.len();
-        // This `inspect` is okay since we have check that it is after all relocations, it is
+        // This `inspect` is okay since we have check that it is after all provenance, it is
         // within the bounds of the allocation, and it doesn't affect interpreter execution (we
         // inspect the result after interpreter execution). Any undef byte is replaced with some
         // arbitrary byte value.
index 8a206c0368fcb0ec2c7e5ad9bdecac3b99e87c16..223466fb9b51f26533243aa178b051483b563473 100644 (file)
@@ -19,6 +19,7 @@
 #![warn(rust_2018_idioms)]
 #![warn(unused_lifetimes)]
 
+extern crate rustc_apfloat;
 extern crate rustc_ast;
 extern crate rustc_codegen_ssa;
 extern crate rustc_data_structures;
index f9a5463efcd8a97c5453f1e0cb4a7fa98bb334f5..74115353aaf76267fc9e82e0710b90c29b3a157c 100644 (file)
@@ -13,6 +13,7 @@ cstr = "0.2"
 libc = "0.2"
 libloading = "0.7.1"
 measureme = "10.0.0"
+object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "archive", "coff", "elf", "macho", "pe"] }
 tracing = "0.1"
 rustc_middle = { path = "../rustc_middle" }
 rustc-demangle = "0.1.21"
index 2a6612eb86f12c62b41f516b41dfe18c5cd40806..5202ac697e9496f4551bb265de5732ed542fed72 100644 (file)
@@ -19,7 +19,6 @@
 
 use libc::{c_char, c_uint};
 use smallvec::SmallVec;
-use tracing::debug;
 
 impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
     fn codegen_inline_asm(
index 2e614e5dd88e7fc18068974f22e1e7a3a8a34df7..38a366095b41da97c9fe8906b8ab626be71935e5 100644 (file)
@@ -190,10 +190,10 @@ fn create_dll_import_lib(
 
             let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
 
-            tracing::trace!("invoking LLVMRustWriteImportLibrary");
-            tracing::trace!("  dll_name {:#?}", dll_name_z);
-            tracing::trace!("  output_path {}", output_path.display());
-            tracing::trace!(
+            trace!("invoking LLVMRustWriteImportLibrary");
+            trace!("  dll_name {:#?}", dll_name_z);
+            trace!("  output_path {}", output_path.display());
+            trace!(
                 "  import names: {}",
                 dll_imports
                     .iter()
index 3731c6bcfe77b9be7c7a21df20807341e7a78ba4..a89df00e248e30e385fe2bc35202e4879d866780 100644 (file)
@@ -1,15 +1,16 @@
 use crate::back::write::{
     self, save_temp_bitcode, to_llvm_opt_settings, with_llvm_pmb, DiagnosticHandlers,
 };
-use crate::llvm::archive_ro::ArchiveRO;
 use crate::llvm::{self, build_string, False, True};
 use crate::{llvm_util, LlvmCodegenBackend, ModuleLlvm};
+use object::read::archive::ArchiveFile;
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
 use rustc_codegen_ssa::back::symbol_export;
 use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, TargetMachineFactoryConfig};
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::memmap::Mmap;
 use rustc_errors::{FatalError, Handler};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::bug;
@@ -17,7 +18,6 @@
 use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
 use rustc_session::cgu_reuse_tracker::CguReuse;
 use rustc_session::config::{self, CrateType, Lto};
-use tracing::{debug, info};
 
 use std::ffi::{CStr, CString};
 use std::fs::File;
@@ -107,14 +107,24 @@ fn prepare_lto(
                     .extend(exported_symbols[&cnum].iter().filter_map(symbol_filter));
             }
 
-            let archive = ArchiveRO::open(path).expect("wanted an rlib");
+            let archive_data = unsafe {
+                Mmap::map(std::fs::File::open(&path).expect("couldn't open rlib"))
+                    .expect("couldn't map rlib")
+            };
+            let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib");
             let obj_files = archive
-                .iter()
-                .filter_map(|child| child.ok().and_then(|c| c.name().map(|name| (name, c))))
+                .members()
+                .filter_map(|child| {
+                    child.ok().and_then(|c| {
+                        std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c))
+                    })
+                })
                 .filter(|&(name, _)| looks_like_rust_object_file(name));
             for (name, child) in obj_files {
                 info!("adding bitcode from {}", name);
-                match get_bitcode_slice_from_object_data(child.data()) {
+                match get_bitcode_slice_from_object_data(
+                    child.data(&*archive_data).expect("corrupt rlib"),
+                ) {
                     Ok(data) => {
                         let module = SerializedModule::FromRlib(data.to_vec());
                         upstream_modules.push((module, CString::new(name).unwrap()));
index 740a68d0772c1632ba54061cc8bb783591eecfd6..a695df8409bb4621326aa87929be8851337a418a 100644 (file)
@@ -28,7 +28,6 @@
 use rustc_span::symbol::sym;
 use rustc_span::InnerSpan;
 use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo};
-use tracing::debug;
 
 use libc::{c_char, c_int, c_uint, c_void, size_t};
 use std::ffi::CString;
index 073feecb1647f1b37236479ff828f9c6ae938f09..63b63c6a1fab5d42d89c48ca7dea9dfc90ddd69e 100644 (file)
@@ -27,7 +27,6 @@
 use std::iter;
 use std::ops::Deref;
 use std::ptr;
-use tracing::{debug, instrument};
 
 // All Builders must have an llfn associated with them
 #[must_use]
@@ -725,11 +724,11 @@ fn sext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty, UNNAMED) }
     }
 
-    fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
+    fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
         self.fptoint_sat(false, val, dest_ty)
     }
 
-    fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
+    fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
         self.fptoint_sat(true, val, dest_ty)
     }
 
@@ -1429,12 +1428,7 @@ fn add_incoming_to_phi(&mut self, phi: &'ll Value, val: &'ll Value, bb: &'ll Bas
         }
     }
 
-    fn fptoint_sat(
-        &mut self,
-        signed: bool,
-        val: &'ll Value,
-        dest_ty: &'ll Type,
-    ) -> Option<&'ll Value> {
+    fn fptoint_sat(&mut self, signed: bool, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
         let src_ty = self.cx.val_ty(val);
         let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector {
             assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty));
@@ -1459,7 +1453,7 @@ fn fptoint_sat(
             format!("llvm.{}.sat.i{}.f{}", instr, int_width, float_width)
         };
         let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
-        Some(self.call(self.type_func(&[src_ty], dest_ty), f, &[val], None))
+        self.call(self.type_func(&[src_ty], dest_ty), f, &[val], None)
     }
 
     pub(crate) fn landing_pad(
index d55f995b933a6f6ec4935c8bf712247a0fcd9762..b83c1e8f08f3182ee2178faa1a03b98862d3985c 100644 (file)
@@ -11,7 +11,6 @@
 use crate::llvm;
 use crate::value::Value;
 use rustc_codegen_ssa::traits::*;
-use tracing::debug;
 
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
 use rustc_middle::ty::{self, Instance, TypeVisitable};
index 63d3bb40a3fe0c448463f9d32253b984b7476424..13e437cfbf7fb1b52d06589eb20c068ad140a131 100644 (file)
@@ -21,7 +21,6 @@
 
 use libc::{c_char, c_uint};
 use std::fmt::Write;
-use tracing::debug;
 
 /*
 * A note on nomenclature of linking: "extern", "foreign", and "upcall".
index f41ff325590afc4c0d7afab71a5c2cbf1e723e82..a559f7f3d57035a58da56542d948fdad98a9274a 100644 (file)
     AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
 };
 use std::ops::Range;
-use tracing::debug;
 
 pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value {
     let alloc = alloc.inner();
-    let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
+    let mut llvals = Vec::with_capacity(alloc.provenance().len() + 1);
     let dl = cx.data_layout();
     let pointer_size = dl.pointer_size.bytes() as usize;
 
-    // Note: this function may call `inspect_with_uninit_and_ptr_outside_interpreter`,
-    // so `range` must be within the bounds of `alloc` and not contain or overlap a relocation.
+    // Note: this function may call `inspect_with_uninit_and_ptr_outside_interpreter`, so `range`
+    // must be within the bounds of `alloc` and not contain or overlap a pointer provenance.
     fn append_chunks_of_init_and_uninit_bytes<'ll, 'a, 'b>(
         llvals: &mut Vec<&'ll Value>,
         cx: &'a CodegenCx<'ll, 'b>,
@@ -79,12 +78,12 @@ fn append_chunks_of_init_and_uninit_bytes<'ll, 'a, 'b>(
     }
 
     let mut next_offset = 0;
-    for &(offset, alloc_id) in alloc.relocations().iter() {
+    for &(offset, alloc_id) in alloc.provenance().iter() {
         let offset = offset.bytes();
         assert_eq!(offset as usize as u64, offset);
         let offset = offset as usize;
         if offset > next_offset {
-            // This `inspect` is okay since we have checked that it is not within a relocation, it
+            // This `inspect` is okay since we have checked that there is no provenance, it
             // is within the bounds of the allocation, and it doesn't affect interpreter execution
             // (we inspect the result after interpreter execution).
             append_chunks_of_init_and_uninit_bytes(&mut llvals, cx, alloc, next_offset..offset);
@@ -93,7 +92,7 @@ fn append_chunks_of_init_and_uninit_bytes<'ll, 'a, 'b>(
             dl.endian,
             // This `inspect` is okay since it is within the bounds of the allocation, it doesn't
             // affect interpreter execution (we inspect the result after interpreter execution),
-            // and we properly interpret the relocation as a relocation pointer offset.
+            // and we properly interpret the provenance as a relocation pointer offset.
             alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)),
         )
         .expect("const_alloc_to_llvm: could not read relocation pointer")
@@ -121,7 +120,7 @@ fn append_chunks_of_init_and_uninit_bytes<'ll, 'a, 'b>(
     }
     if alloc.len() >= next_offset {
         let range = next_offset..alloc.len();
-        // This `inspect` is okay since we have check that it is after all relocations, it is
+        // This `inspect` is okay since we have check that it is after all provenance, it is
         // within the bounds of the allocation, and it doesn't affect interpreter execution (we
         // inspect the result after interpreter execution).
         append_chunks_of_init_and_uninit_bytes(&mut llvals, cx, alloc, range);
@@ -479,7 +478,7 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
                 //
                 // We could remove this hack whenever we decide to drop macOS 10.10 support.
                 if self.tcx.sess.target.is_like_osx {
-                    // The `inspect` method is okay here because we checked relocations, and
+                    // The `inspect` method is okay here because we checked for provenance, and
                     // because we are doing this access to inspect the final interpreter state
                     // (not as part of the interpreter execution).
                     //
@@ -487,7 +486,7 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
                     // happens to be zero. Instead, we should only check the value of defined bytes
                     // and set all undefined bytes to zero if this allocation is headed for the
                     // BSS.
-                    let all_bytes_are_zero = alloc.relocations().is_empty()
+                    let all_bytes_are_zero = alloc.provenance().is_empty()
                         && alloc
                             .inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())
                             .iter()
@@ -511,9 +510,9 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
                         section.as_str().as_ptr().cast(),
                         section.as_str().len() as c_uint,
                     );
-                    assert!(alloc.relocations().is_empty());
+                    assert!(alloc.provenance().is_empty());
 
-                    // The `inspect` method is okay here because we checked relocations, and
+                    // The `inspect` method is okay here because we checked for provenance, and
                     // because we are doing this access to inspect the final interpreter state (not
                     // as part of the interpreter execution).
                     let bytes =
index 58f391692c49c109bb59b7011109403a09625943..0d1df6fb1acd99e437c9fbcf3d4bc59b984b4578 100644 (file)
@@ -16,8 +16,6 @@
 
 use std::ffi::CString;
 
-use tracing::debug;
-
 /// Generates and exports the Coverage Map.
 ///
 /// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions
index 98ba38356a4c30c8cafcd806115ebff394581817..964a632b6eeddc77a68711eed82bc4eef8c20e73 100644 (file)
@@ -28,7 +28,6 @@
 use std::ffi::CString;
 
 use std::iter;
-use tracing::debug;
 
 pub mod mapgen;
 
index d0a6f216858b61575238b6101f2a34fd151d8bd0..163ccd9460c54b58c9f1326fd3d186ae60496d9f 100644 (file)
@@ -42,7 +42,6 @@
 use rustc_symbol_mangling::typeid_for_trait_ref;
 use rustc_target::abi::{Align, Size};
 use smallvec::smallvec;
-use tracing::debug;
 
 use libc::{c_char, c_longlong, c_uint};
 use std::borrow::Cow;
@@ -51,7 +50,6 @@
 use std::iter;
 use std::path::{Path, PathBuf};
 use std::ptr;
-use tracing::instrument;
 
 impl PartialEq for llvm::Metadata {
     fn eq(&self, other: &Self) -> bool {
index cf591295b84680b57c660219f07e891a0c09a821..b23fe3fc9d5575ae8971c6dbb4b61cd1905512aa 100644 (file)
@@ -39,7 +39,6 @@
 use std::cell::OnceCell;
 use std::cell::RefCell;
 use std::iter;
-use tracing::debug;
 
 mod create_scope_map;
 pub mod gdb;
index 8f24367390775e1a8b43cac1024b7d093b17e4d3..a40cfc8b23fb32217f5b6b0897bea0e4f9e27373 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
 use rustc_middle::ty::{self, DefIdTree, Ty};
-use tracing::trace;
+use trace;
 
 use crate::common::CodegenCx;
 use crate::llvm;
index fa0ecd18fc895bcd7908250d6b970a0834677243..0f663a26732bba8abf5094a095a859784f6f9012 100644 (file)
@@ -22,7 +22,6 @@
 use rustc_middle::ty::Ty;
 use rustc_symbol_mangling::typeid::typeid_for_fnabi;
 use smallvec::SmallVec;
-use tracing::debug;
 
 /// Declare a function.
 ///
index c80ad6920006db275fd699bc1756ebd23685fdc7..334425ae55b43300c1f3f7e06463b235a5ad3a28 100644 (file)
@@ -6,6 +6,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(hash_raw_entry)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(extern_types)]
 #![feature(once_cell)]
@@ -15,6 +16,8 @@
 
 #[macro_use]
 extern crate rustc_macros;
+#[macro_use]
+extern crate tracing;
 
 use back::write::{create_informational_target_machine, create_target_machine};
 
index 64db4f7462df81d860c559c94550bcbaa012a688..7d948970223451361bfe606341afa17a07c2ee6d 100644 (file)
@@ -83,17 +83,6 @@ pub fn name(&self) -> Option<&'a str> {
             }
         }
     }
-
-    pub fn data(&self) -> &'a [u8] {
-        unsafe {
-            let mut data_len = 0;
-            let data_ptr = super::LLVMRustArchiveChildData(self.raw, &mut data_len);
-            if data_ptr.is_null() {
-                panic!("failed to read data from archive child");
-            }
-            slice::from_raw_parts(data_ptr as *const u8, data_len as usize)
-        }
-    }
 }
 
 impl<'a> Drop for Child<'a> {
index 4ca3dd78caedec2f22e9cb679f44c36451ff62b7..172684414fc5534495d2218c26062c80306f4b94 100644 (file)
@@ -2389,7 +2389,6 @@ pub fn LLVMRustArchiveIteratorNext<'a>(
         AIR: &ArchiveIterator<'a>,
     ) -> Option<&'a mut ArchiveChild<'a>>;
     pub fn LLVMRustArchiveChildName(ACR: &ArchiveChild<'_>, size: &mut size_t) -> *const c_char;
-    pub fn LLVMRustArchiveChildData(ACR: &ArchiveChild<'_>, size: &mut size_t) -> *const c_char;
     pub fn LLVMRustArchiveChildFree<'a>(ACR: &'a mut ArchiveChild<'a>);
     pub fn LLVMRustArchiveIteratorFree<'a>(AIR: &'a mut ArchiveIterator<'a>);
     pub fn LLVMRustDestroyArchive(AR: &'static mut Archive);
index f5d676c44e3428b83677bd237daf7e5ad9ca2782..1b049dfe9790444e300423cbbef45ccb27370168 100644 (file)
@@ -15,7 +15,6 @@
 use rustc_target::spec::{MergeFunctions, PanicStrategy};
 use smallvec::{smallvec, SmallVec};
 use std::ffi::{CStr, CString};
-use tracing::debug;
 
 use std::mem;
 use std::path::Path;
index 6e94284852f357970663599fbf08766576eef75c..1eceb7f5c87beb362760851e5ce31ae40a66c75f 100644 (file)
@@ -11,7 +11,6 @@
 use rustc_middle::ty::{self, Instance, TypeVisitable};
 use rustc_session::config::CrateType;
 use rustc_target::spec::RelocModel;
-use tracing::debug;
 
 impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
     fn predefine_static(
index 9f0e6c80b19a7f0108620d5fa07275f7dd90aaee..dc1165835e7ca271b38986619f20801fb8c5a71e 100644 (file)
@@ -11,7 +11,6 @@
 use rustc_target::abi::{Int, Pointer, F32, F64};
 use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants};
 use smallvec::{smallvec, SmallVec};
-use tracing::debug;
 
 use std::fmt::Write;
 
index 46d6344dbb2ef9d273daa0a14d1937c527a5738c..d868e3d56ba6b33d240fe92b65b7e003ebe45726 100644 (file)
@@ -26,7 +26,6 @@ rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
 rustc_middle = { path = "../rustc_middle" }
-rustc_apfloat = { path = "../rustc_apfloat" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
 rustc_data_structures = { path = "../rustc_data_structures" }
index d2f2c7bf7988ad84ea14ffd0563c5961fb631c7c..e9171823c242c7c1be928306c1b50d76025066a4 100644 (file)
@@ -1173,13 +1173,6 @@ fn infer_from(
             // only the linker flavor is known; use the default linker for the selected flavor
             (None, Some(flavor)) => Some((
                 PathBuf::from(match flavor {
-                    LinkerFlavor::Em => {
-                        if cfg!(windows) {
-                            "emcc.bat"
-                        } else {
-                            "emcc"
-                        }
-                    }
                     LinkerFlavor::Gcc => {
                         if cfg!(any(target_os = "solaris", target_os = "illumos")) {
                             // On historical Solaris systems, "cc" may have
@@ -1194,11 +1187,17 @@ fn infer_from(
                         }
                     }
                     LinkerFlavor::Ld => "ld",
-                    LinkerFlavor::Msvc => "link.exe",
                     LinkerFlavor::Lld(_) => "lld",
-                    LinkerFlavor::PtxLinker => "rust-ptx-linker",
-                    LinkerFlavor::BpfLinker => "bpf-linker",
-                    LinkerFlavor::L4Bender => "l4-bender",
+                    LinkerFlavor::Msvc => "link.exe",
+                    LinkerFlavor::EmCc => {
+                        if cfg!(windows) {
+                            "emcc.bat"
+                        } else {
+                            "emcc"
+                        }
+                    }
+                    LinkerFlavor::Bpf => "bpf-linker",
+                    LinkerFlavor::Ptx => "rust-ptx-linker",
                 }),
                 flavor,
             )),
@@ -1208,7 +1207,7 @@ fn infer_from(
                 });
 
                 let flavor = if stem == "emcc" {
-                    LinkerFlavor::Em
+                    LinkerFlavor::EmCc
                 } else if stem == "gcc"
                     || stem.ends_with("-gcc")
                     || stem == "clang"
@@ -1236,7 +1235,8 @@ fn infer_from(
 
     // linker and linker flavor specified via command line have precedence over what the target
     // specification specifies
-    if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) {
+    let linker_flavor = sess.opts.cg.linker_flavor.map(LinkerFlavor::from_cli);
+    if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) {
         return ret;
     }
 
@@ -2113,11 +2113,11 @@ fn add_order_independent_options(
         });
     }
 
-    if flavor == LinkerFlavor::PtxLinker {
+    if flavor == LinkerFlavor::Ptx {
         // Provide the linker with fallback to internal `target-cpu`.
         cmd.arg("--fallback-arch");
         cmd.arg(&codegen_results.crate_info.target_cpu);
-    } else if flavor == LinkerFlavor::BpfLinker {
+    } else if flavor == LinkerFlavor::Bpf {
         cmd.arg("--cpu");
         cmd.arg(&codegen_results.crate_info.target_cpu);
         cmd.arg("--cpu-features");
@@ -2797,20 +2797,24 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         if let LinkerFlavor::Gcc = flavor {
             match ld_impl {
                 LdImpl::Lld => {
-                    let tools_path = sess.get_tools_search_paths(false);
-                    let gcc_ld_dir = tools_path
-                        .into_iter()
-                        .map(|p| p.join("gcc-ld"))
-                        .find(|p| {
-                            p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists()
-                        })
-                        .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found"));
-                    cmd.arg({
-                        let mut arg = OsString::from("-B");
-                        arg.push(gcc_ld_dir);
-                        arg
-                    });
-                    cmd.arg(format!("-Wl,-rustc-lld-flavor={}", sess.target.lld_flavor.as_str()));
+                    // Implement the "self-contained" part of -Zgcc-ld
+                    // by adding rustc distribution directories to the tool search path.
+                    for path in sess.get_tools_search_paths(false) {
+                        cmd.arg({
+                            let mut arg = OsString::from("-B");
+                            arg.push(path.join("gcc-ld"));
+                            arg
+                        });
+                    }
+                    // Implement the "linker flavor" part of -Zgcc-ld
+                    // by asking cc to use some kind of lld.
+                    cmd.arg("-fuse-ld=lld");
+                    if sess.target.lld_flavor != LldFlavor::Ld {
+                        // Tell clang to use a non-default LLD flavor.
+                        // Gcc doesn't understand the target option, but we currently assume
+                        // that gcc is not used for Apple and Wasm targets (#97402).
+                        cmd.arg(format!("--target={}", sess.target.llvm_target));
+                    }
                 }
             }
         } else {
index ce51b2e9531fcedbe1520bb18736badb692a4de9..8c6f526b054bc5ec213eddf5fac9d8505029d9d5 100644 (file)
@@ -126,29 +126,26 @@ pub fn get_linker<'a>(
     // to the linker args construction.
     assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
     match flavor {
-        LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
-            Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>
-        }
-        LinkerFlavor::Em => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
         LinkerFlavor::Gcc => {
             Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: false })
                 as Box<dyn Linker>
         }
-
+        LinkerFlavor::Ld if sess.target.os == "l4re" => {
+            Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
+        }
         LinkerFlavor::Lld(LldFlavor::Ld)
         | LinkerFlavor::Lld(LldFlavor::Ld64)
         | LinkerFlavor::Ld => {
             Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: true })
                 as Box<dyn Linker>
         }
-
+        LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
+            Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>
+        }
         LinkerFlavor::Lld(LldFlavor::Wasm) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
-
-        LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
-
-        LinkerFlavor::BpfLinker => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
-
-        LinkerFlavor::L4Bender => Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>,
+        LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
+        LinkerFlavor::Bpf => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
+        LinkerFlavor::Ptx => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
     }
 }
 
index 32b340832ce289625a283503b9bdf090c2a608c6..8d7e2c5cf3939a5cc5d907751f18ba1c94df1355 100644 (file)
@@ -540,7 +540,7 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
         .map(|fnabi| (fnabi.conv, &fnabi.args[..]))
         .unwrap_or((Conv::Rust, &[]));
 
-    // Decorate symbols with prefices, suffices and total number of bytes of arguments.
+    // Decorate symbols with prefixes, suffixes and total number of bytes of arguments.
     // Reference: https://docs.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170
     let (prefix, suffix) = match conv {
         Conv::X86Fastcall => ("@", "@"),
index 2930d09d71f1a61c8c690e24256c6cadc7ceb7e1..68f3b19b715ad7563a672184f44ce9aa895f7aa0 100644 (file)
@@ -1892,7 +1892,7 @@ pub fn join(self, sess: &Session) -> (CodegenResults, FxHashMap<WorkProductId, W
             }
         });
 
-        sess.cgu_reuse_tracker.check_expected_reuse(sess.diagnostic());
+        sess.cgu_reuse_tracker.check_expected_reuse(sess);
 
         sess.abort_if_errors();
 
index 4c6be3f910827d7886b48e2ebbada31c3d701a86..6e482062383d451884f06dd08dbe887dd2b73274 100644 (file)
@@ -389,15 +389,14 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     let main_llfn = cx.get_fn_addr(instance);
 
-    let use_start_lang_item = EntryFnType::Start != entry_type;
-    let entry_fn = create_entry_fn::<Bx>(cx, main_llfn, main_def_id, use_start_lang_item);
+    let entry_fn = create_entry_fn::<Bx>(cx, main_llfn, main_def_id, entry_type);
     return Some(entry_fn);
 
     fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         cx: &'a Bx::CodegenCx,
         rust_main: Bx::Value,
         rust_main_def_id: DefId,
-        use_start_lang_item: bool,
+        entry_type: EntryFnType,
     ) -> Bx::Function {
         // The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
         // depending on whether the target needs `argc` and `argv` to be passed in.
@@ -442,7 +441,7 @@ fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         let i8pp_ty = cx.type_ptr_to(cx.type_i8p());
         let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx);
 
-        let (start_fn, start_ty, args) = if use_start_lang_item {
+        let (start_fn, start_ty, args) = if let EntryFnType::Main { sigpipe } = entry_type {
             let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
             let start_fn = cx.get_fn_addr(
                 ty::Instance::resolve(
@@ -454,8 +453,13 @@ fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 .unwrap()
                 .unwrap(),
             );
-            let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, i8pp_ty], isize_ty);
-            (start_fn, start_ty, vec![rust_main, arg_argc, arg_argv])
+
+            let i8_ty = cx.type_i8();
+            let arg_sigpipe = bx.const_u8(sigpipe);
+
+            let start_ty =
+                cx.type_func(&[cx.val_ty(rust_main), isize_ty, i8pp_ty, i8_ty], isize_ty);
+            (start_fn, start_ty, vec![rust_main, arg_argc, arg_argv, arg_sigpipe])
         } else {
             debug!("using user-defined start fn");
             let start_ty = cx.type_func(&[isize_ty, i8pp_ty], isize_ty);
index 27d791d90a51aed975810fb20486f932fa068179..f8e982b775189f7ed45ae19b5f0e572bb657f3af 100644 (file)
@@ -1,6 +1,6 @@
 use crate::traits::*;
 
-use rustc_middle::ty::{self, subst::GenericArgKind, ExistentialPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
 use rustc_session::config::Lto;
 use rustc_symbol_mangling::typeid_for_trait_ref;
 use rustc_target::abi::call::FnAbi;
@@ -29,7 +29,7 @@ pub fn get_fn<Bx: BuilderMethods<'a, 'tcx>>(
             && bx.cx().sess().lto() == Lto::Fat
         {
             let typeid =
-                bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), get_trait_ref(bx.tcx(), ty)));
+                bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty)));
             let vtable_byte_offset = self.0 * bx.data_layout().pointer_size.bytes();
             let type_checked_load = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
             let func = bx.extract_value(type_checked_load, 0);
@@ -64,17 +64,13 @@ pub fn get_usize<Bx: BuilderMethods<'a, 'tcx>>(
     }
 }
 
-fn get_trait_ref<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::PolyExistentialTraitRef<'tcx> {
+/// This takes a valid `self` receiver type and extracts the principal trait
+/// ref of the type.
+fn expect_dyn_trait_in_self<'tcx>(ty: Ty<'tcx>) -> ty::PolyExistentialTraitRef<'tcx> {
     for arg in ty.peel_refs().walk() {
         if let GenericArgKind::Type(ty) = arg.unpack() {
-            if let ty::Dynamic(trait_refs, _) = ty.kind() {
-                return trait_refs[0].map_bound(|trait_ref| match trait_ref {
-                    ExistentialPredicate::Trait(tr) => tr,
-                    ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
-                    ExistentialPredicate::AutoTrait(_) => {
-                        bug!("auto traits don't have functions")
-                    }
-                });
+            if let ty::Dynamic(data, _) = ty.kind() {
+                return data.principal().expect("expected principal trait object");
             }
         }
     }
index d6bbcd99234553bf3173620c5fdc8d7c0a419674..2b931bfc91d63b05c93717a42b522d87a9a4b127 100644 (file)
@@ -191,7 +191,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 // errored or at least linted
                 ErrorHandled::Reported(_) | ErrorHandled::Linted => {}
                 ErrorHandled::TooGeneric => {
-                    span_bug!(const_.span, "codgen encountered polymorphic constant: {:?}", err)
+                    span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err)
                 }
             }
         }
index 268c4d765030568f074d975153a2bd6fa30a8f1b..04b8c8636f634ddeaebdaf90e7417939ae10c9ba 100644 (file)
@@ -4,7 +4,6 @@
 use crate::common::IntPredicate;
 use crate::glue;
 use crate::traits::*;
-use crate::MemFlags;
 
 use rustc_middle::mir;
 use rustc_middle::mir::tcx::PlaceTy;
@@ -343,16 +342,6 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                 ..
             } => {
                 if variant_index != dataful_variant {
-                    if bx.cx().sess().target.arch == "arm"
-                        || bx.cx().sess().target.arch == "aarch64"
-                    {
-                        // FIXME(#34427): as workaround for LLVM bug on ARM,
-                        // use memset of 0 before assigning niche value.
-                        let fill_byte = bx.cx().const_u8(0);
-                        let size = bx.cx().const_usize(self.layout.size.bytes());
-                        bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty());
-                    }
-
                     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 9f49749bb41fb9d42a6609c5aec9ed8cb90dc7bc..10cf8948b5a54fc55c73e100fc988f7752d7b607 100644 (file)
@@ -1,6 +1,5 @@
 use super::abi::AbiBuilderMethods;
 use super::asm::AsmBuilderMethods;
-use super::consts::ConstMethods;
 use super::coverageinfo::CoverageInfoBuilderMethods;
 use super::debuginfo::DebugInfoBuilderMethods;
 use super::intrinsic::IntrinsicCallMethods;
@@ -15,7 +14,6 @@
 use crate::mir::place::PlaceRef;
 use crate::MemFlags;
 
-use rustc_apfloat::{ieee, Float, Round, Status};
 use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
 use rustc_middle::ty::Ty;
 use rustc_span::Span;
@@ -188,8 +186,8 @@ fn inbounds_gep(
 
     fn trunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
     fn sext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
-    fn fptoui_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Option<Self::Value>;
-    fn fptosi_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Option<Self::Value>;
+    fn fptoui_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
+    fn fptosi_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
     fn fptoui(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
     fn fptosi(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
     fn uitofp(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
@@ -223,156 +221,7 @@ fn cast_float_to_int(
             return if signed { self.fptosi(x, dest_ty) } else { self.fptoui(x, dest_ty) };
         }
 
-        let try_sat_result =
-            if signed { self.fptosi_sat(x, dest_ty) } else { self.fptoui_sat(x, dest_ty) };
-        if let Some(try_sat_result) = try_sat_result {
-            return try_sat_result;
-        }
-
-        let int_width = self.cx().int_width(int_ty);
-        let float_width = self.cx().float_width(float_ty);
-        // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the
-        // destination integer type after rounding towards zero. This `undef` value can cause UB in
-        // safe code (see issue #10184), so we implement a saturating conversion on top of it:
-        // Semantically, the mathematical value of the input is rounded towards zero to the next
-        // mathematical integer, and then the result is clamped into the range of the destination
-        // integer type. Positive and negative infinity are mapped to the maximum and minimum value of
-        // the destination integer type. NaN is mapped to 0.
-        //
-        // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to
-        // a value representable in int_ty.
-        // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits.
-        // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two.
-        // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly
-        // representable. Note that this only works if float_ty's exponent range is sufficiently large.
-        // f16 or 256 bit integers would break this property. Right now the smallest float type is f32
-        // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127.
-        // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
-        // we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
-        // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
-        let int_max = |signed: bool, int_width: u64| -> u128 {
-            let shift_amount = 128 - int_width;
-            if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
-        };
-        let int_min = |signed: bool, int_width: u64| -> i128 {
-            if signed { i128::MIN >> (128 - int_width) } else { 0 }
-        };
-
-        let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
-            let rounded_min =
-                ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);
-            assert_eq!(rounded_min.status, Status::OK);
-            let rounded_max =
-                ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero);
-            assert!(rounded_max.value.is_finite());
-            (rounded_min.value.to_bits(), rounded_max.value.to_bits())
-        };
-        let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) {
-            let rounded_min =
-                ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
-            assert_eq!(rounded_min.status, Status::OK);
-            let rounded_max =
-                ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
-            assert!(rounded_max.value.is_finite());
-            (rounded_min.value.to_bits(), rounded_max.value.to_bits())
-        };
-        // To implement saturation, we perform the following steps:
-        //
-        // 1. Cast x to an integer with fpto[su]i. This may result in undef.
-        // 2. Compare x to f_min and f_max, and use the comparison results to select:
-        //  a) int_ty::MIN if x < f_min or x is NaN
-        //  b) int_ty::MAX if x > f_max
-        //  c) the result of fpto[su]i otherwise
-        // 3. If x is NaN, return 0.0, otherwise return the result of step 2.
-        //
-        // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the
-        // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of
-        // undef does not introduce any non-determinism either.
-        // More importantly, the above procedure correctly implements saturating conversion.
-        // Proof (sketch):
-        // If x is NaN, 0 is returned by definition.
-        // Otherwise, x is finite or infinite and thus can be compared with f_min and f_max.
-        // This yields three cases to consider:
-        // (1) if x in [f_min, f_max], the result of fpto[su]i is returned, which agrees with
-        //     saturating conversion for inputs in that range.
-        // (2) if x > f_max, then x is larger than int_ty::MAX. This holds even if f_max is rounded
-        //     (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger
-        //     than int_ty::MAX. Because x is larger than int_ty::MAX, the return value of int_ty::MAX
-        //     is correct.
-        // (3) if x < f_min, then x is smaller than int_ty::MIN. As shown earlier, f_min exactly equals
-        //     int_ty::MIN and therefore the return value of int_ty::MIN is correct.
-        // QED.
-
-        let float_bits_to_llval = |bx: &mut Self, bits| {
-            let bits_llval = match float_width {
-                32 => bx.cx().const_u32(bits as u32),
-                64 => bx.cx().const_u64(bits as u64),
-                n => bug!("unsupported float width {}", n),
-            };
-            bx.bitcast(bits_llval, float_ty)
-        };
-        let (f_min, f_max) = match float_width {
-            32 => compute_clamp_bounds_single(signed, int_width),
-            64 => compute_clamp_bounds_double(signed, int_width),
-            n => bug!("unsupported float width {}", n),
-        };
-        let f_min = float_bits_to_llval(self, f_min);
-        let f_max = float_bits_to_llval(self, f_max);
-        let int_max = self.cx().const_uint_big(int_ty, int_max(signed, int_width));
-        let int_min = self.cx().const_uint_big(int_ty, int_min(signed, int_width) as u128);
-        let zero = self.cx().const_uint(int_ty, 0);
-
-        // If we're working with vectors, constants must be "splatted": the constant is duplicated
-        // into each lane of the vector.  The algorithm stays the same, we are just using the
-        // same constant across all lanes.
-        let maybe_splat = |bx: &mut Self, val| {
-            if bx.cx().type_kind(dest_ty) == TypeKind::Vector {
-                bx.vector_splat(bx.vector_length(dest_ty), val)
-            } else {
-                val
-            }
-        };
-        let f_min = maybe_splat(self, f_min);
-        let f_max = maybe_splat(self, f_max);
-        let int_max = maybe_splat(self, int_max);
-        let int_min = maybe_splat(self, int_min);
-        let zero = maybe_splat(self, zero);
-
-        // Step 1 ...
-        let fptosui_result = if signed { self.fptosi(x, dest_ty) } else { self.fptoui(x, dest_ty) };
-        let less_or_nan = self.fcmp(RealPredicate::RealULT, x, f_min);
-        let greater = self.fcmp(RealPredicate::RealOGT, x, f_max);
-
-        // Step 2: We use two comparisons and two selects, with %s1 being the
-        // result:
-        //     %less_or_nan = fcmp ult %x, %f_min
-        //     %greater = fcmp olt %x, %f_max
-        //     %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
-        //     %s1 = select %greater, int_ty::MAX, %s0
-        // Note that %less_or_nan uses an *unordered* comparison. This
-        // comparison is true if the operands are not comparable (i.e., if x is
-        // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
-        // x is NaN.
-        //
-        // Performance note: Unordered comparison can be lowered to a "flipped"
-        // comparison and a negation, and the negation can be merged into the
-        // select. Therefore, it not necessarily any more expensive than an
-        // ordered ("normal") comparison. Whether these optimizations will be
-        // performed is ultimately up to the backend, but at least x86 does
-        // perform them.
-        let s0 = self.select(less_or_nan, int_min, fptosui_result);
-        let s1 = self.select(greater, int_max, s0);
-
-        // Step 3: NaN replacement.
-        // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN.
-        // Therefore we only need to execute this step for signed integer types.
-        if signed {
-            // LLVM has no isNaN predicate, so we use (x == x) instead
-            let cmp = self.fcmp(RealPredicate::RealOEQ, x, x);
-            self.select(cmp, s1, zero)
-        } else {
-            s1
-        }
+        if signed { self.fptosi_sat(x, dest_ty) } else { self.fptoui_sat(x, dest_ty) }
     }
 
     fn icmp(&mut self, op: IntPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
index eb81f43c3fe8cbafa2b3b9fa1f70e40594b88904..09d53331b5b269310fc29249887f64f2e28de83d 100644 (file)
 use super::InterpCx;
 use crate::interpret::{
     struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType,
+    UnsupportedOpInfo,
 };
 
 /// The CTFE machine has some custom error kinds.
 #[derive(Clone, Debug)]
 pub enum ConstEvalErrKind {
-    NeedsRfc(String),
     ConstAccessesStatic,
     ModifiedGlobal,
     AssertFailure(AssertKind<ConstInt>),
@@ -42,9 +42,6 @@ impl fmt::Display for ConstEvalErrKind {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use self::ConstEvalErrKind::*;
         match *self {
-            NeedsRfc(ref msg) => {
-                write!(f, "\"{}\" needs an rfc before being allowed inside constants", msg)
-            }
             ConstAccessesStatic => write!(f, "constant accesses static"),
             ModifiedGlobal => {
                 write!(f, "modifying a static's initial value from another static's initializer")
@@ -153,6 +150,18 @@ fn struct_generic(
             if let Some(span_msg) = span_msg {
                 err.span_label(self.span, span_msg);
             }
+            // Add some more context for select error types.
+            match self.error {
+                InterpError::Unsupported(
+                    UnsupportedOpInfo::ReadPointerAsBytes
+                    | UnsupportedOpInfo::PartialPointerOverwrite(_)
+                    | UnsupportedOpInfo::PartialPointerCopy(_),
+                ) => {
+                    err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
+                    err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
+                }
+                _ => {}
+            }
             // Add spans for the stacktrace. Don't print a single-line backtrace though.
             if self.stacktrace.len() > 1 {
                 // Helper closure to print duplicated lines.
index 4601914c25f88b70e7b99300970259196d9389f7..a2f14e753aebe7ca5cb6bf7b049123f7c746ff5d 100644 (file)
@@ -2,8 +2,8 @@
 use crate::interpret::eval_nullary_intrinsic;
 use crate::interpret::{
     intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId,
-    Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
-    StackPopCleanup,
+    Immediate, InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy,
+    RefTracking, StackPopCleanup,
 };
 
 use rustc_hir::def::DefKind;
@@ -197,7 +197,7 @@ pub(super) fn op_to_const<'tcx>(
     }
 }
 
-#[instrument(skip(tcx), level = "debug")]
+#[instrument(skip(tcx), level = "debug", ret)]
 pub(crate) fn turn_into_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
     constant: ConstAlloc<'tcx>,
@@ -224,10 +224,7 @@ pub(crate) fn turn_into_const_value<'tcx>(
     );
 
     // Turn this into a proper constant.
-    let const_val = op_to_const(&ecx, &mplace.into());
-    debug!(?const_val);
-
-    const_val
+    op_to_const(&ecx, &mplace.into())
 }
 
 #[instrument(skip(tcx), level = "debug")]
@@ -387,7 +384,9 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
                     ecx.tcx,
                     "it is undefined behavior to use this value",
                     |diag| {
-                        diag.note(NOTE_ON_UNDEFINED_BEHAVIOR_ERROR);
+                        if matches!(err.error, InterpError::UndefinedBehavior(_)) {
+                            diag.note(NOTE_ON_UNDEFINED_BEHAVIOR_ERROR);
+                        }
                         diag.note(&format!(
                             "the raw bytes of the constant ({}",
                             display_allocation(
index 6c1e61fccca194619b81e82d4ade8e7e2f60b006..9ea9fbe0e0e54188260281048bf8bfd11edfc308 100644 (file)
@@ -269,9 +269,10 @@ fn load_mir(
                     );
                     throw_inval!(AlreadyReported(guar));
                 } else {
+                    // `find_mir_or_eval_fn` checks that this is a const fn before even calling us,
+                    // so this should be unreachable.
                     let path = ecx.tcx.def_path_str(def.did);
-                    Err(ConstEvalErrKind::NeedsRfc(format!("calling extern function `{}`", path))
-                        .into())
+                    bug!("trying to call extern function `{path}` at compile-time");
                 }
             }
             _ => Ok(ecx.tcx.instance_mir(instance)),
@@ -339,11 +340,7 @@ fn call_intrinsic(
 
         // CTFE-specific intrinsics.
         let Some(ret) = target else {
-            return Err(ConstEvalErrKind::NeedsRfc(format!(
-                "calling intrinsic `{}`",
-                intrinsic_name
-            ))
-            .into());
+            throw_unsup_format!("intrinsic `{intrinsic_name}` is not supported at compile-time");
         };
         match intrinsic_name {
             sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
@@ -400,11 +397,9 @@ fn call_intrinsic(
                 }
             }
             _ => {
-                return Err(ConstEvalErrKind::NeedsRfc(format!(
-                    "calling intrinsic `{}`",
-                    intrinsic_name
-                ))
-                .into());
+                throw_unsup_format!(
+                    "intrinsic `{intrinsic_name}` is not supported at compile-time"
+                );
             }
         }
 
@@ -447,7 +442,7 @@ fn binary_ptr_op(
         _left: &ImmTy<'tcx>,
         _right: &ImmTy<'tcx>,
     ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
-        Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into())
+        throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time");
     }
 
     fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
@@ -469,7 +464,8 @@ fn expose_ptr(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _ptr: Pointer<AllocId>,
     ) -> InterpResult<'tcx> {
-        Err(ConstEvalErrKind::NeedsRfc("exposing pointers".to_string()).into())
+        // This is only reachable with -Zunleash-the-miri-inside-of-you.
+        throw_unsup_format!("exposing pointers is not possible at compile-time")
     }
 
     #[inline(always)]
index 373b139c86e424d941b779aaddbe7e5912db6301..8b7c3cf3377cc9108bc7a9e9f1f7f4763b35cdf8 100644 (file)
@@ -204,7 +204,7 @@ fn get_info_on_unsized_field<'tcx>(
     (unsized_inner_ty, num_elems)
 }
 
-#[instrument(skip(ecx), level = "debug")]
+#[instrument(skip(ecx), level = "debug", ret)]
 fn create_pointee_place<'tcx>(
     ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
     ty: Ty<'tcx>,
@@ -237,14 +237,11 @@ fn create_pointee_place<'tcx>(
         let ptr = ecx.allocate_ptr(size, align, MemoryKind::Stack).unwrap();
         debug!(?ptr);
 
-        let place = MPlaceTy::from_aligned_ptr_with_meta(
+        MPlaceTy::from_aligned_ptr_with_meta(
             ptr.into(),
             layout,
             MemPlaceMeta::Meta(Scalar::from_machine_usize(num_elems as u64, &tcx)),
-        );
-        debug!(?place);
-
-        place
+        )
     } else {
         create_mplace_from_layout(ecx, ty)
     }
@@ -253,7 +250,7 @@ fn create_pointee_place<'tcx>(
 /// Converts a `ValTree` to a `ConstValue`, which is needed after mir
 /// construction has finished.
 // FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function
-#[instrument(skip(tcx), level = "debug")]
+#[instrument(skip(tcx), level = "debug", ret)]
 pub fn valtree_to_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
@@ -294,7 +291,7 @@ pub fn valtree_to_const_value<'tcx>(
             dump_place(&ecx, place.into());
             intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
 
-            let const_val = match ty.kind() {
+            match ty.kind() {
                 ty::Ref(_, _, _) => {
                     let ref_place = place.to_ref(&tcx);
                     let imm =
@@ -303,10 +300,7 @@ pub fn valtree_to_const_value<'tcx>(
                     op_to_const(&ecx, &imm.into())
                 }
                 _ => op_to_const(&ecx, &place.into()),
-            };
-            debug!(?const_val);
-
-            const_val
+            }
         }
         ty::Never
         | ty::Error(_)
index 2da9123b84610520d7ea7601ad1df1f98605041d..d37eaeed095a154fa7732fa24253ab4dfde84688 100644 (file)
@@ -187,9 +187,6 @@ pub enum LocalValue<Prov: Provenance = AllocId> {
 
 impl<'tcx, Prov: Provenance + 'static> LocalState<'tcx, Prov> {
     /// Read the local's value or error if the local is not yet live or not live anymore.
-    ///
-    /// Note: This may only be invoked from the `Machine::access_local` hook and not from
-    /// anywhere else. You may be invalidating machine invariants if you do!
     #[inline]
     pub fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
         match &self.value {
index 376b8872c90ac1be2610e792cadbd844e3b6d60d..24dbc769529c3665a6e30da12c750226a21ffd19 100644 (file)
@@ -134,7 +134,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
         alloc.mutability = Mutability::Not;
     };
     // link the alloc id to the actual allocation
-    leftover_allocations.extend(alloc.relocations().iter().map(|&(_, alloc_id)| alloc_id));
+    leftover_allocations.extend(alloc.provenance().iter().map(|&(_, alloc_id)| alloc_id));
     let alloc = tcx.intern_const_alloc(alloc);
     tcx.set_alloc_id_memory(alloc_id, alloc);
     None
@@ -191,10 +191,10 @@ fn visit_aggregate(
                     return Ok(true);
                 };
 
-                // If there are no relocations in this allocation, it does not contain references
+                // If there is no provenance in this allocation, it does not contain references
                 // that point to another allocation, and we can avoid the interning walk.
                 if let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr, size, align)? {
-                    if !alloc.has_relocations() {
+                    if !alloc.has_provenance() {
                         return Ok(false);
                     }
                 } else {
@@ -233,8 +233,8 @@ fn visit_aggregate(
     }
 
     fn visit_value(&mut self, mplace: &MPlaceTy<'tcx>) -> InterpResult<'tcx> {
-        // Handle Reference types, as these are the only relocations supported by const eval.
-        // Raw pointers (and boxes) are handled by the `leftover_relocations` logic.
+        // Handle Reference types, as these are the only types with provenance supported by const eval.
+        // Raw pointers (and boxes) are handled by the `leftover_allocations` logic.
         let tcx = self.ecx.tcx;
         let ty = mplace.layout.ty;
         if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() {
@@ -334,7 +334,7 @@ pub enum InternKind {
 /// tracks where in the value we are and thus can show much better error messages.
 /// Any errors here would anyway be turned into `const_err` lints, whereas validation failures
 /// are hard errors.
-#[tracing::instrument(level = "debug", skip(ecx))]
+#[instrument(level = "debug", skip(ecx))]
 pub fn intern_const_alloc_recursive<
     'mir,
     'tcx: 'mir,
@@ -410,7 +410,7 @@ pub fn intern_const_alloc_recursive<
             // references and a `leftover_allocations` set (where we only have a todo-list here).
             // So we hand-roll the interning logic here again.
             match intern_kind {
-                // Statics may contain mutable allocations even behind relocations.
+                // Statics may point to mutable allocations.
                 // Even for immutable statics it would be ok to have mutable allocations behind
                 // raw pointers, e.g. for `static FOO: *const AtomicUsize = &AtomicUsize::new(42)`.
                 InternKind::Static(_) => {}
@@ -441,7 +441,7 @@ pub fn intern_const_alloc_recursive<
             }
             let alloc = tcx.intern_const_alloc(alloc);
             tcx.set_alloc_id_memory(alloc_id, alloc);
-            for &(_, alloc_id) in alloc.inner().relocations().iter() {
+            for &(_, alloc_id) in alloc.inner().provenance().iter() {
                 if leftover_allocations.insert(alloc_id) {
                     todo.push(alloc_id);
                 }
index 6f3bd3bf4c52be06bd7455d9f10e119aada6695c..adda9639990d0e38934100bce1856cb15c67c518 100644 (file)
@@ -320,7 +320,7 @@ pub fn emulate_intrinsic(
                 let (a_offset, b_offset) =
                     match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) {
                         (Err(a), Err(b)) => {
-                            // Neither poiner points to an allocation.
+                            // Neither pointer points to an allocation.
                             // If these are inequal or null, this *will* fail the deref check below.
                             (a, b)
                         }
@@ -687,10 +687,23 @@ pub(crate) fn raw_eq_intrinsic(
         let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?;
         assert!(!layout.is_unsized());
 
-        let lhs = self.read_pointer(lhs)?;
-        let rhs = self.read_pointer(rhs)?;
-        let lhs_bytes = self.read_bytes_ptr(lhs, layout.size)?;
-        let rhs_bytes = self.read_bytes_ptr(rhs, layout.size)?;
+        let get_bytes = |this: &InterpCx<'mir, 'tcx, M>,
+                         op: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+                         size|
+         -> InterpResult<'tcx, &[u8]> {
+            let ptr = this.read_pointer(op)?;
+            let Some(alloc_ref) = self.get_ptr_alloc(ptr, size, Align::ONE)? else {
+                // zero-sized access
+                return Ok(&[]);
+            };
+            if alloc_ref.has_provenance() {
+                throw_ub_format!("`raw_eq` on bytes with provenance");
+            }
+            alloc_ref.get_bytes_strip_provenance()
+        };
+
+        let lhs_bytes = get_bytes(self, lhs, layout.size)?;
+        let rhs_bytes = get_bytes(self, rhs, layout.size)?;
         Ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
     }
 }
index 6bed8a7a00773a2e35f2b6d2fef28c2834785f2b..5aabb14fba88454bc55bbf7c824e52d5a456a95a 100644 (file)
@@ -215,23 +215,12 @@ fn binary_ptr_op(
         right: &ImmTy<'tcx, Self::Provenance>,
     ) -> InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)>;
 
-    /// Called to read the specified `local` from the `frame`.
-    /// Since reading a ZST is not actually accessing memory or locals, this is never invoked
-    /// for ZST reads.
-    #[inline]
-    fn access_local<'a>(
-        frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
-        local: mir::Local,
-    ) -> InterpResult<'tcx, &'a Operand<Self::Provenance>>
-    where
-        'tcx: 'mir,
-    {
-        frame.locals[local].access()
-    }
-
     /// Called to write the specified `local` from the `frame`.
     /// Since writing a ZST is not actually accessing memory or locals, this is never invoked
     /// for ZST reads.
+    ///
+    /// Due to borrow checker trouble, we indicate the `frame` as an index rather than an `&mut
+    /// Frame`.
     #[inline]
     fn access_local_mut<'a>(
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
@@ -326,7 +315,7 @@ fn ptr_get_alloc(
     /// cache the result. (This relies on `AllocMap::get_or` being able to add the
     /// owned allocation to the map even when the map is shared.)
     ///
-    /// This must only fail if `alloc` contains relocations.
+    /// This must only fail if `alloc` contains provenance.
     fn adjust_allocation<'b>(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         id: AllocId,
@@ -490,6 +479,7 @@ fn ptr_from_addr_cast(
     ) -> InterpResult<$tcx, Pointer<Option<AllocId>>> {
         // Allow these casts, but make the pointer not dereferenceable.
         // (I.e., they behave like transmutation.)
+        // This is correct because no pointers can ever be exposed in compile-time evaluation.
         Ok(Pointer::from_addr(addr))
     }
 
index c4e9377029294958d6579367861fbc9e316fc737..ed155fbfef087e3fab4b188b53efcda489cc295b 100644 (file)
@@ -214,7 +214,7 @@ pub fn allocate_bytes_ptr(
         self.allocate_raw_ptr(alloc, kind).unwrap()
     }
 
-    /// This can fail only of `alloc` contains relocations.
+    /// This can fail only of `alloc` contains provenance.
     pub fn allocate_raw_ptr(
         &mut self,
         alloc: Allocation,
@@ -437,7 +437,7 @@ fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
                         msg,
                     })
                 }
-                // Ensure we never consider the null pointer dereferencable.
+                // Ensure we never consider the null pointer dereferenceable.
                 if M::Provenance::OFFSET_IS_ADDR {
                     assert_ne!(ptr.addr(), Size::ZERO);
                 }
@@ -794,10 +794,10 @@ pub fn leak_report(&self, static_roots: &[AllocId]) -> usize {
             todo.extend(static_roots);
             while let Some(id) = todo.pop() {
                 if reachable.insert(id) {
-                    // This is a new allocation, add its relocations to `todo`.
+                    // This is a new allocation, add the allocation it points to to `todo`.
                     if let Some((_, alloc)) = self.memory.alloc_map.get(id) {
                         todo.extend(
-                            alloc.relocations().values().filter_map(|prov| prov.get_alloc_id()),
+                            alloc.provenance().values().filter_map(|prov| prov.get_alloc_id()),
                         );
                     }
                 }
@@ -833,7 +833,7 @@ fn write_allocation_track_relocs<'tcx, Prov: Provenance, Extra>(
             allocs_to_print: &mut VecDeque<AllocId>,
             alloc: &Allocation<Prov, Extra>,
         ) -> std::fmt::Result {
-            for alloc_id in alloc.relocations().values().filter_map(|prov| prov.get_alloc_id()) {
+            for alloc_id in alloc.provenance().values().filter_map(|prov| prov.get_alloc_id()) {
                 allocs_to_print.push_back(alloc_id);
             }
             write!(fmt, "{}", display_allocation(tcx, alloc))
@@ -914,7 +914,7 @@ pub fn write_ptr_sized(&mut self, offset: Size, val: Scalar<Prov>) -> InterpResu
         self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val)
     }
 
-    /// Mark the entire referenced range as uninitalized
+    /// Mark the entire referenced range as uninitialized
     pub fn write_uninit(&mut self) -> InterpResult<'tcx> {
         Ok(self
             .alloc
@@ -953,24 +953,25 @@ pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, Scalar<Prov>> {
     }
 
     /// `range` is relative to this allocation reference, not the base of the allocation.
-    pub fn check_bytes(&self, range: AllocRange) -> InterpResult<'tcx> {
+    pub fn get_bytes_strip_provenance<'b>(&'b self) -> InterpResult<'tcx, &'a [u8]> {
         Ok(self
             .alloc
-            .check_bytes(&self.tcx, self.range.subrange(range))
+            .get_bytes_strip_provenance(&self.tcx, self.range)
             .map_err(|e| e.to_interp_error(self.alloc_id))?)
     }
 
-    /// Returns whether the allocation has relocations for the entire range of the `AllocRef`.
-    pub(crate) fn has_relocations(&self) -> bool {
-        self.alloc.has_relocations(&self.tcx, self.range)
+    /// Returns whether the allocation has provenance anywhere in the range of the `AllocRef`.
+    pub(crate) fn has_provenance(&self) -> bool {
+        self.alloc.range_has_provenance(&self.tcx, self.range)
     }
 }
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
-    /// Reads the given number of bytes from memory. Returns them as a slice.
+    /// Reads the given number of bytes from memory, and strips their provenance if possible.
+    /// Returns them as a slice.
     ///
     /// Performs appropriate bounds checks.
-    pub fn read_bytes_ptr(
+    pub fn read_bytes_ptr_strip_provenance(
         &self,
         ptr: Pointer<Option<M::Provenance>>,
         size: Size,
@@ -983,7 +984,7 @@ pub fn read_bytes_ptr(
         // (We are staying inside the bounds here so all is good.)
         Ok(alloc_ref
             .alloc
-            .get_bytes(&alloc_ref.tcx, alloc_ref.range)
+            .get_bytes_strip_provenance(&alloc_ref.tcx, alloc_ref.range)
             .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?)
     }
 
@@ -1078,17 +1079,20 @@ pub fn mem_copy_repeatedly(
             return Ok(());
         };
 
-        // This checks relocation edges on the src, which needs to happen before
-        // `prepare_relocation_copy`.
-        let src_bytes = src_alloc
-            .get_bytes_with_uninit_and_ptr(&tcx, src_range)
-            .map_err(|e| e.to_interp_error(src_alloc_id))?
-            .as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation
-        // first copy the relocations to a temporary buffer, because
-        // `get_bytes_mut` will clear the relocations, which is correct,
-        // since we don't want to keep any relocations at the target.
-        let relocations =
-            src_alloc.prepare_relocation_copy(self, src_range, dest_offset, num_copies);
+        // Checks provenance edges on the src, which needs to happen before
+        // `prepare_provenance_copy`.
+        if src_alloc.range_has_provenance(&tcx, alloc_range(src_range.start, Size::ZERO)) {
+            throw_unsup!(PartialPointerCopy(Pointer::new(src_alloc_id, src_range.start)));
+        }
+        if src_alloc.range_has_provenance(&tcx, alloc_range(src_range.end(), Size::ZERO)) {
+            throw_unsup!(PartialPointerCopy(Pointer::new(src_alloc_id, src_range.end())));
+        }
+        let src_bytes = src_alloc.get_bytes_unchecked(src_range).as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation
+        // first copy the provenance to a temporary buffer, because
+        // `get_bytes_mut` will clear the provenance, which is correct,
+        // since we don't want to keep any provenance at the target.
+        let provenance =
+            src_alloc.prepare_provenance_copy(self, src_range, dest_offset, num_copies);
         // Prepare a copy of the initialization mask.
         let compressed = src_alloc.compress_uninit_range(src_range);
 
@@ -1117,7 +1121,7 @@ pub fn mem_copy_repeatedly(
             dest_alloc
                 .write_uninit(&tcx, dest_range)
                 .map_err(|e| e.to_interp_error(dest_alloc_id))?;
-            // We can forget about the relocations, this is all not initialized anyway.
+            // We can forget about the provenance, this is all not initialized anyway.
             return Ok(());
         }
 
@@ -1161,8 +1165,8 @@ pub fn mem_copy_repeatedly(
             alloc_range(dest_offset, size), // just a single copy (i.e., not full `dest_range`)
             num_copies,
         );
-        // copy the relocations to the destination
-        dest_alloc.mark_relocation_range(relocations);
+        // copy the provenance to the destination
+        dest_alloc.mark_provenance_range(provenance);
 
         Ok(())
     }
index e80a82acd585b1780732350d06c7bfc09310f5c5..35c2cf8102dc571269645cc1537433a415339063 100644 (file)
@@ -415,7 +415,7 @@ pub fn read_pointer(
     /// Turn the wide MPlace into a string (must already be dereferenced!)
     pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx, &str> {
         let len = mplace.len(self)?;
-        let bytes = self.read_bytes_ptr(mplace.ptr, Size::from_bytes(len))?;
+        let bytes = self.read_bytes_ptr_strip_provenance(mplace.ptr, Size::from_bytes(len))?;
         let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?;
         Ok(str)
     }
@@ -444,7 +444,7 @@ pub fn operand_to_simd(
         }
     }
 
-    /// Read from a local. Will not actually access the local if reading from a ZST.
+    /// Read from a local.
     /// Will not access memory, instead an indirect `Operand` is returned.
     ///
     /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an
@@ -456,12 +456,7 @@ pub fn local_to_op(
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         let layout = self.layout_of_local(frame, local, layout)?;
-        let op = if layout.is_zst() {
-            // Bypass `access_local` (helps in ConstProp)
-            Operand::Immediate(Immediate::Uninit)
-        } else {
-            *M::access_local(frame, local)?
-        };
+        let op = *frame.locals[local].access()?;
         Ok(OpTy { op, layout, align: Some(layout.align.abi) })
     }
 
index 7aa76fe1dae0a1f40656e6b4ebe79a777b8b6adc..a03b0dfb6038b737739098c77213a4433caab1e5 100644 (file)
@@ -2,8 +2,6 @@
 //! into a place.
 //! All high-level functions to write to memory work on places as destinations.
 
-use std::hash::Hash;
-
 use rustc_ast::Mutability;
 use rustc_middle::mir;
 use rustc_middle::ty;
@@ -290,7 +288,7 @@ pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Prov> {
 // FIXME: Working around https://github.com/rust-lang/rust/issues/54385
 impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M>
 where
-    Prov: Provenance + Eq + Hash + 'static,
+    Prov: Provenance + 'static,
     M: Machine<'mir, 'tcx, Provenance = Prov>,
 {
     /// Take a value, which represents a (thin or wide) reference, and make it a place.
@@ -642,7 +640,7 @@ fn copy_op_no_validate(
         // avoid force_allocation.
         let src = match self.read_immediate_raw(src)? {
             Ok(src_val) => {
-                assert!(!src.layout.is_unsized(), "cannot have unsized immediates");
+                assert!(!src.layout.is_unsized(), "cannot copy unsized immediates");
                 assert!(
                     !dest.layout.is_unsized(),
                     "the src is sized, so the dest must also be sized"
index 742339f2b0aff0c76c440b06f981d2899d5163cc..77da8f1041eeaf961e70e661ba911878e265a35c 100644 (file)
@@ -1,14 +1,12 @@
 //! This file implements "place projections"; basically a symmetric API for 3 types: MPlaceTy, OpTy, PlaceTy.
 //!
-//! OpTy and PlaceTy genrally work by "let's see if we are actually an MPlaceTy, and do something custom if not".
+//! OpTy and PlaceTy generally work by "let's see if we are actually an MPlaceTy, and do something custom if not".
 //! For PlaceTy, the custom thing is basically always to call `force_allocation` and then use the MPlaceTy logic anyway.
 //! For OpTy, the custom thing on field pojections has to be pretty clever (since `Operand::Immediate` can have fields),
 //! but for array/slice operations it only has to worry about `Operand::Uninit`. That makes the value part trivial,
 //! but we still need to do bounds checking and adjust the layout. To not duplicate that with MPlaceTy, we actually
 //! implement the logic on OpTy, and MPlaceTy calls that.
 
-use std::hash::Hash;
-
 use rustc_middle::mir;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::LayoutOf;
@@ -22,7 +20,7 @@
 // FIXME: Working around https://github.com/rust-lang/rust/issues/54385
 impl<'mir, 'tcx: 'mir, Prov, M> InterpCx<'mir, 'tcx, M>
 where
-    Prov: Provenance + Eq + Hash + 'static,
+    Prov: Provenance + 'static,
     M: Machine<'mir, 'tcx, Provenance = Prov>,
 {
     //# Field access
@@ -100,6 +98,8 @@ pub fn operand_field(
         // This makes several assumptions about what layouts we will encounter; we match what
         // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`).
         let field_val: Immediate<_> = match (*base, base.layout.abi) {
+            // if the entire value is uninit, then so is the field (can happen in ConstProp)
+            (Immediate::Uninit, _) => Immediate::Uninit,
             // the field contains no information, can be left uninit
             _ if field_layout.is_zst() => Immediate::Uninit,
             // the field covers the entire type
@@ -124,6 +124,7 @@ pub fn operand_field(
                     b_val
                 })
             }
+            // everything else is a bug
             _ => span_bug!(
                 self.cur_span(),
                 "invalid field access on immediate {}, layout {:#?}",
index 683e11ff7e0e50fc97448cff63ad10185b48e03c..6b827149f505ea60f6c7c44e1d7fb39652eb67fa 100644 (file)
@@ -251,8 +251,8 @@ pub fn eval_rvalue_into_place(
 
             Len(place) => {
                 let src = self.eval_place(place)?;
-                let mplace = self.force_allocation(&src)?;
-                let len = mplace.len(self)?;
+                let op = self.place_to_op(&src)?;
+                let len = op.len(self)?;
                 self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?;
             }
 
index a71a5d4b833c8c43d2681f92afe6544e6c45ae4e..ea366eba77245b90ec7a44dad831c7a3c68d60b4 100644 (file)
@@ -217,7 +217,7 @@ fn check_argument_compat(
         // When comparing the PassMode, we have to be smart about comparing the attributes.
         let arg_attr_compat = |a1: &ArgAttributes, a2: &ArgAttributes| {
             // There's only one regular attribute that matters for the call ABI: InReg.
-            // Everything else is things like noalias, dereferencable, nonnull, ...
+            // Everything else is things like noalias, dereferenceable, nonnull, ...
             // (This also applies to pointee_size, pointee_align.)
             if a1.regular.contains(ArgAttribute::InReg) != a2.regular.contains(ArgAttribute::InReg)
             {
@@ -556,7 +556,7 @@ pub(crate) fn eval_fn_call(
                     .tcx
                     .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env);
                 let ty::Dynamic(data, ..) = receiver_tail.kind() else {
-                    span_bug!(self.cur_span(), "dyanmic call on non-`dyn` type {}", receiver_tail)
+                    span_bug!(self.cur_span(), "dynamic call on non-`dyn` type {}", receiver_tail)
                 };
 
                 // Get the required information from the vtable.
index b3a511d5a492bdd146f3e36cda800d14a3fd032e..cab23b7241ffc2ea2649103b83552c091d00119a 100644 (file)
@@ -32,7 +32,7 @@ pub fn get_vtable_ptr(
         Ok(vtable_ptr.into())
     }
 
-    /// Returns a high-level representation of the entires of the given vtable.
+    /// Returns a high-level representation of the entries of the given vtable.
     pub fn get_vtable_entries(
         &self,
         vtable: Pointer<Option<M::Provenance>>,
index 2d096199e91227b6f4db4f52629f9e7c5d848f7c..14aaee6ac3f9ea1168dccb5c502aa6e90dc0c0b0 100644 (file)
 
 use std::hash::Hash;
 
+// for the validation errors
+use super::UndefinedBehaviorInfo::*;
 use super::{
-    alloc_range, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy,
-    Machine, MemPlaceMeta, OpTy, Scalar, ValueVisitor,
+    CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine,
+    MemPlaceMeta, OpTy, Scalar, ValueVisitor,
 };
 
 macro_rules! throw_validation_failure {
@@ -60,6 +62,7 @@ macro_rules! throw_validation_failure {
 /// });
 /// ```
 ///
+/// The patterns must be of type `UndefinedBehaviorInfo`.
 /// An additional expected parameter can also be added to the failure message:
 ///
 /// ```
@@ -87,7 +90,7 @@ macro_rules! try_validation {
             // allocation here as this can only slow down builds that fail anyway.
             Err(e) => match e.kind() {
                 $(
-                    $($p)|+ =>
+                    InterpError::UndefinedBehavior($($p)|+) =>
                        throw_validation_failure!(
                             $where,
                             { $( $what_fmt ),+ } $( expected { $( $expected_fmt ),+ } )?
@@ -313,8 +316,7 @@ fn read_immediate(
         Ok(try_validation!(
             self.ecx.read_immediate(op),
             self.path,
-            err_unsup!(ReadPointerAsBytes) => { "(potentially part of) a pointer" } expected { "{expected}" },
-            err_ub!(InvalidUninitBytes(None)) => { "uninitialized memory" } expected { "{expected}" }
+            InvalidUninitBytes(None) => { "uninitialized memory" } expected { "{expected}" }
         ))
     }
 
@@ -339,18 +341,14 @@ fn check_wide_ptr_meta(
                 let (_ty, _trait) = try_validation!(
                     self.ecx.get_ptr_vtable(vtable),
                     self.path,
-                    err_ub!(DanglingIntPointer(..)) |
-                    err_ub!(InvalidVTablePointer(..)) =>
+                    DanglingIntPointer(..) |
+                    InvalidVTablePointer(..) =>
                         { "{vtable}" } expected { "a vtable pointer" },
                 );
                 // FIXME: check if the type/trait match what ty::Dynamic says?
             }
             ty::Slice(..) | ty::Str => {
-                let _len = try_validation!(
-                    meta.unwrap_meta().to_machine_usize(self.ecx),
-                    self.path,
-                    err_unsup!(ReadPointerAsBytes) => { "non-integer slice length in wide pointer" },
-                );
+                let _len = meta.unwrap_meta().to_machine_usize(self.ecx)?;
                 // We do not check that `len * elem_size <= isize::MAX`:
                 // that is only required for references, and there it falls out of the
                 // "dereferenceable" check performed by Stacked Borrows.
@@ -381,7 +379,7 @@ fn check_safe_pointer(
         let size_and_align = try_validation!(
             self.ecx.size_and_align_of_mplace(&place),
             self.path,
-            err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg },
+            InvalidMeta(msg) => { "invalid {} metadata: {}", kind, msg },
         );
         let (size, align) = size_and_align
             // for the purpose of validity, consider foreign types to have
@@ -397,21 +395,21 @@ fn check_safe_pointer(
                 CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
             ),
             self.path,
-            err_ub!(AlignmentCheckFailed { required, has }) =>
+            AlignmentCheckFailed { required, has } =>
                 {
                     "an unaligned {kind} (required {} byte alignment but found {})",
                     required.bytes(),
                     has.bytes()
                 },
-            err_ub!(DanglingIntPointer(0, _)) =>
+            DanglingIntPointer(0, _) =>
                 { "a null {kind}" },
-            err_ub!(DanglingIntPointer(i, _)) =>
+            DanglingIntPointer(i, _) =>
                 { "a dangling {kind} (address {i:#x} is unallocated)" },
-            err_ub!(PointerOutOfBounds { .. }) =>
+            PointerOutOfBounds { .. } =>
                 { "a dangling {kind} (going beyond the bounds of its allocation)" },
             // This cannot happen during const-eval (because interning already detects
             // dangling pointers), but it can happen in Miri.
-            err_ub!(PointerUseAfterFree(..)) =>
+            PointerUseAfterFree(..) =>
                 { "a dangling {kind} (use-after-free)" },
         );
         // Do not allow pointers to uninhabited types.
@@ -499,7 +497,7 @@ fn try_visit_primitive(
                 try_validation!(
                     value.to_bool(),
                     self.path,
-                    err_ub!(InvalidBool(..)) =>
+                    InvalidBool(..) =>
                         { "{:x}", value } expected { "a boolean" },
                 );
                 Ok(true)
@@ -509,7 +507,7 @@ fn try_visit_primitive(
                 try_validation!(
                     value.to_char(),
                     self.path,
-                    err_ub!(InvalidChar(..)) =>
+                    InvalidChar(..) =>
                         { "{:x}", value } expected { "a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)" },
                 );
                 Ok(true)
@@ -568,8 +566,8 @@ fn try_visit_primitive(
                     let _fn = try_validation!(
                         self.ecx.get_ptr_fn(ptr),
                         self.path,
-                        err_ub!(DanglingIntPointer(..)) |
-                        err_ub!(InvalidFunctionPointer(..)) =>
+                        DanglingIntPointer(..) |
+                        InvalidFunctionPointer(..) =>
                             { "{ptr}" } expected { "a function pointer" },
                     );
                     // FIXME: Check if the signature matches
@@ -684,12 +682,10 @@ fn read_discriminant(
             Ok(try_validation!(
                 this.ecx.read_discriminant(op),
                 this.path,
-                err_ub!(InvalidTag(val)) =>
+                InvalidTag(val) =>
                     { "{:x}", val } expected { "a valid enum tag" },
-                err_ub!(InvalidUninitBytes(None)) =>
+                InvalidUninitBytes(None) =>
                     { "uninitialized bytes" } expected { "a valid enum tag" },
-                err_unsup!(ReadPointerAsBytes) =>
-                    { "a pointer" } expected { "a valid enum tag" },
             )
             .1)
         })
@@ -829,10 +825,9 @@ fn visit_aggregate(
                 let mplace = op.assert_mem_place(); // strings are unsized and hence never immediate
                 let len = mplace.len(self.ecx)?;
                 try_validation!(
-                    self.ecx.read_bytes_ptr(mplace.ptr, Size::from_bytes(len)),
+                    self.ecx.read_bytes_ptr_strip_provenance(mplace.ptr, Size::from_bytes(len)),
                     self.path,
-                    err_ub!(InvalidUninitBytes(..)) => { "uninitialized data in `str`" },
-                    err_unsup!(ReadPointerAsBytes) => { "a pointer in `str`" },
+                    InvalidUninitBytes(..) => { "uninitialized data in `str`" },
                 );
             }
             ty::Array(tys, ..) | ty::Slice(tys)
@@ -880,9 +875,9 @@ fn visit_aggregate(
                 // We also accept uninit, for consistency with the slow path.
                 let alloc = self.ecx.get_ptr_alloc(mplace.ptr, size, mplace.align)?.expect("we already excluded size 0");
 
-                match alloc.check_bytes(alloc_range(Size::ZERO, size)) {
+                match alloc.get_bytes_strip_provenance() {
                     // In the happy case, we needn't check anything else.
-                    Ok(()) => {}
+                    Ok(_) => {}
                     // Some error happened, try to provide a more detailed description.
                     Err(err) => {
                         // For some errors we might be able to provide extra information.
@@ -900,9 +895,6 @@ fn visit_aggregate(
 
                                 throw_validation_failure!(self.path, { "uninitialized bytes" })
                             }
-                            err_unsup!(ReadPointerAsBytes) => {
-                                throw_validation_failure!(self.path, { "a pointer" } expected { "plain (non-pointer) bytes" })
-                            }
 
                             // Propagate upwards (that will also check for unexpected errors).
                             _ => return Err(err),
@@ -943,14 +935,14 @@ fn validate_operand_internal(
             Ok(()) => Ok(()),
             // Pass through validation failures.
             Err(err) if matches!(err.kind(), err_ub!(ValidationFailure { .. })) => Err(err),
-            // Also pass through InvalidProgram, those just indicate that we could not
-            // validate and each caller will know best what to do with them.
-            Err(err) if matches!(err.kind(), InterpError::InvalidProgram(_)) => Err(err),
-            // Avoid other errors as those do not show *where* in the value the issue lies.
-            Err(err) => {
+            // Complain about any other kind of UB error -- those are bad because we'd like to
+            // report them in a way that shows *where* in the value the issue lies.
+            Err(err) if matches!(err.kind(), InterpError::UndefinedBehavior(_)) => {
                 err.print_backtrace();
-                bug!("Unexpected error during validation: {}", err);
+                bug!("Unexpected Undefined Behavior error during validation: {}", err);
             }
+            // Pass through everything else.
+            Err(err) => Err(err),
         }
     }
 
index 7272ae5aa0976b4a036eb244699fbaa2160a4313..72ac6af685dc4b247341c8a9fec847e1177cac83 100644 (file)
@@ -9,6 +9,7 @@
 #![feature(control_flow_enum)]
 #![feature(decl_macro)]
 #![feature(exact_size_is_empty)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
index 6301388d1e84091fa97f262ea76babfb0cf7c9ad..f5ba408bee0e132955e38c978f7a03e5a1c478ba 100644 (file)
@@ -41,7 +41,7 @@ pub struct PromoteTemps<'tcx> {
 
 impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
     fn phase_change(&self) -> Option<MirPhase> {
-        Some(MirPhase::ConstsPromoted)
+        Some(MirPhase::Analysis(AnalysisPhase::Initial))
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -964,7 +964,7 @@ pub fn promote_candidates<'tcx>(
         let mut scope = body.source_scopes[body.source_info(candidate.location).scope].clone();
         scope.parent_scope = None;
 
-        let promoted = Body::new(
+        let mut promoted = Body::new(
             body.source, // `promoted` gets filled in below
             IndexVec::new(),
             IndexVec::from_elem_n(scope, 1),
@@ -976,6 +976,7 @@ pub fn promote_candidates<'tcx>(
             body.generator_kind(),
             body.tainted_by_errors,
         );
+        promoted.phase = MirPhase::Analysis(AnalysisPhase::Initial);
 
         let promoter = Promoter {
             promoted,
index 45a94972c1134b8fd2cd4523713e724fe5ccf5fc..b798862583952eb5d1604a56750c14850ac8c6ab 100644 (file)
@@ -8,8 +8,8 @@
 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, Rvalue, SourceScope,
-    Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK,
+    MirPass, MirPhase, 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;
@@ -181,16 +181,23 @@ fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
         if (src, dest).has_opaque_types() {
             return true;
         }
-        // Normalize projections and things like that.
-        let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
-        let src = self.tcx.normalize_erasing_regions(param_env, src);
-        let dest = self.tcx.normalize_erasing_regions(param_env, dest);
 
+        // Normalize projections and things like that.
         // Type-changing assignments can happen when subtyping is used. While
         // all normal lifetimes are erased, higher-ranked types with their
         // late-bound lifetimes are still around and can lead to type
         // differences. So we compare ignoring lifetimes.
-        equal_up_to_regions(self.tcx, param_env, src, dest)
+
+        // First, try with reveal_all. This might not work in some cases, as the predicates
+        // can be cleared in reveal_all mode. We try the reveal first anyways as it is used
+        // by some other passes like inlining as well.
+        let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
+        if equal_up_to_regions(self.tcx, param_env, src, dest) {
+            return true;
+        }
+
+        // If this fails, we can try it without the reveal.
+        equal_up_to_regions(self.tcx, self.param_env, src, dest)
     }
 }
 
@@ -221,7 +228,8 @@ fn visit_local(&mut self, local: Local, context: PlaceContext, location: Locatio
 
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed.
-        if self.tcx.sess.opts.unstable_opts.validate_mir && self.mir_phase < MirPhase::DropsLowered
+        if self.tcx.sess.opts.unstable_opts.validate_mir
+            && self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial)
         {
             // `Operand::Copy` is only supposed to be used with `Copy` types.
             if let Operand::Copy(place) = operand {
@@ -252,7 +260,9 @@ fn visit_projection_elem(
                     self.fail(location, format!("bad index ({:?} != usize)", index_ty))
                 }
             }
-            ProjectionElem::Deref if self.mir_phase >= MirPhase::GeneratorsLowered => {
+            ProjectionElem::Deref
+                if self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup) =>
+            {
                 let base_ty = Place::ty_from(local, proj_base, &self.body.local_decls, self.tcx).ty;
 
                 if base_ty.is_box() {
@@ -360,7 +370,7 @@ fn visit_place(&mut self, place: &Place<'tcx>, cntxt: PlaceContext, location: Lo
         // Set off any `bug!`s in the type computation code
         let _ = place.ty(&self.body.local_decls, self.tcx);
 
-        if self.mir_phase >= MirPhase::Derefered
+        if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial)
             && place.projection.len() > 1
             && cntxt != PlaceContext::NonUse(VarDebugInfo)
             && place.projection[1..].contains(&ProjectionElem::Deref)
@@ -384,8 +394,7 @@ macro_rules! check_kinds {
             Rvalue::Aggregate(agg_kind, _) => {
                 let disallowed = match **agg_kind {
                     AggregateKind::Array(..) => false,
-                    AggregateKind::Generator(..) => self.mir_phase >= MirPhase::GeneratorsLowered,
-                    _ => self.mir_phase >= MirPhase::Deaggregated,
+                    _ => self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup),
                 };
                 if disallowed {
                     self.fail(
@@ -395,10 +404,10 @@ macro_rules! check_kinds {
                 }
             }
             Rvalue::Ref(_, BorrowKind::Shallow, _) => {
-                if self.mir_phase >= MirPhase::DropsLowered {
+                if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(
                         location,
-                        "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase",
+                        "`Assign` statement with a `Shallow` borrow should have been removed in runtime MIR",
                     );
                 }
             }
@@ -612,7 +621,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 }
             }
             StatementKind::AscribeUserType(..) => {
-                if self.mir_phase >= MirPhase::DropsLowered {
+                if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(
                         location,
                         "`AscribeUserType` should have been removed after drop lowering phase",
@@ -620,7 +629,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 }
             }
             StatementKind::FakeRead(..) => {
-                if self.mir_phase >= MirPhase::DropsLowered {
+                if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(
                         location,
                         "`FakeRead` should have been removed after drop lowering phase",
@@ -664,7 +673,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 }
             }
             StatementKind::SetDiscriminant { place, .. } => {
-                if self.mir_phase < MirPhase::Deaggregated {
+                if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(location, "`SetDiscriminant`is not allowed until deaggregation");
                 }
                 let pty = place.ty(&self.body.local_decls, self.tcx).ty.kind();
@@ -679,7 +688,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 }
             }
             StatementKind::Deinit(..) => {
-                if self.mir_phase < MirPhase::Deaggregated {
+                if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(location, "`Deinit`is not allowed until deaggregation");
                 }
             }
@@ -759,7 +768,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 }
             }
             TerminatorKind::DropAndReplace { target, unwind, .. } => {
-                if self.mir_phase >= MirPhase::DropsLowered {
+                if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(
                         location,
                         "`DropAndReplace` should have been removed during drop elaboration",
@@ -830,7 +839,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 if self.body.generator.is_none() {
                     self.fail(location, "`Yield` cannot appear outside generator bodies");
                 }
-                if self.mir_phase >= MirPhase::GeneratorsLowered {
+                if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(location, "`Yield` should have been replaced by generator lowering");
                 }
                 self.check_edge(location, *resume, EdgeKind::Normal);
@@ -839,7 +848,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 }
             }
             TerminatorKind::FalseEdge { real_target, imaginary_target } => {
-                if self.mir_phase >= MirPhase::DropsLowered {
+                if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(
                         location,
                         "`FalseEdge` should have been removed after drop elaboration",
@@ -849,7 +858,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 self.check_edge(location, *imaginary_target, EdgeKind::Normal);
             }
             TerminatorKind::FalseUnwind { real_target, unwind } => {
-                if self.mir_phase >= MirPhase::DropsLowered {
+                if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(
                         location,
                         "`FalseUnwind` should have been removed after drop elaboration",
@@ -872,7 +881,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 if self.body.generator.is_none() {
                     self.fail(location, "`GeneratorDrop` cannot appear outside generator bodies");
                 }
-                if self.mir_phase >= MirPhase::GeneratorsLowered {
+                if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(
                         location,
                         "`GeneratorDrop` should have been replaced by generator lowering",
index 5c641f54f686d8a99b3abd71c8507dfadbaaaeb4..2d8658db5e6aacb45eed5283d42b1c67d148b41d 100644 (file)
@@ -8,25 +8,26 @@ doctest = false
 
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
+bitflags = "1.2.1"
+cfg-if = "0.1.2"
 ena = "0.14"
 indexmap = { version = "1.9.1" }
-tracing = "0.1"
 jobserver_crate = { version = "0.1.13", package = "jobserver" }
-rustc_serialize = { path = "../rustc_serialize" }
-rustc_macros = { path = "../rustc_macros" }
-rustc_graphviz = { path = "../rustc_graphviz" }
-cfg-if = "0.1.2"
-stable_deref_trait = "1.0.0"
-rayon = { version = "0.4.0", package = "rustc-rayon", optional = true }
+libc = "0.2"
+measureme = "10.0.0"
 rayon-core = { version = "0.4.0", package = "rustc-rayon-core", optional = true }
+rayon = { version = "0.4.0", package = "rustc-rayon", optional = true }
+rustc_graphviz = { path = "../rustc_graphviz" }
 rustc-hash = "1.1.0"
-smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] }
 rustc_index = { path = "../rustc_index", package = "rustc_index" }
-bitflags = "1.2.1"
-measureme = "10.0.0"
-libc = "0.2"
+rustc_macros = { path = "../rustc_macros" }
+rustc_serialize = { path = "../rustc_serialize" }
+smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] }
+stable_deref_trait = "1.0.0"
 stacker = "0.1.14"
 tempfile = "3.2"
+thin-vec = "0.2.8"
+tracing = "0.1"
 
 [dependencies.parking_lot]
 version = "0.11"
index 5ff2d18dd2be375bd77725bb8f217b25110840cf..a39178016ce20617dda20a517959ae7843ade27b 100644 (file)
@@ -29,7 +29,7 @@ pub fn to_smaller_hash(&self) -> u64 {
         // quality hash values, let's still combine the two values because the
         // Fingerprints in DefPathHash have the StableCrateId portion which is
         // the same for all DefPathHashes from the same crate. Combining the
-        // two halfs makes sure we get a good quality hash in such cases too.
+        // two halves makes sure we get a good quality hash in such cases too.
         self.0.wrapping_mul(3).wrapping_add(self.1)
     }
 
@@ -120,7 +120,7 @@ fn write_fingerprint(&mut self, fingerprint: &Fingerprint) {
         // quality hash values, let's still combine the two values because the
         // Fingerprints in DefPathHash have the StableCrateId portion which is
         // the same for all DefPathHashes from the same crate. Combining the
-        // two halfs makes sure we get a good quality hash in such cases too.
+        // two halves makes sure we get a good quality hash in such cases too.
         //
         // Since `Unhasher` is used only in the context of HashMaps, it is OK
         // to combine the two components in an order-independent way (which is
index c8b09cffe0136e0ef5cfb8b4d5c9a4262fb0c0ea..a7429ed008fb8d1d496c0b4f6e58ac5b96579c46 100644 (file)
@@ -75,7 +75,6 @@ pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
 pub mod sharded;
 pub mod stack;
 pub mod sync;
-pub mod thin_vec;
 pub mod tiny_list;
 pub mod transitive_relation;
 pub mod vec_linked_list;
index d912211443a893813d6b5c4fda225f2487765289..a0d4b7ade1f33385e751e48b4379fa9323183f1c 100644 (file)
@@ -1,6 +1,6 @@
-use crate::thin_vec::ThinVec;
 use smallvec::{Array, SmallVec};
 use std::ptr;
+use thin_vec::ThinVec;
 
 pub trait MapInPlace<T>: Sized {
     fn map_in_place<F>(&mut self, mut f: F)
index 9efea1228ab29e8ad42783aee9adc7165ef2f5a8..937cb671573a1c97b2096d3dab4382075365a97e 100644 (file)
@@ -164,7 +164,7 @@ pub fn offset_keys<F>(&mut self, f: F)
     /// It is up to the caller to make sure that the elements are sorted by key
     /// and that there are no duplicates.
     #[inline]
-    pub fn insert_presorted(&mut self, mut elements: Vec<(K, V)>) {
+    pub fn insert_presorted(&mut self, elements: Vec<(K, V)>) {
         if elements.is_empty() {
             return;
         }
@@ -173,28 +173,28 @@ pub fn insert_presorted(&mut self, mut elements: Vec<(K, V)>) {
 
         let start_index = self.lookup_index_for(&elements[0].0);
 
-        let drain = match start_index {
+        let elements = match start_index {
             Ok(index) => {
-                let mut drain = elements.drain(..);
-                self.data[index] = drain.next().unwrap();
-                drain
+                let mut elements = elements.into_iter();
+                self.data[index] = elements.next().unwrap();
+                elements
             }
             Err(index) => {
                 if index == self.data.len() || elements.last().unwrap().0 < self.data[index].0 {
                     // We can copy the whole range without having to mix with
                     // existing elements.
-                    self.data.splice(index..index, elements.drain(..));
+                    self.data.splice(index..index, elements.into_iter());
                     return;
                 }
 
-                let mut drain = elements.drain(..);
-                self.data.insert(index, drain.next().unwrap());
-                drain
+                let mut elements = elements.into_iter();
+                self.data.insert(index, elements.next().unwrap());
+                elements
             }
         };
 
         // Insert the rest
-        for (k, v) in drain {
+        for (k, v) in elements {
             self.insert(k, v);
         }
     }
diff --git a/compiler/rustc_data_structures/src/thin_vec.rs b/compiler/rustc_data_structures/src/thin_vec.rs
deleted file mode 100644 (file)
index fce42e7..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-use crate::stable_hasher::{HashStable, StableHasher};
-
-use std::iter::FromIterator;
-
-/// A vector type optimized for cases where this size is usually 0 (cf. `SmallVec`).
-/// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`,
-/// which uses only a single (null) pointer.
-#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq)]
-pub struct ThinVec<T>(Option<Box<Vec<T>>>);
-
-impl<T> ThinVec<T> {
-    pub fn new() -> Self {
-        ThinVec(None)
-    }
-
-    pub fn iter(&self) -> std::slice::Iter<'_, T> {
-        self.into_iter()
-    }
-
-    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
-        self.into_iter()
-    }
-
-    pub fn push(&mut self, item: T) {
-        match *self {
-            ThinVec(Some(ref mut vec)) => vec.push(item),
-            ThinVec(None) => *self = vec![item].into(),
-        }
-    }
-
-    /// Note: if `set_len(0)` is called on a non-empty `ThinVec`, it will
-    /// remain in the `Some` form. This is required for some code sequences
-    /// (such as the one in `flat_map_in_place`) that call `set_len(0)` before
-    /// an operation that might panic, and then call `set_len(n)` again
-    /// afterwards.
-    pub unsafe fn set_len(&mut self, new_len: usize) {
-        match *self {
-            ThinVec(None) => {
-                // A prerequisite of `Vec::set_len` is that `new_len` must be
-                // less than or equal to capacity(). The same applies here.
-                if new_len != 0 {
-                    panic!("unsafe ThinVec::set_len({})", new_len);
-                }
-            }
-            ThinVec(Some(ref mut vec)) => vec.set_len(new_len),
-        }
-    }
-
-    pub fn insert(&mut self, index: usize, value: T) {
-        match *self {
-            ThinVec(None) => {
-                if index == 0 {
-                    *self = vec![value].into();
-                } else {
-                    panic!("invalid ThinVec::insert");
-                }
-            }
-            ThinVec(Some(ref mut vec)) => vec.insert(index, value),
-        }
-    }
-
-    pub fn remove(&mut self, index: usize) -> T {
-        match self {
-            ThinVec(None) => panic!("invalid ThinVec::remove"),
-            ThinVec(Some(vec)) => vec.remove(index),
-        }
-    }
-
-    pub fn as_slice(&self) -> &[T] {
-        match self {
-            ThinVec(None) => &[],
-            ThinVec(Some(vec)) => vec.as_slice(),
-        }
-    }
-}
-
-impl<T> From<Vec<T>> for ThinVec<T> {
-    fn from(vec: Vec<T>) -> Self {
-        if vec.is_empty() { ThinVec(None) } else { ThinVec(Some(Box::new(vec))) }
-    }
-}
-
-impl<T> Into<Vec<T>> for ThinVec<T> {
-    fn into(self) -> Vec<T> {
-        match self {
-            ThinVec(None) => Vec::new(),
-            ThinVec(Some(vec)) => *vec,
-        }
-    }
-}
-
-impl<T> ::std::ops::Deref for ThinVec<T> {
-    type Target = [T];
-    fn deref(&self) -> &[T] {
-        match *self {
-            ThinVec(None) => &[],
-            ThinVec(Some(ref vec)) => vec,
-        }
-    }
-}
-
-impl<T> ::std::ops::DerefMut for ThinVec<T> {
-    fn deref_mut(&mut self) -> &mut [T] {
-        match *self {
-            ThinVec(None) => &mut [],
-            ThinVec(Some(ref mut vec)) => vec,
-        }
-    }
-}
-
-impl<T> FromIterator<T> for ThinVec<T> {
-    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
-        // `Vec::from_iter()` should not allocate if the iterator is empty.
-        let vec: Vec<_> = iter.into_iter().collect();
-        if vec.is_empty() { ThinVec(None) } else { ThinVec(Some(Box::new(vec))) }
-    }
-}
-
-impl<T> IntoIterator for ThinVec<T> {
-    type Item = T;
-    type IntoIter = std::vec::IntoIter<T>;
-
-    fn into_iter(self) -> Self::IntoIter {
-        // This is still performant because `Vec::new()` does not allocate.
-        self.0.map_or_else(Vec::new, |ptr| *ptr).into_iter()
-    }
-}
-
-impl<'a, T> IntoIterator for &'a ThinVec<T> {
-    type Item = &'a T;
-    type IntoIter = std::slice::Iter<'a, T>;
-
-    fn into_iter(self) -> Self::IntoIter {
-        self.as_ref().iter()
-    }
-}
-
-impl<'a, T> IntoIterator for &'a mut ThinVec<T> {
-    type Item = &'a mut T;
-    type IntoIter = std::slice::IterMut<'a, T>;
-
-    fn into_iter(self) -> Self::IntoIter {
-        self.as_mut().iter_mut()
-    }
-}
-
-impl<T> Extend<T> for ThinVec<T> {
-    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
-        match *self {
-            ThinVec(Some(ref mut vec)) => vec.extend(iter),
-            ThinVec(None) => *self = iter.into_iter().collect::<Vec<_>>().into(),
-        }
-    }
-
-    fn extend_one(&mut self, item: T) {
-        self.push(item)
-    }
-
-    fn extend_reserve(&mut self, additional: usize) {
-        match *self {
-            ThinVec(Some(ref mut vec)) => vec.reserve(additional),
-            ThinVec(None) => *self = Vec::with_capacity(additional).into(),
-        }
-    }
-}
-
-impl<T: HashStable<CTX>, CTX> HashStable<CTX> for ThinVec<T> {
-    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        (**self).hash_stable(hcx, hasher)
-    }
-}
-
-impl<T> Default for ThinVec<T> {
-    fn default() -> Self {
-        Self(None)
-    }
-}
-
-#[cfg(test)]
-mod tests;
diff --git a/compiler/rustc_data_structures/src/thin_vec/tests.rs b/compiler/rustc_data_structures/src/thin_vec/tests.rs
deleted file mode 100644 (file)
index 0221b99..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-use super::*;
-
-impl<T> ThinVec<T> {
-    fn into_vec(self) -> Vec<T> {
-        self.into()
-    }
-}
-
-#[test]
-fn test_from_iterator() {
-    assert_eq!(std::iter::empty().collect::<ThinVec<String>>().into_vec(), Vec::<String>::new());
-    assert_eq!(std::iter::once(42).collect::<ThinVec<_>>().into_vec(), vec![42]);
-    assert_eq!([1, 2].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2]);
-    assert_eq!([1, 2, 3].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2, 3]);
-}
-
-#[test]
-fn test_into_iterator_owned() {
-    assert_eq!(ThinVec::new().into_iter().collect::<Vec<String>>(), Vec::<String>::new());
-    assert_eq!(ThinVec::from(vec![1]).into_iter().collect::<Vec<_>>(), vec![1]);
-    assert_eq!(ThinVec::from(vec![1, 2]).into_iter().collect::<Vec<_>>(), vec![1, 2]);
-    assert_eq!(ThinVec::from(vec![1, 2, 3]).into_iter().collect::<Vec<_>>(), vec![1, 2, 3]);
-}
-
-#[test]
-fn test_into_iterator_ref() {
-    assert_eq!(ThinVec::new().iter().collect::<Vec<&String>>(), Vec::<&String>::new());
-    assert_eq!(ThinVec::from(vec![1]).iter().collect::<Vec<_>>(), vec![&1]);
-    assert_eq!(ThinVec::from(vec![1, 2]).iter().collect::<Vec<_>>(), vec![&1, &2]);
-    assert_eq!(ThinVec::from(vec![1, 2, 3]).iter().collect::<Vec<_>>(), vec![&1, &2, &3]);
-}
-
-#[test]
-fn test_into_iterator_ref_mut() {
-    assert_eq!(ThinVec::new().iter_mut().collect::<Vec<&mut String>>(), Vec::<&mut String>::new());
-    assert_eq!(ThinVec::from(vec![1]).iter_mut().collect::<Vec<_>>(), vec![&mut 1]);
-    assert_eq!(ThinVec::from(vec![1, 2]).iter_mut().collect::<Vec<_>>(), vec![&mut 1, &mut 2]);
-    assert_eq!(
-        ThinVec::from(vec![1, 2, 3]).iter_mut().collect::<Vec<_>>(),
-        vec![&mut 1, &mut 2, &mut 3],
-    );
-}
index 4570c1448337eec7b661868deb0d81d64f219916..d1d02ed73f9595a3847d38d96eb8665fc56badbc 100644 (file)
@@ -7,7 +7,7 @@ edition = "2021"
 crate-type = ["dylib"]
 
 [dependencies]
-tracing = { version = "0.1.28" }
+tracing = { version = "0.1.35" }
 serde_json = "1.0.59"
 rustc_log = { path = "../rustc_log" }
 rustc_middle = { path = "../rustc_middle" }
index f66b1a2976f1cd0427da976c31a92d50fddcef88..faeacd3e41040d317183beaacfbe7137ed4e1177 100644 (file)
@@ -1,5 +1,6 @@
 //! The various pretty-printing routines.
 
+use crate::session_diagnostics::UnprettyDumpFail;
 use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
 use rustc_errors::ErrorGuaranteed;
@@ -357,12 +358,15 @@ fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
     (src, src_name)
 }
 
-fn write_or_print(out: &str, ofile: Option<&Path>) {
+fn write_or_print(out: &str, ofile: Option<&Path>, sess: &Session) {
     match ofile {
         None => print!("{}", out),
         Some(p) => {
             if let Err(e) = std::fs::write(p, out) {
-                panic!("print-print failed to write {} due to {}", p.display(), e);
+                sess.emit_fatal(UnprettyDumpFail {
+                    path: p.display().to_string(),
+                    err: e.to_string(),
+                });
             }
         }
     }
@@ -402,7 +406,7 @@ pub fn print_after_parsing(
         _ => unreachable!(),
     };
 
-    write_or_print(&out, ofile);
+    write_or_print(&out, ofile, sess);
 }
 
 pub fn print_after_hir_lowering<'tcx>(
@@ -468,7 +472,7 @@ pub fn print_after_hir_lowering<'tcx>(
         _ => unreachable!(),
     };
 
-    write_or_print(&out, ofile);
+    write_or_print(&out, ofile, tcx.sess);
 }
 
 // In an ideal world, this would be a public function called by the driver after
@@ -512,7 +516,7 @@ fn print_with_analysis(
         _ => unreachable!(),
     };
 
-    write_or_print(&out, ofile);
+    write_or_print(&out, ofile, tcx.sess);
 
     Ok(())
 }
index fe64d0fca9b20c58771ce834bdb5c28a594e3912..e9696792d051f59bcc891e5e87f2f5a6cd9cf265 100644 (file)
@@ -31,3 +31,10 @@ pub(crate) struct RLinkRustcVersionMismatch<'a> {
 #[derive(SessionDiagnostic)]
 #[diag(driver::rlink_no_a_file)]
 pub(crate) struct RlinkNotAFile;
+
+#[derive(SessionDiagnostic)]
+#[diag(driver::unpretty_dump_fail)]
+pub(crate) struct UnprettyDumpFail {
+    pub path: String,
+    pub err: String,
+}
index dcb1e2b08306fe65b23864db9ab851ba9ee1bb65..f2790531aba44de40e247d6d7a8b4d956fd08684 100644 (file)
@@ -129,3 +129,5 @@ ast_lowering_not_supported_for_lifetime_binder_async_closure =
 
 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
index db91a886c725e4ab9a0ebf0c52dd2df426fe28b5..d7108e1e2de35e5dbc22da59213a42b39cf8388b 100644 (file)
@@ -4,6 +4,10 @@ ast_passes_forbidden_let =
     .not_supported_or = `||` operators are not supported in let chain expressions
     .not_supported_parentheses = `let`s wrapped in parentheses are not supported in a context with let chains
 
+ast_passes_forbidden_let_stable =
+    expected expression, found statement (`let`)
+    .note = variable declaration using `let` is a statement
+
 ast_passes_deprecated_where_clause_location =
     where clause not allowed here
 
index 73f084cf3290bf7d1d8e7a0af03b4a35410aafa4..8ad198c86c933460a359e9e8b9aaaae7b7b05a44 100644 (file)
@@ -9,3 +9,5 @@ driver_rlink_encoding_version_mismatch = .rlink file was produced with encoding
 driver_rlink_rustc_version_mismatch = .rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}`
 
 driver_rlink_no_a_file = rlink must be a file
+
+driver_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}`
diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl
new file mode 100644 (file)
index 0000000..00067a1
--- /dev/null
@@ -0,0 +1,272 @@
+metadata_rlib_required =
+    crate `{$crate_name}` required to be available in rlib format, but was not found in this form
+
+metadata_lib_required =
+    crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+
+metadata_crate_dep_multiple =
+    cannot satisfy dependencies so `{$crate_name}` only shows up once
+    .help = having upstream crates all available in one format will likely make this go away
+
+metadata_two_panic_runtimes =
+    cannot link together two panic runtimes: {$prev_name} and {$cur_name}
+
+metadata_bad_panic_strategy =
+    the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}`
+
+metadata_required_panic_strategy =
+    the crate `{$crate_name}` requires panic strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
+
+metadata_incompatible_panic_in_drop_strategy =
+    the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
+
+metadata_multiple_names_in_link =
+    multiple `name` arguments in a single `#[link]` attribute
+
+metadata_multiple_kinds_in_link =
+    multiple `kind` arguments in a single `#[link]` attribute
+
+metadata_link_name_form =
+    link name must be of the form `name = "string"`
+
+metadata_link_kind_form =
+    link kind must be of the form `kind = "string"`
+
+metadata_link_modifiers_form =
+    link modifiers must be of the form `modifiers = "string"`
+
+metadata_link_cfg_form =
+    link cfg must be of the form `cfg(/* predicate */)`
+
+metadata_wasm_import_form =
+    wasm import module must be of the form `wasm_import_module = "string"`
+
+metadata_empty_link_name =
+    link name must not be empty
+    .label = empty link name
+
+metadata_link_framework_apple =
+    link kind `framework` is only supported on Apple targets
+
+metadata_framework_only_windows =
+    link kind `raw-dylib` is only supported on Windows targets
+
+metadata_unknown_link_kind =
+    unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib
+    .label = unknown link kind
+
+metadata_multiple_link_modifiers =
+    multiple `modifiers` arguments in a single `#[link]` attribute
+
+metadata_multiple_cfgs =
+    multiple `cfg` arguments in a single `#[link]` attribute
+
+metadata_link_cfg_single_predicate =
+    link cfg must have a single predicate argument
+
+metadata_multiple_wasm_import =
+    multiple `wasm_import_module` arguments in a single `#[link]` attribute
+
+metadata_unexpected_link_arg =
+    unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
+
+metadata_invalid_link_modifier =
+    invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
+
+metadata_multiple_modifiers =
+    multiple `{$modifier}` modifiers in a single `modifiers` argument
+
+metadata_bundle_needs_static =
+    linking modifier `bundle` is only compatible with `static` linking kind
+
+metadata_whole_archive_needs_static =
+    linking modifier `whole-archive` is only compatible with `static` linking kind
+
+metadata_as_needed_compatibility =
+    linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds
+
+metadata_unknown_link_modifier =
+    unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
+
+metadata_incompatible_wasm_link =
+    `wasm_import_module` is incompatible with other arguments in `#[link]` attributes
+
+metadata_link_requires_name =
+    `#[link]` attribute requires a `name = "string"` argument
+    .label = missing `name` argument
+
+metadata_raw_dylib_no_nul =
+    link name must not contain NUL characters if link kind is `raw-dylib`
+
+metadata_link_ordinal_raw_dylib =
+    `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+
+metadata_lib_framework_apple =
+    library kind `framework` is only supported on Apple targets
+
+metadata_empty_renaming_target =
+    an empty renaming target was specified for library `{$lib_name}`
+
+metadata_renaming_no_link =
+    renaming of the library `{$lib_name}` was specified, however this crate contains no `#[link(...)]` attributes referencing this library
+
+metadata_multiple_renamings =
+    multiple renamings were specified for library `{$lib_name}`
+
+metadata_no_link_mod_override =
+    overriding linking modifiers from command line is not supported
+
+metadata_unsupported_abi_i686 =
+    ABI not supported by `#[link(kind = "raw-dylib")]` on i686
+
+metadata_unsupported_abi =
+    ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
+
+metadata_fail_create_file_encoder =
+    failed to create file encoder: {$err}
+
+metadata_fail_seek_file =
+    failed to seek the file: {$err}
+
+metadata_fail_write_file =
+    failed to write to the file: {$err}
+
+metadata_crate_not_panic_runtime =
+    the crate `{$crate_name}` is not a panic runtime
+
+metadata_no_panic_strategy =
+    the crate `{$crate_name}` does not have the panic strategy `{$strategy}`
+
+metadata_profiler_builtins_needs_core =
+    `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]`
+
+metadata_not_profiler_runtime =
+    the crate `{$crate_name}` is not a profiler runtime
+
+metadata_no_multiple_global_alloc =
+    cannot define multiple global allocators
+    .label = cannot define a new global allocator
+
+metadata_prev_global_alloc =
+    previous global allocator defined here
+
+metadata_conflicting_global_alloc =
+    the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
+
+metadata_global_alloc_required =
+    no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
+
+metadata_no_transitive_needs_dep =
+    the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}`
+
+metadata_failed_write_error =
+    failed to write {$filename}: {$err}
+
+metadata_failed_create_tempdir =
+    couldn't create a temp dir: {$err}
+
+metadata_failed_create_file =
+    failed to create the file {$filename}: {$err}
+
+metadata_failed_create_encoded_metadata =
+    failed to create encoded metadata from file: {$err}
+
+metadata_non_ascii_name =
+    cannot load a crate with a non-ascii name `{$crate_name}`
+
+metadata_extern_location_not_exist =
+    extern location for {$crate_name} does not exist: {$location}
+
+metadata_extern_location_not_file =
+    extern location for {$crate_name} is not a file: {$location}
+
+metadata_multiple_candidates =
+    multiple {$flavor} candidates for `{$crate_name}` found
+
+metadata_multiple_matching_crates =
+    multiple matching crates for `{$crate_name}`
+    .note = candidates:{$candidates}
+
+metadata_symbol_conflicts_current =
+    the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two.
+
+metadata_symbol_conflicts_others =
+    found two different crates with name `{$crate_name}` that are not distinguished by differing `-C metadata`. This will result in symbol conflicts between the two.
+
+metadata_stable_crate_id_collision =
+    found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values.
+
+metadata_dl_error =
+    {$err}
+
+metadata_newer_crate_version =
+    found possibly newer version of crate `{$crate_name}`{$add_info}
+    .note = perhaps that crate needs to be recompiled?
+
+metadata_found_crate_versions =
+    the following crate versions were found:{$found_crates}
+
+metadata_no_crate_with_triple =
+    couldn't find crate `{$crate_name}` with expected target triple {$locator_triple}{$add_info}
+
+metadata_found_staticlib =
+    found staticlib `{$crate_name}` instead of rlib or dylib{$add_info}
+    .help = please recompile that crate using --crate-type lib
+
+metadata_incompatible_rustc =
+    found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info}
+    .help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first)
+
+metadata_invalid_meta_files =
+    found invalid metadata files for crate `{$crate_name}`{$add_info}
+
+metadata_cannot_find_crate =
+    can't find crate for `{$crate_name}`{$add_info}
+
+metadata_no_dylib_plugin =
+    plugin `{$crate_name}` only found in rlib format, but must be available in dylib format
+
+metadata_target_not_installed =
+    the `{$locator_triple}` target may not be installed
+
+metadata_target_no_std_support =
+    the `{$locator_triple}` target may not support the standard library
+
+metadata_consider_downloading_target =
+    consider downloading the target with `rustup target add {$locator_triple}`
+
+metadata_std_required =
+    `std` is required by `{$current_crate}` because it does not declare `#![no_std]`
+
+metadata_consider_building_std =
+    consider building the standard library from source with `cargo build -Zbuild-std`
+
+metadata_compiler_missing_profiler =
+    the compiler may have been built without the profiler runtime
+
+metadata_install_missing_components =
+    maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`
+
+metadata_cant_find_crate =
+    can't find crate
+
+metadata_crate_location_unknown_type =
+    extern location for {$crate_name} is of an unknown type: {$path}
+
+metadata_lib_filename_form =
+    file name should be lib*.rlib or {dll_prefix}*.{dll_suffix}
+
+metadata_multiple_import_name_type =
+    multiple `import_name_type` arguments in a single `#[link]` attribute
+
+metadata_import_name_type_form =
+    import name type must be of the form `import_name_type = "string"`
+
+metadata_import_name_type_x86 =
+    import name type is only supported on x86
+
+metadata_unknown_import_name_type =
+    unknown import name type `{$import_name_type}`, expected one of: decorated, noprefix, undecorated
+
+metadata_import_name_type_raw =
+    import name type can only be used with link kind `raw-dylib`
diff --git a/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl b/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl
new file mode 100644 (file)
index 0000000..42c84fd
--- /dev/null
@@ -0,0 +1,26 @@
+monomorphize_recursion_limit =
+    reached the recursion limit while instantiating `{$shrunk}`
+    .note = `{$def_path_str}` defined here
+
+monomorphize_written_to_path = the full type name has been written to '{$path}'
+
+monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
+
+monomorphize_consider_type_length_limit =
+    consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate
+
+monomorphize_fatal_error = {$error_message}
+
+monomorphize_unknown_partition_strategy = unknown partitioning strategy
+
+monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
+
+monomorphize_unused_generic_params = item has unused generic parameters
+
+monomorphize_large_assignments =
+    moving {$size} bytes
+    .label = value moved from here
+    .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+
+monomorphize_requires_lang_item =
+    requires `{$lang_item}` lang_item
index 223092a74bd97cf00d62ed229dcbae3493e985c4..da987152ff66030dcdbba447d15dce67950c45b9 100644 (file)
@@ -11,6 +11,8 @@ privacy_in_public_interface = {$vis_descr} {$kind} `{$descr}` in public interfac
     .label = can't leak {$vis_descr} {$kind}
     .visibility_label = `{$descr}` declared as {$vis_descr}
 
+privacy_report_access_level = {$descr}
+
 privacy_from_private_dep_in_public_interface =
     {$kind} `{$descr}` from private dependency '{$krate}' in public interface
 
diff --git a/compiler/rustc_error_messages/locales/en-US/query_system.ftl b/compiler/rustc_error_messages/locales/en-US/query_system.ftl
new file mode 100644 (file)
index 0000000..167704e
--- /dev/null
@@ -0,0 +1,25 @@
+query_system_reentrant = internal compiler error: re-entrant incremental verify failure, suppressing message
+
+query_system_increment_compilation = internal compiler error: encountered incremental compilation error with {$dep_node}
+    .help = This is a known issue with the compiler. Run {$run_cmd} to allow your project to compile
+
+query_system_increment_compilation_note1 = Please follow the instructions below to create a bug report with the provided information
+query_system_increment_compilation_note2 = See <https://github.com/rust-lang/rust/issues/84970> for more information
+
+query_system_cycle = cycle detected when {$stack_bottom}
+
+query_system_cycle_usage = cycle used when {$usage}
+
+query_system_cycle_stack_single = ...which immediately requires {$stack_bottom} again
+
+query_system_cycle_stack_multiple = ...which again requires {$stack_bottom}, completing the cycle
+
+query_system_cycle_recursive_ty_alias = type aliases cannot be recursive
+query_system_cycle_recursive_ty_alias_help1 = consider using a struct, enum, or union instead to break the cycle
+query_system_cycle_recursive_ty_alias_help2 = see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
+
+query_system_cycle_recursive_trait_alias = trait aliases cannot be recursive
+
+query_system_cycle_which_requires = ...which requires {$desc}...
+
+query_system_query_overflow = queries overflow the depth limit!
diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl
new file mode 100644 (file)
index 0000000..983e5ce
--- /dev/null
@@ -0,0 +1,16 @@
+session_incorrect_cgu_reuse_type =
+    CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
+    [one] {"at least "}
+    *[other] {""}
+    }`{$expected_reuse}`
+
+session_cgu_not_recorded =
+    CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded`
+
+session_feature_gate_error = {$explain}
+
+session_feature_diagnostic_for_issue =
+    see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
+
+session_feature_diagnostic_help =
+    add `#![feature({$feature})]` to the crate attributes to enable
diff --git a/compiler/rustc_error_messages/locales/en-US/symbol_mangling.ftl b/compiler/rustc_error_messages/locales/en-US/symbol_mangling.ftl
new file mode 100644 (file)
index 0000000..55d6fbb
--- /dev/null
@@ -0,0 +1,7 @@
+symbol_mangling_invalid_symbol_name = symbol-name({$mangled_formatted})
+
+symbol_mangling_invalid_trait_item = demangling({$demangling_formatted})
+
+symbol_mangling_alt_invalid_trait_item = demangling-alt({$alt_demangling_formatted})
+
+symbol_mangling_invalid_def_path = def-path({$def_path})
diff --git a/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl b/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl
new file mode 100644 (file)
index 0000000..004e0ab
--- /dev/null
@@ -0,0 +1,26 @@
+trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries}
+
+trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}
+
+trait_selection_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}`
+    .label = deref recursion limit reached
+    .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
+
+trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]`
+    .label = empty on-clause here
+
+trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]`
+    .label = invalid on-clause here
+
+trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value
+    .label = expected value here
+    .note = eg `#[rustc_on_unimplemented(message="foo")]`
+
+trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc ->
+        [none] {""}
+       *[default] {" "}for type `{$self_desc}`
+    }:
+    .negative_implementation_here = negative implementation here
+    .negative_implementation_in_crate = negative implementation in crate `{$negative_impl_cname}`
+    .positive_implementation_here = positive implementation here
+    .positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}`
index b17668dc0ae7718fd194f2931625483ced29ef5d..5281a287b0dbe81f22398144636bbe1cb65d1d94 100644 (file)
@@ -1,9 +1,13 @@
+#![feature(let_chains)]
 #![feature(once_cell)]
 #![feature(rustc_attrs)]
 #![feature(type_alias_impl_trait)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
+#[macro_use]
+extern crate tracing;
+
 use fluent_bundle::FluentResource;
 use fluent_syntax::parser::ParserError;
 use rustc_data_structures::sync::Lrc;
@@ -15,7 +19,6 @@
 use std::fs;
 use std::io;
 use std::path::{Path, PathBuf};
-use tracing::{instrument, trace};
 
 #[cfg(not(parallel_compiler))]
 use std::cell::LazyCell as Lazy;
     const_eval => "../locales/en-US/const_eval.ftl",
     driver => "../locales/en-US/driver.ftl",
     expand => "../locales/en-US/expand.ftl",
+    session => "../locales/en-US/session.ftl",
     interface => "../locales/en-US/interface.ftl",
     infer => "../locales/en-US/infer.ftl",
     lint => "../locales/en-US/lint.ftl",
+    monomorphize => "../locales/en-US/monomorphize.ftl",
+    metadata => "../locales/en-US/metadata.ftl",
     parser => "../locales/en-US/parser.ftl",
     passes => "../locales/en-US/passes.ftl",
     plugin_impl => "../locales/en-US/plugin_impl.ftl",
     privacy => "../locales/en-US/privacy.ftl",
+    query_system => "../locales/en-US/query_system.ftl",
+    trait_selection => "../locales/en-US/trait_selection.ftl",
     save_analysis => "../locales/en-US/save_analysis.ftl",
     ty_utils => "../locales/en-US/ty_utils.ftl",
     typeck => "../locales/en-US/typeck.ftl",
     mir_dataflow => "../locales/en-US/mir_dataflow.ftl",
+    symbol_mangling => "../locales/en-US/symbol_mangling.ftl",
 }
 
 pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
index 36805aa874fe7740961f1740f80317f74556e02e..4d207fd17fb2dfb9b2f16d3e9a9fa9f8a2a023f4 100644 (file)
@@ -15,13 +15,14 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_lint_defs = { path = "../rustc_lint_defs" }
+rustc_target = { path = "../rustc_target" }
 unicode-width = "0.1.4"
 atty = "0.2"
 termcolor = "1.0"
 annotate-snippets = "0.9"
 termize = "0.1.1"
-serde = { version = "1.0.125", features = ["derive"] }
+serde = { version = "1.0.125", features = [ "derive" ] }
 serde_json = "1.0.59"
 
 [target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["handleapi", "synchapi", "winbase"] }
+winapi = { version = "0.3", features = [ "handleapi", "synchapi", "winbase" ] }
index 506198df4d8edd2e24896c219bd9e9416ee576ba..a052aaee047567610702f244baf0a1910f193464 100644 (file)
@@ -10,6 +10,7 @@
 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 std::borrow::Cow;
 use std::fmt;
 use std::hash::{Hash, Hasher};
@@ -144,6 +145,12 @@ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
     }
 }
 
+impl IntoDiagnosticArg for PanicStrategy {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string()))
+    }
+}
+
 impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
     fn into(self) -> FluentValue<'source> {
         match self {
@@ -686,19 +693,12 @@ pub fn tool_only_multipart_suggestion(
         suggestion: Vec<(Span, String)>,
         applicability: Applicability,
     ) -> &mut Self {
-        assert!(!suggestion.is_empty());
-        self.push_suggestion(CodeSuggestion {
-            substitutions: vec![Substitution {
-                parts: suggestion
-                    .into_iter()
-                    .map(|(span, snippet)| SubstitutionPart { snippet, span })
-                    .collect(),
-            }],
-            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
-            style: SuggestionStyle::CompletelyHidden,
+        self.multipart_suggestion_with_style(
+            msg,
+            suggestion,
             applicability,
-        });
-        self
+            SuggestionStyle::CompletelyHidden,
+        )
     }
 
     /// Prints out a message with a suggested edit of the code.
@@ -981,12 +981,12 @@ pub fn sub(
     fn sub_with_highlights<M: Into<SubdiagnosticMessage>>(
         &mut self,
         level: Level,
-        mut message: Vec<(M, Style)>,
+        message: Vec<(M, Style)>,
         span: MultiSpan,
         render_span: Option<MultiSpan>,
     ) {
         let message = message
-            .drain(..)
+            .into_iter()
             .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1))
             .collect();
         let sub = SubDiagnostic { level, message, span, render_span };
index 61d767a1cc6b4f97d806c45b8a0d3a127ec2d59a..7e29dc207accecca9a86275ec477cb9426c2b087 100644 (file)
@@ -12,7 +12,6 @@
 use std::marker::PhantomData;
 use std::ops::{Deref, DerefMut};
 use std::thread::panicking;
-use tracing::debug;
 
 /// Used for emitting structured error messages and other diagnostic information.
 ///
index 6c1bfcb9919eb9df89a3124f90bf16a655da2645..e79ce11a6fc075a8bdf162f7b63256b066c89a29 100644 (file)
@@ -34,7 +34,6 @@
 use std::path::Path;
 use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream};
 use termcolor::{Buffer, Color, WriteColor};
-use tracing::*;
 
 /// Default column width, used in tests and when terminal dimensions cannot be determined.
 const DEFAULT_COLUMN_WIDTH: usize = 140;
index 9b9c334d4dfcc2bbd852fa2db85272685f5813e9..68abdd0bad1ff06165317a28d1f20392b33ba96e 100644 (file)
@@ -6,6 +6,7 @@
 #![feature(drain_filter)]
 #![feature(if_let_guard)]
 #![feature(adt_const_params)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
 #![feature(result_option_inspect)]
@@ -1248,9 +1249,13 @@ fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_ext
     }
 
     fn treat_err_as_bug(&self) -> bool {
-        self.flags
-            .treat_err_as_bug
-            .map_or(false, |c| self.err_count() + self.lint_err_count >= c.get())
+        self.flags.treat_err_as_bug.map_or(false, |c| {
+            self.err_count()
+                + self.lint_err_count
+                + self.delayed_span_bugs.len()
+                + self.delayed_good_path_bugs.len()
+                >= c.get()
+        })
     }
 
     fn print_error_count(&mut self, registry: &Registry) {
@@ -1406,7 +1411,14 @@ fn delay_span_bug(
         // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
         // incrementing `err_count` by one, so we need to +1 the comparing.
         // FIXME: Would be nice to increment err_count in a more coherent way.
-        if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c.get()) {
+        if self.flags.treat_err_as_bug.map_or(false, |c| {
+            self.err_count()
+                + self.lint_err_count
+                + self.delayed_span_bugs.len()
+                + self.delayed_good_path_bugs.len()
+                + 1
+                >= c.get()
+        }) {
             // FIXME: don't abort here if report_delayed_bugs is off
             self.span_bug(sp, msg);
         }
index 65338f56d9ccb5ea545c607095c61966e8191f4e..4f407badb3f9eb777e3857ac835dccc9cdab1993 100644 (file)
@@ -21,7 +21,7 @@ pub trait Translate {
     /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
     /// passed around as a reference thereafter.
     fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> {
-        FromIterator::from_iter(args.to_vec().drain(..))
+        FromIterator::from_iter(args.iter().cloned())
     }
 
     /// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
index e1dde1672c1905daa3677cbbd9d600ff32503fc9..ac0e200b1b73ee783e22affe3e6b48ab2b4a435f 100644 (file)
@@ -2,6 +2,7 @@
 #![feature(associated_type_bounds)]
 #![feature(associated_type_defaults)]
 #![feature(if_let_guard)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(macro_metavar_expr)]
 #![feature(proc_macro_diagnostic)]
@@ -14,6 +15,9 @@
 #[macro_use]
 extern crate rustc_macros;
 
+#[macro_use]
+extern crate tracing;
+
 extern crate proc_macro as pm;
 
 mod placeholders;
index 4fa91dfeaea27847b274c5242bce21202f1f0011..c8bdc39311c6550c7c206eb0b24e6bc1fc099b22 100644 (file)
@@ -430,7 +430,7 @@ fn parse_tt_inner(
                     }
                 }
                 MatcherLoc::Delimited => {
-                    // Entering the delimeter is trivial.
+                    // Entering the delimiter is trivial.
                     mp.idx += 1;
                     self.cur_mps.push(mp);
                 }
index e009e4f7c68d09388b4e9c26388fdae6755528fd..7764ffd246e323d205c992bd61627c9652ce3b05 100644 (file)
@@ -32,7 +32,6 @@
 use std::borrow::Cow;
 use std::collections::hash_map::Entry;
 use std::{mem, slice};
-use tracing::debug;
 
 pub(crate) struct ParserAnyMacro<'a> {
     parser: Parser<'a>,
@@ -976,7 +975,7 @@ fn replace_with_irrelevant(&mut self) {
         self.maybe_empty = false;
     }
 
-    // Adds `tok` to the set for `self`, marking sequence as non-empy.
+    // Adds `tok` to the set for `self`, marking sequence as non-empty.
     fn add_one(&mut self, tt: TtHandle<'tt>) {
         if !self.tokens.contains(&tt) {
             self.tokens.push(tt);
index beb33c05913cf8c9e5ee81c064db5f1dd729c9c9..59a7b668a83ce96d1da7811bef686cd23980a242 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Diagnostic, MultiSpan, PResult};
+use rustc_errors::{MultiSpan, PResult};
 use rustc_parse::lexer::nfc_normalize;
 use rustc_parse::parse_stream_from_source_str;
 use rustc_session::parse::ParseSess;
@@ -15,7 +15,7 @@
 use rustc_span::{BytePos, FileName, Pos, SourceFile, Span};
 
 use pm::bridge::{
-    server, DelimSpan, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
+    server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
 };
 use pm::{Delimiter, Level, LineColumn};
 use std::ops::Bound;
@@ -368,8 +368,6 @@ impl server::Types for Rustc<'_, '_> {
     type FreeFunctions = FreeFunctions;
     type TokenStream = TokenStream;
     type SourceFile = Lrc<SourceFile>;
-    type MultiSpan = Vec<Span>;
-    type Diagnostic = Diagnostic;
     type Span = Span;
     type Symbol = Symbol;
 }
@@ -436,6 +434,21 @@ fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symb
             span: self.call_site,
         })
     }
+
+    fn emit_diagnostic(&mut self, diagnostic: Diagnostic<Self::Span>) {
+        let mut diag =
+            rustc_errors::Diagnostic::new(diagnostic.level.to_internal(), diagnostic.message);
+        diag.set_span(MultiSpan::from_spans(diagnostic.spans));
+        for child in diagnostic.children {
+            diag.sub(
+                child.level.to_internal(),
+                child.message,
+                MultiSpan::from_spans(child.spans),
+                None,
+            );
+        }
+        self.sess().span_diagnostic.emit_diagnostic(&mut diag);
+    }
 }
 
 impl server::TokenStream for Rustc<'_, '_> {
@@ -583,38 +596,6 @@ fn is_real(&mut self, file: &Self::SourceFile) -> bool {
     }
 }
 
-impl server::MultiSpan for Rustc<'_, '_> {
-    fn new(&mut self) -> Self::MultiSpan {
-        vec![]
-    }
-
-    fn push(&mut self, spans: &mut Self::MultiSpan, span: Self::Span) {
-        spans.push(span)
-    }
-}
-
-impl server::Diagnostic for Rustc<'_, '_> {
-    fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
-        let mut diag = Diagnostic::new(level.to_internal(), msg);
-        diag.set_span(MultiSpan::from_spans(spans));
-        diag
-    }
-
-    fn sub(
-        &mut self,
-        diag: &mut Self::Diagnostic,
-        level: Level,
-        msg: &str,
-        spans: Self::MultiSpan,
-    ) {
-        diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None);
-    }
-
-    fn emit(&mut self, mut diag: Self::Diagnostic) {
-        self.sess().span_diagnostic.emit_diagnostic(&mut diag);
-    }
-}
-
 impl server::Span for Rustc<'_, '_> {
     fn debug(&mut self, span: Self::Span) -> String {
         if self.ecx.ecfg.span_debug {
index fb1ad8d6beb3dfbc417d2a52c20264d0c85b9f80..c22adf77a27f6c4ffaae83ee1ffce37e98bd457e 100644 (file)
@@ -188,8 +188,6 @@ macro_rules! declare_features {
     (accepted, item_like_imports, "1.15.0", Some(35120), None),
     /// Allows `'a: { break 'a; }`.
     (accepted, label_break_value, "CURRENT_RUSTC_VERSION", Some(48594), None),
-    /// Allows `if/while p && let q = r && ...` chains.
-    (accepted, let_chains, "1.64.0", Some(53667), None),
     /// Allows `break {expr}` with a value inside `loop`s.
     (accepted, loop_break_value, "1.19.0", Some(37339), None),
     /// Allows use of `?` as the Kleene "at most one" operator in macros.
index 22178dd2123e50389681de48c2dd72d24e161f66..f71b3d59e2c04cb8d41d5586bfe802d2156e258b 100644 (file)
@@ -422,6 +422,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, isa_attribute, "1.48.0", Some(74727), None),
     // Allows setting the threshold for the `large_assignments` lint.
     (active, large_assignments, "1.52.0", Some(83518), None),
+    /// Allows `if/while p && let q = r && ...` chains.
+    (active, let_chains, "1.37.0", Some(53667), None),
     /// Allows `let...else` statements.
     (active, let_else, "1.56.0", Some(87335), None),
     /// Allows `#[link(..., cfg(..))]`.
@@ -479,8 +481,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (incomplete, raw_dylib, "1.40.0", 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_attr]` attribute.
-    (active, register_attr, "1.41.0", Some(66080), None),
     /// Allows using the `#[register_tool]` attribute.
     (active, register_tool, "1.41.0", Some(66079), None),
     /// Allows the `#[repr(i128)]` attribute for enums.
@@ -519,6 +519,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows creation of instances of a struct by moving fields that have
     /// not changed from prior instances of the same struct (RFC #2528)
     (active, type_changing_struct_update, "1.58.0", Some(86555), None),
+    /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
+    (active, unix_sigpipe, "CURRENT_RUSTC_VERSION", Some(97889), None),
     /// Allows unsized fn parameters.
     (active, unsized_fn_params, "1.49.0", Some(48055), None),
     /// Allows unsized rvalues at arguments and parameters.
index d520efed9b8b8768c33090c579d9e7d6cec33e30..e359d50c4e9e52fff5b101a99d3b8efe8b4e5531 100644 (file)
@@ -359,6 +359,7 @@ pub struct BuiltinAttribute {
     ),
 
     // Entry point:
+    gated!(unix_sigpipe, Normal, template!(Word, NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing, experimental!(unix_sigpipe)),
     ungated!(start, Normal, template!(Word), WarnFollowing),
     ungated!(no_start, CrateLevel, template!(Word), WarnFollowing),
     ungated!(no_main, CrateLevel, template!(Word), WarnFollowing),
@@ -458,10 +459,6 @@ pub struct BuiltinAttribute {
     ),
     gated!(ffi_pure, Normal, template!(Word), WarnFollowing, experimental!(ffi_pure)),
     gated!(ffi_const, Normal, template!(Word), WarnFollowing, experimental!(ffi_const)),
-    gated!(
-        register_attr, CrateLevel, template!(List: "attr1, attr2, ..."), DuplicatesOk,
-        experimental!(register_attr),
-    ),
     gated!(
         register_tool, CrateLevel, template!(List: "tool1, tool2, ..."), DuplicatesOk,
         experimental!(register_tool),
@@ -762,6 +759,7 @@ pub struct BuiltinAttribute {
     // Internal attributes, Testing:
     // ==========================================================================
 
+    rustc_attr!(TEST, rustc_access_level, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_outlives, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
index 2ddaf9201098ec8069e68e3aeb22d7936f21b36f..13f275bb6a0c923c8faf88df743e4409fc28b686 100644 (file)
@@ -163,6 +163,9 @@ macro_rules! declare_features {
     (removed, quad_precision_float, "1.0.0", None, None, None),
     (removed, quote, "1.33.0", Some(29601), None, None),
     (removed, reflect, "1.0.0", Some(27749), None, None),
+    /// Allows using the `#[register_attr]` attribute.
+    (removed, register_attr, "CURRENT_RUSTC_VERSION", Some(66080), None,
+     Some("removed in favor of `#![register_tool]`")),
     /// Allows using the macros:
     /// + `__diagnostic_used`
     /// + `__register_diagnostic`
index be5b7eccbafb2ef34cc1bd53fd2924fe265ac2fe..2d2648a8f35af5e586d70b998e4407a8e5251713 100644 (file)
@@ -45,8 +45,6 @@ pub enum NonMacroAttrKind {
     /// Single-segment custom attribute registered by a derive macro
     /// but used before that derive macro was expanded (deprecated).
     DeriveHelperCompat,
-    /// Single-segment custom attribute registered with `#[register_attr]`.
-    Registered,
 }
 
 /// What kind of definition something is; e.g., `mod` vs `struct`.
@@ -564,15 +562,11 @@ pub fn descr(self) -> &'static str {
             NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::DeriveHelperCompat => {
                 "derive helper attribute"
             }
-            NonMacroAttrKind::Registered => "explicitly registered attribute",
         }
     }
 
     pub fn article(self) -> &'static str {
-        match self {
-            NonMacroAttrKind::Registered => "an",
-            _ => "a",
-        }
+        "a"
     }
 
     /// Users of some attributes cannot mark them as used, so they are considered always used.
@@ -581,7 +575,7 @@ pub fn is_used(self) -> bool {
             NonMacroAttrKind::Tool
             | NonMacroAttrKind::DeriveHelper
             | NonMacroAttrKind::DeriveHelperCompat => true,
-            NonMacroAttrKind::Builtin(..) | NonMacroAttrKind::Registered => false,
+            NonMacroAttrKind::Builtin(..) => false,
         }
     }
 }
index c2c551e78a41105af9ee32fe96fbabbd750a3b7e..d85ac960f9b2f10b415cb0a43d2eaa7de8bfc102 100644 (file)
@@ -15,7 +15,6 @@
 
 use std::fmt::{self, Write};
 use std::hash::Hash;
-use tracing::debug;
 
 /// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa.
 /// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey`
diff --git a/compiler/rustc_hir/src/errors.rs b/compiler/rustc_hir/src/errors.rs
new file mode 100644 (file)
index 0000000..e593ed1
--- /dev/null
@@ -0,0 +1,10 @@
+use crate::LangItem;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
+pub struct LangItemError(pub LangItem);
+
+impl ToString for LangItemError {
+    fn to_string(&self) -> String {
+        format!("requires `{}` lang_item", self.0.name())
+    }
+}
index c337be12ae4929416e36901c49c3f09b7e7b33ce..0c01326d0032ac61842af06569cf493b714d7ed5 100644 (file)
@@ -8,6 +8,7 @@
 //! * Functions called by the compiler itself.
 
 use crate::def_id::DefId;
+use crate::errors::LangItemError;
 use crate::{MethodKind, Target};
 
 use rustc_ast as ast;
@@ -115,9 +116,9 @@ pub fn items(&self) -> &[Option<DefId>] {
 
             /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`.
             /// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`,
-            /// returns an error message as a string.
-            pub fn require(&self, it: LangItem) -> Result<DefId, String> {
-                self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
+            /// returns an error encapsulating the `LangItem`.
+            pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> {
+                self.items[it as usize].ok_or_else(|| LangItemError(it))
             }
 
             /// Returns the [`DefId`]s of all lang items in a group.
index 7097f998bebda712288402632ecc1b25dc5e34f8..1b33cb9c2da9cbcebbe4be41ca0bd6d1d7665e08 100644 (file)
@@ -17,6 +17,9 @@
 #[macro_use]
 extern crate rustc_macros;
 
+#[macro_use]
+extern crate tracing;
+
 #[macro_use]
 extern crate rustc_data_structures;
 
@@ -27,6 +30,7 @@
 pub mod def_path_hash_map;
 pub mod definitions;
 pub mod diagnostic_items;
+pub mod errors;
 pub use rustc_span::def_id;
 mod hir;
 pub mod hir_id;
index e37c0cf0fd0325706ae3a1910a1679b670ae03ba..00e238648712ffaf103d6750c4c5c3b9ce6fbede 100644 (file)
@@ -78,6 +78,10 @@ pub fn fork(&self) -> Self {
             err_count_on_creation: self.err_count_on_creation,
             in_snapshot: self.in_snapshot.clone(),
             universe: self.universe.clone(),
+            normalize_fn_sig_for_diagnostic: self
+                .normalize_fn_sig_for_diagnostic
+                .as_ref()
+                .map(|f| f.clone()),
         }
     }
 }
index ca7862c9dc46778be5f69fa54b76bf54bfc48a86..46f8c0e8d8b9acad49d334fcc9d3dc04852b53b8 100644 (file)
@@ -372,7 +372,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
                 debug!(
                     "canonical: region var found with vid {:?}, \
                      opportunistically resolved to {:?}",
-                    vid, r
+                    vid, resolved_vid
                 );
                 let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
                 self.canonicalize_mode.canonicalize_free_region(self, r)
index 8dc20544f1b1add6279876915572578c8259c64f..64c759f73d410323cc08d6eeb8c688c5b5d7942f 100644 (file)
@@ -63,8 +63,8 @@ pub fn make_canonicalized_query_response<T>(
         Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
     {
         let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?;
+        debug!("query_response = {:#?}", query_response);
         let canonical_result = self.canonicalize_response(query_response);
-
         debug!("canonical_result = {:#?}", canonical_result);
 
         Ok(self.tcx.arena.alloc(canonical_result))
@@ -125,6 +125,7 @@ fn make_query_response<T>(
         debug!("ambig_errors = {:#?}", ambig_errors);
 
         let region_obligations = self.take_registered_region_obligations();
+        debug!(?region_obligations);
         let region_constraints = self.with_region_constraints(|region_constraints| {
             make_query_region_constraints(
                 tcx,
@@ -132,6 +133,7 @@ fn make_query_response<T>(
                 region_constraints,
             )
         });
+        debug!(?region_constraints);
 
         let certainty =
             if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
@@ -632,6 +634,8 @@ pub fn make_query_region_constraints<'tcx>(
     assert!(verifys.is_empty());
     assert!(givens.is_empty());
 
+    debug!(?constraints);
+
     let outlives: Vec<_> = constraints
         .iter()
         .map(|(k, _)| match *k {
index 8bf1de34a9b5cace73b66a13e3f888ebafc6fbb9..d4350aa5734dee4aefe5583a5f1e6233d0cf2303 100644 (file)
@@ -391,7 +391,7 @@ pub fn instantiate(
     /// Preconditions:
     ///
     /// - `for_vid` is a "root vid"
-    #[instrument(skip(self), level = "trace")]
+    #[instrument(skip(self), level = "trace", ret)]
     fn generalize(
         &self,
         ty: Ty<'tcx>,
@@ -435,15 +435,8 @@ fn generalize(
             cache: SsoHashMap::new(),
         };
 
-        let ty = match generalize.relate(ty, ty) {
-            Ok(ty) => ty,
-            Err(e) => {
-                debug!(?e, "failure");
-                return Err(e);
-            }
-        };
+        let ty = generalize.relate(ty, ty)?;
         let needs_wf = generalize.needs_wf;
-        trace!(?ty, ?needs_wf, "success");
         Ok(Generalization { ty, needs_wf })
     }
 
@@ -499,6 +492,7 @@ struct Generalizer<'cx, 'tcx> {
 /// Result from a generalization operation. This includes
 /// not only the generalized type, but also a bool flag
 /// indicating whether further WF checks are needed.
+#[derive(Debug)]
 struct Generalization<'tcx> {
     ty: Ty<'tcx>,
 
@@ -856,10 +850,9 @@ fn binders<T>(
         Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         debug_assert_eq!(t, _t);
-        debug!("ConstInferUnifier: t={:?}", t);
 
         match t.kind() {
             &ty::Infer(ty::TyVar(vid)) => {
@@ -883,12 +876,7 @@ fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                             .borrow_mut()
                             .type_variables()
                             .new_var(self.for_universe, origin);
-                        let u = self.tcx().mk_ty_var(new_var_id);
-                        debug!(
-                            "ConstInferUnifier: replacing original vid={:?} with new={:?}",
-                            vid, u
-                        );
-                        Ok(u)
+                        Ok(self.tcx().mk_ty_var(new_var_id))
                     }
                 }
             }
@@ -932,14 +920,13 @@ fn regions(
         }
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn consts(
         &mut self,
         c: ty::Const<'tcx>,
         _c: ty::Const<'tcx>,
     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         debug_assert_eq!(c, _c);
-        debug!("ConstInferUnifier: c={:?}", c);
 
         match c.kind() {
             ty::ConstKind::Infer(InferConst::Var(vid)) => {
index 465508e12058f9ef9e5ab173b848a2ab6ab015d8..6dad9873d613404a124bac052236be887ecdb7f0 100644 (file)
@@ -961,12 +961,23 @@ fn push_comma(
         }
     }
 
+    fn normalize_fn_sig_for_diagnostic(&self, sig: ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> {
+        if let Some(normalize) = &self.normalize_fn_sig_for_diagnostic {
+            normalize(self, sig)
+        } else {
+            sig
+        }
+    }
+
     /// Given two `fn` signatures highlight only sub-parts that are different.
     fn cmp_fn_sig(
         &self,
         sig1: &ty::PolyFnSig<'tcx>,
         sig2: &ty::PolyFnSig<'tcx>,
     ) -> (DiagnosticStyledString, DiagnosticStyledString) {
+        let sig1 = &self.normalize_fn_sig_for_diagnostic(*sig1);
+        let sig2 = &self.normalize_fn_sig_for_diagnostic(*sig2);
+
         let get_lifetimes = |sig| {
             use rustc_hir::def::Namespace;
             let (_, sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS)
@@ -1423,7 +1434,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
     /// the message in `secondary_span` as the primary label, and apply the message that would
     /// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on
     /// E0271, like `src/test/ui/issues/issue-39970.stderr`.
-    #[tracing::instrument(
+    #[instrument(
         level = "debug",
         skip(self, diag, secondary_span, swap_secondary_and_primary, prefer_label)
     )]
@@ -2044,22 +2055,22 @@ fn suggest_as_ref_where_appropriate(
             (exp_found.expected.kind(), exp_found.found.kind())
         {
             if let ty::Adt(found_def, found_substs) = *found_ty.kind() {
-                let path_str = format!("{:?}", exp_def);
                 if exp_def == &found_def {
-                    let opt_msg = "you can convert from `&Option<T>` to `Option<&T>` using \
-                                       `.as_ref()`";
-                    let result_msg = "you can convert from `&Result<T, E>` to \
-                                          `Result<&T, &E>` using `.as_ref()`";
                     let have_as_ref = &[
-                        ("std::option::Option", opt_msg),
-                        ("core::option::Option", opt_msg),
-                        ("std::result::Result", result_msg),
-                        ("core::result::Result", result_msg),
+                        (
+                            sym::Option,
+                            "you can convert from `&Option<T>` to `Option<&T>` using \
+                        `.as_ref()`",
+                        ),
+                        (
+                            sym::Result,
+                            "you can convert from `&Result<T, E>` to \
+                        `Result<&T, &E>` using `.as_ref()`",
+                        ),
                     ];
-                    if let Some(msg) = have_as_ref
-                        .iter()
-                        .find_map(|(path, msg)| (&path_str == path).then_some(msg))
-                    {
+                    if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| {
+                        self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg)
+                    }) {
                         let mut show_suggestion = true;
                         for (exp_ty, found_ty) in
                             iter::zip(exp_substs.types(), found_substs.types())
@@ -2725,7 +2736,10 @@ fn regions(
         a: ty::Region<'tcx>,
         b: ty::Region<'tcx>,
     ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        if (a.is_var() && b.is_free_or_static()) || (b.is_var() && a.is_free_or_static()) || a == b
+        if (a.is_var() && b.is_free_or_static())
+            || (b.is_var() && a.is_free_or_static())
+            || (a.is_var() && b.is_var())
+            || a == b
         {
             Ok(a)
         } else {
index e990fe7ecb50427edb13538bd0a4a0b985cf7fa0..91a05367eee0242565e6cda3d03e4731e55d2a1a 100644 (file)
@@ -199,7 +199,7 @@ fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
 }
 
 /// We don't want to directly use `ty_to_string` for closures as their type isn't really
-/// something users are familar with. Directly printing the `fn_sig` of closures also
+/// something users are familiar with. Directly printing the `fn_sig` of closures also
 /// doesn't work as they actually use the "rust-call" API.
 fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
     let ty::Closure(_, substs) = ty.kind() else { unreachable!() };
index c1b201da69121c92e5a1b2e63a068a90836a376a..ddad72fdab93d9dfabeba68820cef3edfac199a1 100644 (file)
@@ -103,7 +103,7 @@ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
                     // Find the index of the named region that was part of the
                     // error. We will then search the function parameters for a bound
                     // region at the right depth with the same index
-                    (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
+                    (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
                         debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
                         if id == def_id {
                             self.found_type = Some(arg);
@@ -133,7 +133,7 @@ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
                         Some(
                             rl::Region::Static
                             | rl::Region::Free(_, _)
-                            | rl::Region::EarlyBound(_, _)
+                            | rl::Region::EarlyBound(_)
                             | rl::Region::LateBound(_, _, _),
                         )
                         | None,
@@ -188,7 +188,7 @@ fn nested_visit_map(&mut self) -> Map<'tcx> {
     fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
         match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
             // the lifetime of the TyPath!
-            (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
+            (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
                 debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
                 if id == def_id {
                     self.found_it = true;
@@ -209,7 +209,7 @@ fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
             (
                 Some(
                     rl::Region::Static
-                    | rl::Region::EarlyBound(_, _)
+                    | rl::Region::EarlyBound(_)
                     | rl::Region::LateBound(_, _, _)
                     | rl::Region::Free(_, _),
                 )
index d0d9efe152cc04109799f78aa8df246f6db4a191..67426fcf0feda6c5a7664772c7dfffd8cd941ae1 100644 (file)
@@ -69,7 +69,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// For more details visit the relevant sections of the [rustc dev guide].
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
     where
         T: TypeFoldable<'tcx> + Copy,
@@ -104,9 +104,8 @@ pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T
             },
         };
 
-        let result = self.tcx.replace_bound_vars_uncached(binder, delegate);
-        debug!(?next_universe, ?result);
-        result
+        debug!(?next_universe);
+        self.tcx.replace_bound_vars_uncached(binder, delegate)
     }
 
     /// See [RegionConstraintCollector::leak_check][1].
index 3783cfb4cc5c85c85aaf53e674bdfb7916a95ba8..13b7e8eb9643611e0a5678f9b936250e347ac216 100644 (file)
@@ -333,9 +333,9 @@ fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
     ///
     /// Neither `a` nor `b` may be an inference variable (hence the
     /// term "concrete regions").
-    #[instrument(level = "trace", skip(self))]
+    #[instrument(level = "trace", skip(self), ret)]
     fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
-        let r = match (*a, *b) {
+        match (*a, *b) {
             (ReLateBound(..), _) | (_, ReLateBound(..)) | (ReErased, _) | (_, ReErased) => {
                 bug!("cannot relate region: LUB({:?}, {:?})", a, b);
             }
@@ -399,11 +399,7 @@ fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx>
                     self.tcx().lifetimes.re_static
                 }
             }
-        };
-
-        debug!("lub_concrete_regions({:?}, {:?}) = {:?}", a, b, r);
-
-        r
+        }
     }
 
     /// After expansion is complete, go and check upper bounds (i.e.,
index c95738e0018c09d722a399a6cbc7fe41f0d85a01..fe037a458a7f85106d756c92aef897a779552738 100644 (file)
@@ -337,6 +337,9 @@ pub struct InferCtxt<'a, 'tcx> {
     /// when we enter into a higher-ranked (`for<..>`) type or trait
     /// bound.
     universe: Cell<ty::UniverseIndex>,
+
+    normalize_fn_sig_for_diagnostic:
+        Option<Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
 }
 
 /// See the `error_reporting` module for more details.
@@ -504,7 +507,7 @@ pub enum FixupError<'tcx> {
 }
 
 /// See the `region_obligations` field for more information.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct RegionObligation<'tcx> {
     pub sub_region: ty::Region<'tcx>,
     pub sup_type: Ty<'tcx>,
@@ -540,6 +543,8 @@ pub struct InferCtxtBuilder<'tcx> {
     defining_use_anchor: DefiningAnchor,
     considering_regions: bool,
     fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
+    normalize_fn_sig_for_diagnostic:
+        Option<Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
 }
 
 pub trait TyCtxtInferExt<'tcx> {
@@ -553,6 +558,7 @@ fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
             defining_use_anchor: DefiningAnchor::Error,
             considering_regions: true,
             fresh_typeck_results: None,
+            normalize_fn_sig_for_diagnostic: None,
         }
     }
 }
@@ -582,6 +588,14 @@ pub fn ignoring_regions(mut self) -> Self {
         self
     }
 
+    pub fn with_normalize_fn_sig_for_diagnostic(
+        mut self,
+        fun: Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>,
+    ) -> Self {
+        self.normalize_fn_sig_for_diagnostic = Some(fun);
+        self
+    }
+
     /// Given a canonical value `C` as a starting point, create an
     /// inference context that contains each of the bound values
     /// within instantiated as a fresh variable. The `f` closure is
@@ -611,6 +625,7 @@ pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) ->
             defining_use_anchor,
             considering_regions,
             ref fresh_typeck_results,
+            ref normalize_fn_sig_for_diagnostic,
         } = *self;
         let in_progress_typeck_results = fresh_typeck_results.as_ref();
         f(InferCtxt {
@@ -629,6 +644,9 @@ pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) ->
             in_snapshot: Cell::new(false),
             skip_leak_check: Cell::new(false),
             universe: Cell::new(ty::UniverseIndex::ROOT),
+            normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic
+                .as_ref()
+                .map(|f| f.clone()),
         })
     }
 }
@@ -1315,7 +1333,7 @@ pub fn resolve_regions(
     /// `resolve_vars_if_possible` as well as `fully_resolve`.
     ///
     /// Make sure to call [`InferCtxt::process_registered_region_obligations`]
-    /// first, or preferrably use [`InferCtxt::check_region_obligations_and_report_errors`]
+    /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`]
     /// to do both of these operations together.
     pub fn resolve_regions_and_report_errors(
         &self,
@@ -2027,16 +2045,6 @@ pub fn span(&self) -> Span {
     }
 }
 
-impl<'tcx> fmt::Debug for RegionObligation<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "RegionObligation(sub_region={:?}, sup_type={:?})",
-            self.sub_region, self.sup_type
-        )
-    }
-}
-
 /// Replaces substs that reference param or infer variables with suitable
 /// placeholders. This function is meant to remove these param and infer
 /// substs when they're not actually needed to evaluate a constant.
index bab4f3e9e362ffb4a4c2fcea4c83c45b85d97fcc..bb6f6ae60e26ac27c05ad3e59c889122e90d6ef3 100644 (file)
@@ -396,6 +396,32 @@ fn generalize_value<T: Relate<'tcx>>(
 
         generalizer.relate(value, value)
     }
+
+    fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
+        let mut generalize = |ty, ty_is_expected| {
+            let var = self.infcx.next_ty_var_id_in_universe(
+                TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::MiscVariable,
+                    span: self.delegate.span(),
+                },
+                ty::UniverseIndex::ROOT,
+            );
+            if ty_is_expected {
+                self.relate_ty_var((ty, var))
+            } else {
+                self.relate_ty_var((var, ty))
+            }
+        };
+        let (a, b) = match (a.kind(), b.kind()) {
+            (&ty::Opaque(..), _) => (a, generalize(b, false)?),
+            (_, &ty::Opaque(..)) => (generalize(a, true)?, b),
+            _ => unreachable!(),
+        };
+        self.delegate.register_opaque_type(a, b, true)?;
+        trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
+        Ok(a)
+    }
 }
 
 /// When we instantiate an inference variable with a value in
@@ -516,7 +542,7 @@ fn a_is_expected(&self) -> bool {
         true
     }
 
-    #[instrument(skip(self, info), level = "trace")]
+    #[instrument(skip(self, info), level = "trace", ret)]
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
@@ -534,8 +560,6 @@ fn relate_with_variance<T: Relate<'tcx>>(
 
         self.ambient_variance = old_ambient_variance;
 
-        debug!(?r);
-
         Ok(r)
     }
 
@@ -572,32 +596,16 @@ fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>
             (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
 
             (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
-                self.infcx.super_combine_tys(self, a, b)
+                infcx.commit_if_ok(|_| infcx.super_combine_tys(self, a, b)).or_else(|err| {
+                    self.tcx().sess.delay_span_bug(
+                        self.delegate.span(),
+                        "failure to relate an opaque to itself should result in an error later on",
+                    );
+                    if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
+                })
             }
             (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => {
-                let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
-                let mut generalize = |ty, ty_is_expected| {
-                    let var = infcx.next_ty_var_id_in_universe(
-                        TypeVariableOrigin {
-                            kind: TypeVariableOriginKind::MiscVariable,
-                            span: self.delegate.span(),
-                        },
-                        ty::UniverseIndex::ROOT,
-                    );
-                    if ty_is_expected {
-                        self.relate_ty_var((ty, var))
-                    } else {
-                        self.relate_ty_var((var, ty))
-                    }
-                };
-                let (a, b) = match (a.kind(), b.kind()) {
-                    (&ty::Opaque(..), _) => (a, generalize(b, false)?),
-                    (_, &ty::Opaque(..)) => (generalize(a, true)?, b),
-                    _ => unreachable!(),
-                };
-                self.delegate.register_opaque_type(a, b, true)?;
-                trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
-                Ok(a)
+                self.relate_opaques(a, b)
             }
 
             (&ty::Projection(projection_ty), _)
index 233a5004a3931f53444eaf75538edc8f89d65e6a..d45adf43abfcc0040f0feeb235604eff4cc422a9 100644 (file)
@@ -390,7 +390,7 @@ pub fn register_member_constraints(
         });
     }
 
-    #[instrument(skip(self), level = "trace")]
+    #[instrument(skip(self), level = "trace", ret)]
     pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<OpaqueTyOrigin> {
         let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
         let parent_def_id = match self.defining_use_anchor {
@@ -421,16 +421,14 @@ pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<Opaqu
         in_definition_scope.then_some(*origin)
     }
 
-    #[instrument(skip(self), level = "trace")]
+    #[instrument(skip(self), level = "trace", ret)]
     fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin {
-        let origin = match self.tcx.hir().expect_item(def_id).kind {
+        match self.tcx.hir().expect_item(def_id).kind {
             hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,
             ref itemkind => {
                 span_bug!(span, "weird opaque type: {:?}, {:#?}", def_id, itemkind)
             }
-        };
-        trace!(?origin);
-        origin
+        }
     }
 }
 
index fb12da0cc13f0aeb3661ff34d8c7781d92058d9f..4d124554afb94d3bb119275e9c415932dbc8131b 100644 (file)
@@ -29,7 +29,7 @@ pub(crate) fn remove(&mut self, key: OpaqueTypeKey<'tcx>, idx: Option<OpaqueHidd
         }
     }
 
-    #[instrument(level = "debug")]
+    #[instrument(level = "debug", ret)]
     pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> {
         std::mem::take(&mut self.opaque_types)
     }
index 2a085288fb7c069c8d58d8a776b9e758d0b4078c..2d19d1823fdfc2b04816cde419dd59aa3361009b 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_middle::traits::query::OutlivesBound;
 use rustc_middle::ty;
 
-#[instrument(level = "debug", skip(param_env))]
+#[instrument(level = "debug", skip(param_env), ret)]
 pub fn explicit_outlives_bounds<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
 ) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
index dded0a0a6b1b4e51a75ab741e60f5871cafe7d3b..74c8bd88d275dbfb79589c41d21eab3bd91d169b 100644 (file)
@@ -92,6 +92,7 @@ pub fn register_region_obligation_with_cause(
         sub_region: Region<'tcx>,
         cause: &ObligationCause<'tcx>,
     ) {
+        debug!(?sup_type, ?sub_region, ?cause);
         let origin = SubregionOrigin::from_obligation_cause(cause, || {
             infer::RelateParamBound(
                 cause.span,
@@ -248,14 +249,13 @@ pub fn new(
     /// - `origin`, the reason we need this constraint
     /// - `ty`, the type `T`
     /// - `region`, the region `'a`
+    #[instrument(level = "debug", skip(self))]
     pub fn type_must_outlive(
         &mut self,
         origin: infer::SubregionOrigin<'tcx>,
         ty: Ty<'tcx>,
         region: ty::Region<'tcx>,
     ) {
-        debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})", ty, region, origin);
-
         assert!(!ty.has_escaping_bound_vars());
 
         let mut components = smallvec![];
@@ -313,7 +313,7 @@ fn param_ty_must_outlive(
         self.delegate.push_verify(origin, generic, region, verify_bound);
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn projection_must_outlive(
         &mut self,
         origin: infer::SubregionOrigin<'tcx>,
index be03c8b5bae98a507cec3b8581bd874cea47338c..a5c21f0fb9b50eadf775aac2a6840500f388a00d 100644 (file)
@@ -34,7 +34,7 @@
 /// like are used. This is a particular challenge since this function is invoked
 /// very late in inference and hence cannot make use of the normal inference
 /// machinery.
-#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+#[instrument(level = "debug", skip(tcx, param_env))]
 pub fn extract_verify_if_eq<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -71,7 +71,7 @@ pub fn extract_verify_if_eq<'tcx>(
 }
 
 /// True if a (potentially higher-ranked) outlives
-#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+#[instrument(level = "debug", skip(tcx, param_env))]
 pub(super) fn can_match_erased_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -110,7 +110,7 @@ fn no_match<T>(&self) -> RelateResult<'tcx, T> {
 
     /// Binds the pattern variable `br` to `value`; returns an `Err` if the pattern
     /// is already bound to a different value.
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn bind(
         &mut self,
         br: ty::BoundRegion,
index b27571275b73395da0c74945defec150f9f2dbcf..b7eab5d43285b121e16f34f0ec291e42f31703a7 100644 (file)
@@ -4,6 +4,7 @@
 use crate::infer::combine::ConstEquateRelation;
 use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::traits::Obligation;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::TyVar;
@@ -141,17 +142,27 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                     Ok(infcx.tcx.mk_ty_var(var))
                 };
                 let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) };
-                let (a, b) = match (a.kind(), b.kind()) {
+                let (ga, gb) = match (a.kind(), b.kind()) {
                     (&ty::Opaque(..), _) => (a, generalize(b, true)?),
                     (_, &ty::Opaque(..)) => (generalize(a, false)?, b),
                     _ => unreachable!(),
                 };
                 self.fields.obligations.extend(
                     infcx
-                        .handle_opaque_type(a, b, true, &self.fields.trace.cause, self.param_env())?
+                        .handle_opaque_type(ga, gb, true, &self.fields.trace.cause, self.param_env())
+                        // Don't leak any generalized type variables out of this
+                        // subtyping relation in the case of a type error.
+                        .map_err(|err| {
+                            let (ga, gb) = self.fields.infcx.resolve_vars_if_possible((ga, gb));
+                            if let TypeError::Sorts(sorts) = err && sorts.expected == ga && sorts.found == gb {
+                                TypeError::Sorts(ExpectedFound { expected: a, found: b })
+                            } else {
+                                err
+                            }
+                        })?
                         .obligations,
                 );
-                Ok(a)
+                Ok(ga)
             }
 
             _ => {
index 74a26ebc39f817c0673c1e86e9595312c4d9d8b1..611961ab1cc94afb98501fb1b205e4502af4199a 100644 (file)
@@ -100,7 +100,7 @@ fn default() -> Self {
 }
 
 /// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any
-/// action that is convertable into an UndoLog (per the From impls above).
+/// action that is convertible into an UndoLog (per the From impls above).
 impl<'tcx, T> UndoLogs<T> for InferCtxtUndoLogs<'tcx>
 where
     UndoLog<'tcx>: From<T>,
index 602a9ab13f37792b9a0fdadce06d4f839aadba0e..931ebca7d014524a579c16c78355a2c0e0c74c03 100644 (file)
@@ -18,6 +18,7 @@
 #![feature(control_flow_enum)]
 #![feature(extend_one)]
 #![cfg_attr(bootstrap, feature(label_break_value))]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(never_type)]
index dc4799e4afce14a373336a7c44ca9212c6cf15fd..949bd02ad6839a8f1535e453efc2d08d1a704dcf 100644 (file)
@@ -176,7 +176,7 @@ macro_rules! error {
                                         let ident = arg.ident().expect("multi-segment cfg key");
                                         names_valid.insert(ident.name.to_string());
                                     } else {
-                                        error!("`names()` arguments must be simple identifers");
+                                        error!("`names()` arguments must be simple identifiers");
                                     }
                                 }
                                 continue 'specs;
@@ -204,7 +204,7 @@ macro_rules! error {
                                         continue 'specs;
                                     } else {
                                         error!(
-                                            "`values()` first argument must be a simple identifer"
+                                            "`values()` first argument must be a simple identifier"
                                         );
                                     }
                                 } else if args.is_empty() {
@@ -332,7 +332,7 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R
 // JUSTIFICATION: before session exists, only config
 #[allow(rustc::bad_opt_access)]
 pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
-    tracing::trace!("run_compiler");
+    trace!("run_compiler");
     util::run_in_thread_pool_with_globals(
         config.opts.edition,
         config.opts.unstable_opts.threads,
index 258e38c3bdb9e09197fc006865defaa66903149a..1a8d619fafb6212483b49ab045f40f6e07af901f 100644 (file)
@@ -8,6 +8,9 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
+#[macro_use]
+extern crate tracing;
+
 mod callbacks;
 mod errors;
 pub mod interface;
index 66c6a229b89e4564b4e9130f3191eded516adcf7..f8b40949e2ed993ab2b2c2917d251bd94c824ba7 100644 (file)
@@ -38,7 +38,6 @@
 use rustc_span::FileName;
 use rustc_trait_selection::traits;
 use rustc_typeck as typeck;
-use tracing::{info, warn};
 
 use std::any::Any;
 use std::cell::RefCell;
@@ -165,7 +164,7 @@ pub fn create_resolver(
     krate: &ast::Crate,
     crate_name: &str,
 ) -> BoxedResolver {
-    tracing::trace!("create_resolver");
+    trace!("create_resolver");
     BoxedResolver::new(sess, move |sess, resolver_arenas| {
         Resolver::new(sess, krate, crate_name, metadata_loader, resolver_arenas)
     })
@@ -279,7 +278,7 @@ pub fn configure_and_expand(
     crate_name: &str,
     resolver: &mut Resolver<'_>,
 ) -> Result<ast::Crate> {
-    tracing::trace!("configure_and_expand");
+    trace!("configure_and_expand");
     pre_expansion_lint(sess, lint_store, resolver.registered_tools(), &krate, crate_name);
     rustc_builtin_macros::register_builtin_macros(resolver);
 
index 65fa8d7495a4bf16cc76277a97bf5593e3e29fd9..6c725a01b53151ccfb9325f876442a22920facbf 100644 (file)
@@ -166,7 +166,7 @@ pub fn crate_name(&self) -> Result<&Query<String>> {
     pub fn expansion(
         &self,
     ) -> Result<&Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> {
-        tracing::trace!("expansion");
+        trace!("expansion");
         self.expansion.compute(|| {
             let crate_name = self.crate_name()?.peek().clone();
             let (krate, lint_store) = self.register_plugins()?.take();
index 9207a0488623c94e9ef3aa5fd89280f20942666d..5df5ab3ddc032eb19ec354e3f1bcb012b8b32345 100644 (file)
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
 use rustc_span::SourceFileHashAlgorithm;
-use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
-use rustc_target::spec::{
-    RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel,
-};
+use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
+use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
 
 use std::collections::{BTreeMap, BTreeSet};
 use std::iter::FromIterator;
@@ -552,7 +550,7 @@ macro_rules! untracked {
     untracked!(link_args, vec![String::from("abc"), String::from("def")]);
     untracked!(link_self_contained, Some(true));
     untracked!(linker, Some(PathBuf::from("linker")));
-    untracked!(linker_flavor, Some(LinkerFlavor::Gcc));
+    untracked!(linker_flavor, Some(LinkerFlavorCli::Gcc));
     untracked!(no_stack_check, true);
     untracked!(remark, Passes::Some(vec![String::from("pass1"), String::from("pass2")]));
     untracked!(rpath, true);
index e74978485a21c818e780d1d3a923593a73de7b8c..f7e70d355cf86e6ff3ad519311676536ed3a6e24 100644 (file)
@@ -1,3 +1,4 @@
+use info;
 use libloading::Library;
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
@@ -31,7 +32,6 @@
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::OnceLock;
 use std::thread;
-use tracing::info;
 
 /// Function pointer type that constructs a new CodegenBackend.
 pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
index af7ef96e485b5c9af313ecc990ef878fed14b239..4e9c209a58400aa176d13cf336cf7c01e1cc4a86 100644 (file)
@@ -59,7 +59,6 @@
 use crate::nonstandard_style::{method_context, MethodLateContext};
 
 use std::fmt::Write;
-use tracing::{debug, trace};
 
 // hardwired lints from librustc_middle
 pub use rustc_session::lint::builtin::*;
@@ -2026,13 +2025,13 @@ fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
 impl ExplicitOutlivesRequirements {
     fn lifetimes_outliving_lifetime<'tcx>(
         inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
-        index: u32,
+        def_id: DefId,
     ) -> Vec<ty::Region<'tcx>> {
         inferred_outlives
             .iter()
             .filter_map(|(pred, _)| match pred.kind().skip_binder() {
                 ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
-                    ty::ReEarlyBound(ebr) if ebr.index == index => Some(b),
+                    ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b),
                     _ => None,
                 },
                 _ => None,
@@ -2069,8 +2068,12 @@ fn collect_outlives_bound_spans<'tcx>(
             .filter_map(|(i, bound)| {
                 if let hir::GenericBound::Outlives(lifetime) = bound {
                     let is_inferred = match tcx.named_region(lifetime.hir_id) {
-                        Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| {
-                            if let ty::ReEarlyBound(ebr) = **r { ebr.index == index } else { false }
+                        Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| {
+                            if let ty::ReEarlyBound(ebr) = **r {
+                                ebr.def_id == def_id
+                            } else {
+                                false
+                            }
                         }),
                         _ => false,
                     };
@@ -2164,11 +2167,14 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
             for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
                 let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
                     hir::WherePredicate::RegionPredicate(predicate) => {
-                        if let Some(Region::EarlyBound(index, ..)) =
+                        if let Some(Region::EarlyBound(region_def_id)) =
                             cx.tcx.named_region(predicate.lifetime.hir_id)
                         {
                             (
-                                Self::lifetimes_outliving_lifetime(inferred_outlives, index),
+                                Self::lifetimes_outliving_lifetime(
+                                    inferred_outlives,
+                                    region_def_id,
+                                ),
                                 &predicate.bounds,
                                 predicate.span,
                                 predicate.in_where_clause,
@@ -2462,6 +2468,15 @@ fn ty_find_init_error<'tcx>(
                 Char if init == InitKind::Uninit => {
                     Some(("characters must be a valid Unicode codepoint".to_string(), None))
                 }
+                Int(_) | Uint(_) if init == InitKind::Uninit => {
+                    Some(("integers must not be uninitialized".to_string(), None))
+                }
+                Float(_) if init == InitKind::Uninit => {
+                    Some(("floats must not be uninitialized".to_string(), None))
+                }
+                RawPtr(_) if init == InitKind::Uninit => {
+                    Some(("raw pointers must not be uninitialized".to_string(), None))
+                }
                 // Recurse and checks for some compound types.
                 Adt(adt_def, substs) if !adt_def.is_union() => {
                     // First check if this ADT has a layout attribute (like `NonNull` and friends).
@@ -3157,3 +3172,81 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
         }
     }
 }
+
+declare_lint! {
+    /// The `special_module_name` lint detects module
+    /// declarations for files that have a special meaning.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// mod lib;
+    ///
+    /// fn main() {
+    ///     lib::run();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Cargo recognizes `lib.rs` and `main.rs` as the root of a
+    /// library or binary crate, so declaring them as modules
+    /// will lead to miscompilation of the crate unless configured
+    /// explicitly.
+    ///
+    /// To access a library from a binary target within the same crate,
+    /// use `your_crate_name::` as the path path instead of `lib::`:
+    ///
+    /// ```rust,compile_fail
+    /// // bar/src/lib.rs
+    /// fn run() {
+    ///     // ...
+    /// }
+    ///
+    /// // bar/src/main.rs
+    /// fn main() {
+    ///     bar::run();
+    /// }
+    /// ```
+    ///
+    /// Binary targets cannot be used as libraries and so declaring
+    /// one as a module is not allowed.
+    pub SPECIAL_MODULE_NAME,
+    Warn,
+    "module declarations for files with a special meaning",
+}
+
+declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]);
+
+impl EarlyLintPass for SpecialModuleName {
+    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
+        for item in &krate.items {
+            if let ast::ItemKind::Mod(
+                _,
+                ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _),
+            ) = item.kind
+            {
+                if item.attrs.iter().any(|a| a.has_name(sym::path)) {
+                    continue;
+                }
+
+                match item.ident.name.as_str() {
+                    "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
+                        lint.build("found module declaration for lib.rs")
+                            .note("lib.rs is the root of this crate's library target")
+                            .help("to refer to it from other targets, use the library's name as the path")
+                            .emit()
+                    }),
+                    "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
+                        lint.build("found module declaration for main.rs")
+                            .note("a binary crate cannot be used as library")
+                            .emit()
+                    }),
+                    _ => continue
+                }
+            }
+        }
+    }
+}
index 002bba4759be820ace8e656cd52a36f9fe52edca..e3b6c0159870072522a93ce2b2a1477e8dd12198 100644 (file)
@@ -45,7 +45,6 @@
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{BytePos, Span};
 use rustc_target::abi;
-use tracing::debug;
 
 use std::cell::Cell;
 use std::iter;
@@ -417,7 +416,7 @@ pub fn check_lint_name(
                     None => {
                         // 1. The tool is currently running, so this lint really doesn't exist.
                         // FIXME: should this handle tools that never register a lint, like rustfmt?
-                        tracing::debug!("lints={:?}", self.by_name.keys().collect::<Vec<_>>());
+                        debug!("lints={:?}", self.by_name.keys().collect::<Vec<_>>());
                         let tool_prefix = format!("{}::", tool_name);
                         return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
                             self.no_lint_suggestion(&complete_name)
@@ -510,7 +509,7 @@ fn check_tool_name_for_backwards_compat(
                 CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name)))
             }
             Some(other) => {
-                tracing::debug!("got renamed lint {:?}", other);
+                debug!("got renamed lint {:?}", other);
                 CheckLintNameResult::NoLint(None)
             }
         }
index cdb5b3c4284a8d37afc0dd2f6bb7b4f8c3006937..27d173ebde82a506d7c1f8493352b137b3fee634 100644 (file)
@@ -26,7 +26,6 @@
 use rustc_span::Span;
 
 use std::slice;
-use tracing::debug;
 
 macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
index c26d7824758ef06f11b40692b10ff2a2d367ea49..16b7d2cbbaea73ac489f4b4730f76c4eca98a96c 100644 (file)
@@ -12,7 +12,6 @@
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
-use tracing::debug;
 
 declare_tool_lint! {
     pub rustc::DEFAULT_HASH_TYPES,
@@ -393,8 +392,14 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
             return;
         }
 
+        let mut found_parent_with_attr = false;
         let mut found_impl = false;
-        for (_, parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
+        for (hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
+            if let Some(owner_did) = hir_id.as_owner() {
+                found_parent_with_attr = found_parent_with_attr
+                    || cx.tcx.has_attr(owner_did.to_def_id(), sym::rustc_lint_diagnostics);
+            }
+
             debug!(?parent);
             if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent &&
                 let Impl { of_trait: Some(of_trait), .. } = impl_ &&
@@ -407,7 +412,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
             }
         }
         debug!(?found_impl);
-        if !found_impl {
+        if !found_parent_with_attr && !found_impl {
             cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| {
                 lint.build(fluent::lint::diag_out_of_impl).emit();
             })
@@ -425,7 +430,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
             }
         }
         debug!(?found_diagnostic_message);
-        if !found_diagnostic_message {
+        if !found_parent_with_attr && !found_diagnostic_message {
             cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| {
                 lint.build(fluent::lint::untranslatable_diag).emit();
             })
index 5188ac633d3928b9bcf56cc63bcab58bd76ab4da..8a336844dc2fac73f02f7c0fb003ae23ac77181c 100644 (file)
@@ -29,7 +29,6 @@
 use std::any::Any;
 use std::cell::Cell;
 use std::slice;
-use tracing::debug;
 
 /// Extract the `LintStore` from the query context.
 /// This function exists because we've erased `LintStore` as `dyn Any` in the context.
diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs
new file mode 100644 (file)
index 0000000..7e885e6
--- /dev/null
@@ -0,0 +1,175 @@
+use crate::{LateContext, LateLintPass, LintContext};
+use rustc_errors::{Applicability, LintDiagnosticBuilder, MultiSpan};
+use rustc_hir as hir;
+use rustc_middle::ty;
+use rustc_span::Symbol;
+
+declare_lint! {
+    /// The `let_underscore_drop` lint checks for statements which don't bind
+    /// an expression which has a non-trivial Drop implementation to anything,
+    /// causing the expression to be dropped immediately instead of at end of
+    /// scope.
+    ///
+    /// ### Example
+    /// ```
+    /// struct SomeStruct;
+    /// impl Drop for SomeStruct {
+    ///     fn drop(&mut self) {
+    ///         println!("Dropping SomeStruct");
+    ///     }
+    /// }
+    ///
+    /// fn main() {
+    ///    #[warn(let_underscore_drop)]
+    ///     // SomeStuct is dropped immediately instead of at end of scope,
+    ///     // so "Dropping SomeStruct" is printed before "end of main".
+    ///     // The order of prints would be reversed if SomeStruct was bound to
+    ///     // a name (such as "_foo").
+    ///     let _ = SomeStruct;
+    ///     println!("end of main");
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Statements which assign an expression to an underscore causes the
+    /// expression to immediately drop instead of extending the expression's
+    /// lifetime to the end of the scope. This is usually unintended,
+    /// especially for types like `MutexGuard`, which are typically used to
+    /// lock a mutex for the duration of an entire scope.
+    ///
+    /// If you want to extend the expression's lifetime to the end of the scope,
+    /// assign an underscore-prefixed name (such as `_foo`) to the expression.
+    /// If you do actually want to drop the expression immediately, then
+    /// calling `std::mem::drop` on the expression is clearer and helps convey
+    /// intent.
+    pub LET_UNDERSCORE_DROP,
+    Allow,
+    "non-binding let on a type that implements `Drop`"
+}
+
+declare_lint! {
+    /// The `let_underscore_lock` lint checks for statements which don't bind
+    /// a mutex to anything, causing the lock to be released immediately instead
+    /// of at end of scope, which is typically incorrect.
+    ///
+    /// ### Example
+    /// ```compile_fail
+    /// use std::sync::{Arc, Mutex};
+    /// use std::thread;
+    /// let data = Arc::new(Mutex::new(0));
+    ///
+    /// thread::spawn(move || {
+    ///     // The lock is immediately released instead of at the end of the
+    ///     // scope, which is probably not intended.
+    ///     let _ = data.lock().unwrap();
+    ///     println!("doing some work");
+    ///     let mut lock = data.lock().unwrap();
+    ///     *lock += 1;
+    /// });
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Statements which assign an expression to an underscore causes the
+    /// expression to immediately drop instead of extending the expression's
+    /// lifetime to the end of the scope. This is usually unintended,
+    /// especially for types like `MutexGuard`, which are typically used to
+    /// lock a mutex for the duration of an entire scope.
+    ///
+    /// If you want to extend the expression's lifetime to the end of the scope,
+    /// assign an underscore-prefixed name (such as `_foo`) to the expression.
+    /// If you do actually want to drop the expression immediately, then
+    /// calling `std::mem::drop` on the expression is clearer and helps convey
+    /// intent.
+    pub LET_UNDERSCORE_LOCK,
+    Deny,
+    "non-binding let on a synchronization lock"
+}
+
+declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK]);
+
+const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [
+    rustc_span::sym::MutexGuard,
+    rustc_span::sym::RwLockReadGuard,
+    rustc_span::sym::RwLockWriteGuard,
+];
+
+impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
+    fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) {
+        if !matches!(local.pat.kind, hir::PatKind::Wild) {
+            return;
+        }
+        if let Some(init) = local.init {
+            let init_ty = cx.typeck_results().expr_ty(init);
+            // If the type has a trivial Drop implementation, then it doesn't
+            // matter that we drop the value immediately.
+            if !init_ty.needs_drop(cx.tcx, cx.param_env) {
+                return;
+            }
+            let is_sync_lock = match init_ty.kind() {
+                ty::Adt(adt, _) => SYNC_GUARD_SYMBOLS
+                    .iter()
+                    .any(|guard_symbol| cx.tcx.is_diagnostic_item(*guard_symbol, adt.did())),
+                _ => false,
+            };
+
+            if is_sync_lock {
+                let mut span = MultiSpan::from_spans(vec![local.pat.span, init.span]);
+                span.push_span_label(
+                    local.pat.span,
+                    "this lock is not assigned to a binding and is immediately dropped".to_string(),
+                );
+                span.push_span_label(
+                    init.span,
+                    "this binding will immediately drop the value assigned to it".to_string(),
+                );
+                cx.struct_span_lint(LET_UNDERSCORE_LOCK, span, |lint| {
+                    build_and_emit_lint(
+                        lint,
+                        local,
+                        init.span,
+                        "non-binding let on a synchronization lock",
+                    )
+                })
+            } else {
+                cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| {
+                    build_and_emit_lint(
+                        lint,
+                        local,
+                        init.span,
+                        "non-binding let on a type that implements `Drop`",
+                    );
+                })
+            }
+        }
+    }
+}
+
+fn build_and_emit_lint(
+    lint: LintDiagnosticBuilder<'_, ()>,
+    local: &hir::Local<'_>,
+    init_span: rustc_span::Span,
+    msg: &str,
+) {
+    lint.build(msg)
+        .span_suggestion_verbose(
+            local.pat.span,
+            "consider binding to an unused variable to avoid immediately dropping the value",
+            "_unused",
+            Applicability::MachineApplicable,
+        )
+        .multipart_suggestion(
+            "consider immediately dropping the value",
+            vec![
+                (local.span.until(init_span), "drop(".to_string()),
+                (init_span.shrink_to_hi(), ")".to_string()),
+            ],
+            Applicability::MachineApplicable,
+        )
+        .emit();
+}
index 89409b58f88b90af3d5762e537c33ac986f7c131..f1d8ef2e47d31cb74d2f37a3056d1af66766f1e8 100644 (file)
@@ -21,7 +21,6 @@
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use tracing::debug;
 
 use crate::errors::{
     MalformedAttribute, MalformedAttributeSub, OverruledAttribute, OverruledAttributeSub,
index f34e062fd12a9791acf87b5e571a6e2dd958c643..8cbfc82c0f0b6eb8a018c41509e97c4b4597595a 100644 (file)
@@ -33,6 +33,7 @@
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(iter_order_by)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
@@ -41,6 +42,8 @@
 extern crate rustc_middle;
 #[macro_use]
 extern crate rustc_session;
+#[macro_use]
+extern crate tracing;
 
 mod array_into_iter;
 pub mod builtin;
@@ -52,6 +55,7 @@
 pub mod hidden_unicode_codepoints;
 mod internal;
 mod late;
+mod let_underscore;
 mod levels;
 mod methods;
 mod non_ascii_idents;
@@ -83,6 +87,7 @@
 use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
 use hidden_unicode_codepoints::*;
 use internal::*;
+use let_underscore::*;
 use methods::*;
 use non_ascii_idents::*;
 use non_fmt_panic::NonPanicFmt;
@@ -130,6 +135,7 @@ macro_rules! early_lint_passes {
                 UnusedBraces: UnusedBraces,
                 UnusedImportBraces: UnusedImportBraces,
                 UnsafeCode: UnsafeCode,
+                SpecialModuleName: SpecialModuleName,
                 AnonymousParameters: AnonymousParameters,
                 EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
                 NonCamelCaseTypes: NonCamelCaseTypes,
@@ -185,6 +191,7 @@ macro_rules! late_lint_mod_passes {
                 VariantSizeDifferences: VariantSizeDifferences,
                 BoxPointers: BoxPointers,
                 PathStatements: PathStatements,
+                LetUnderscore: LetUnderscore,
                 // Depends on referenced function signatures in expressions
                 UnusedResults: UnusedResults,
                 NonUpperCaseGlobals: NonUpperCaseGlobals,
@@ -311,6 +318,8 @@ macro_rules! register_passes {
         REDUNDANT_SEMICOLONS
     );
 
+    add_lint_group!("let_underscore", LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK);
+
     add_lint_group!(
         "rust_2018_idioms",
         BARE_TRAIT_OBJECTS,
index 413f06a97a2455f8e76c7f5039ee87ea4c519c23..90c554c2e040bf248c36969efdbccb8409cca4ea 100644 (file)
@@ -243,6 +243,5 @@ fn name(&self) -> &'static str {
 }
 
 /// A lint pass boxed up as a trait object.
-pub type EarlyLintPassObject = Box<dyn EarlyLintPass + sync::Send + sync::Sync + 'static>;
-pub type LateLintPassObject =
-    Box<dyn for<'tcx> LateLintPass<'tcx> + sync::Send + sync::Sync + 'static>;
+pub type EarlyLintPassObject = Box<dyn EarlyLintPass + sync::Send + 'static>;
+pub type LateLintPassObject = Box<dyn for<'tcx> LateLintPass<'tcx> + sync::Send + 'static>;
index 484e541afc5879c477a6fefc674ba50bd642e08a..0316651998129037219b6bc7c9e2ac9d4e6adaf2 100644 (file)
@@ -19,7 +19,6 @@
 use std::cmp;
 use std::iter;
 use std::ops::ControlFlow;
-use tracing::debug;
 
 declare_lint! {
     /// The `unused_comparisons` lint detects comparisons made useless by
index 58b2f0a44161c273b62d6079aebfdd70acc55e00..1f4e5b480917d556c3245beaef3e9f82d831bd8d 100644 (file)
@@ -268,7 +268,7 @@ fn check_must_use_ty<'tcx>(
                 },
                 ty::Closure(..) => {
                     cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
-                        // FIXME(davidtwco): this isn't properly translatable becauses of the
+                        // FIXME(davidtwco): this isn't properly translatable because of the
                         // pre/post strings
                         lint.build(fluent::lint::unused_closure)
                             .set_arg("count", plural_len)
@@ -281,7 +281,7 @@ fn check_must_use_ty<'tcx>(
                 }
                 ty::Generator(..) => {
                     cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
-                        // FIXME(davidtwco): this isn't properly translatable becauses of the
+                        // FIXME(davidtwco): this isn't properly translatable because of the
                         // pre/post strings
                         lint.build(fluent::lint::unused_generator)
                             .set_arg("count", plural_len)
@@ -310,7 +310,7 @@ fn check_must_use_def(
         ) -> bool {
             if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
                 cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
-                    // FIXME(davidtwco): this isn't properly translatable becauses of the pre/post
+                    // FIXME(davidtwco): this isn't properly translatable because of the pre/post
                     // strings
                     let mut err = lint.build(fluent::lint::unused_def);
                     err.set_arg("pre", descr_pre_path);
index 2dca6acdd6d6fb562331476c6bec93a59df7f847..845563338eaa992c91b1f2178783800da41c0b5e 100644 (file)
     /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
     Warn,
-    "tranparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields",
+    "transparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #78586 <https://github.com/rust-lang/rust/issues/78586>",
     };
index 9e7cbba9511b206a85a76a6150a4af9bf483dc6c..9c6530c8a08438e8afc2eaddced942affe1df3db 100644 (file)
@@ -41,7 +41,8 @@ macro_rules! pluralize {
 /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
 /// to determine whether it should be automatically applied or if the user should be consulted
 /// before applying the suggestion.
-#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable, Serialize, Deserialize)]
+#[derive(Copy, Clone, Debug, Hash, Encodable, Decodable, Serialize, Deserialize)]
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
 pub enum Applicability {
     /// The suggestion is definitely what the user intended, or maintains the exact meaning of the code.
     /// This suggestion should be automatically applied.
index abb68f3afe5274ec06f362c2e25e506326542b78..28e092c1eb72c1c9205068aa388bc5d912dc0a8c 100644 (file)
@@ -342,10 +342,10 @@ fn main() {
     };
 
     // RISC-V GCC erroneously requires libatomic for sub-word
-    // atomic operations. FreeBSD uses Clang as its system
+    // atomic operations. Some BSD uses Clang as its system
     // compiler and provides no libatomic in its base system so
     // does not want this.
-    if !target.contains("freebsd") && target.starts_with("riscv") {
+    if target.starts_with("riscv") && !target.contains("freebsd") && !target.contains("openbsd") {
         println!("cargo:rustc-link-lib=atomic");
     }
 
index 97541e615da83a0a3129248e1c4d69186ca05e11..448a1f62f69edce1a815b7221a3ac05ccd0a26d2 100644 (file)
@@ -154,19 +154,6 @@ LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
   return Name.data();
 }
 
-extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child,
-                                                size_t *Size) {
-  StringRef Buf;
-  Expected<StringRef> BufOrErr = Child->getBuffer();
-  if (!BufOrErr) {
-    LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str());
-    return nullptr;
-  }
-  Buf = BufOrErr.get();
-  *Size = Buf.size();
-  return Buf.data();
-}
-
 extern "C" LLVMRustArchiveMemberRef
 LLVMRustArchiveMemberNew(char *Filename, char *Name,
                          LLVMRustArchiveChildRef Child) {
index a4ccfcace1923e6bc81cc18519649c75c407eb59..2a4fe48a8aca28de4c5875ace0fb3f0f06051133 100644 (file)
@@ -239,7 +239,7 @@ fn generate_structure_code_for_attr(
             }
         }
 
-        Ok(tokens.drain(..).collect())
+        Ok(tokens.into_iter().collect())
     }
 
     fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
index 666dbc23c287cb3daef7efb7ed219f4e94a172da..dce5d3cfb84ff05b87aeceb2f47148e9bb55eed1 100644 (file)
@@ -12,7 +12,7 @@
 use std::collections::HashMap;
 use std::fmt;
 use std::str::FromStr;
-use syn::{parse_quote, spanned::Spanned, Meta, MetaList, MetaNameValue, NestedMeta, Path};
+use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path};
 use synstructure::{BindingInfo, Structure, VariantInfo};
 
 /// Which kind of suggestion is being created?
@@ -28,8 +28,41 @@ enum SubdiagnosticSuggestionKind {
     Verbose,
 }
 
+impl FromStr for SubdiagnosticSuggestionKind {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "" => Ok(SubdiagnosticSuggestionKind::Normal),
+            "_short" => Ok(SubdiagnosticSuggestionKind::Short),
+            "_hidden" => Ok(SubdiagnosticSuggestionKind::Hidden),
+            "_verbose" => Ok(SubdiagnosticSuggestionKind::Verbose),
+            _ => Err(()),
+        }
+    }
+}
+
+impl SubdiagnosticSuggestionKind {
+    pub fn to_suggestion_style(&self) -> TokenStream {
+        match self {
+            SubdiagnosticSuggestionKind::Normal => {
+                quote! { rustc_errors::SuggestionStyle::ShowCode }
+            }
+            SubdiagnosticSuggestionKind::Short => {
+                quote! { rustc_errors::SuggestionStyle::HideCodeInline }
+            }
+            SubdiagnosticSuggestionKind::Hidden => {
+                quote! { rustc_errors::SuggestionStyle::HideCodeAlways }
+            }
+            SubdiagnosticSuggestionKind::Verbose => {
+                quote! { rustc_errors::SuggestionStyle::ShowAlways }
+            }
+        }
+    }
+}
+
 /// Which kind of subdiagnostic is being created from a variant?
-#[derive(Clone, Copy)]
+#[derive(Clone)]
 enum SubdiagnosticKind {
     /// `#[label(...)]`
     Label,
@@ -40,31 +73,9 @@ enum SubdiagnosticKind {
     /// `#[warning(...)]`
     Warn,
     /// `#[suggestion{,_short,_hidden,_verbose}]`
-    Suggestion(SubdiagnosticSuggestionKind),
-}
-
-impl FromStr for SubdiagnosticKind {
-    type Err = ();
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "label" => Ok(SubdiagnosticKind::Label),
-            "note" => Ok(SubdiagnosticKind::Note),
-            "help" => Ok(SubdiagnosticKind::Help),
-            "warning" => Ok(SubdiagnosticKind::Warn),
-            "suggestion" => Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal)),
-            "suggestion_short" => {
-                Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short))
-            }
-            "suggestion_hidden" => {
-                Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden))
-            }
-            "suggestion_verbose" => {
-                Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose))
-            }
-            _ => Err(()),
-        }
-    }
+    Suggestion { suggestion_kind: SubdiagnosticSuggestionKind, code: TokenStream },
+    /// `#[multipart_suggestion{,_short,_hidden,_verbose}]`
+    MultipartSuggestion { suggestion_kind: SubdiagnosticSuggestionKind },
 }
 
 impl quote::IdentFragment for SubdiagnosticKind {
@@ -74,17 +85,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             SubdiagnosticKind::Note => write!(f, "note"),
             SubdiagnosticKind::Help => write!(f, "help"),
             SubdiagnosticKind::Warn => write!(f, "warn"),
-            SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal) => {
-                write!(f, "suggestion")
-            }
-            SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short) => {
-                write!(f, "suggestion_short")
-            }
-            SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden) => {
-                write!(f, "suggestion_hidden")
-            }
-            SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose) => {
-                write!(f, "suggestion_verbose")
+            SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"),
+            SubdiagnosticKind::MultipartSuggestion { .. } => {
+                write!(f, "multipart_suggestion_with_style")
             }
         }
     }
@@ -148,11 +151,9 @@ pub(crate) fn into_tokens(self) -> TokenStream {
                     variant,
                     span,
                     fields: fields_map,
-                    kind: None,
-                    slug: None,
-                    code: None,
                     span_field: None,
                     applicability: None,
+                    has_suggestion_parts: false,
                 };
                 builder.into_tokens().unwrap_or_else(|v| v.to_compile_error())
             });
@@ -193,21 +194,15 @@ struct SessionSubdiagnosticDeriveBuilder<'a> {
     /// derive builder.
     fields: HashMap<String, TokenStream>,
 
-    /// Subdiagnostic kind of the type/variant.
-    kind: Option<(SubdiagnosticKind, proc_macro::Span)>,
-
-    /// Slug of the subdiagnostic - corresponds to the Fluent identifier for the message - from the
-    /// `#[kind(slug)]` attribute on the type or variant.
-    slug: Option<(Path, proc_macro::Span)>,
-    /// If a suggestion, the code to suggest as a replacement - from the `#[kind(code = "...")]`
-    /// attribute on the type or variant.
-    code: Option<(TokenStream, proc_macro::Span)>,
-
     /// Identifier for the binding to the `#[primary_span]` field.
     span_field: Option<(proc_macro2::Ident, proc_macro::Span)>,
     /// If a suggestion, the identifier for the binding to the `#[applicability]` field or a
     /// `rustc_errors::Applicability::*` variant directly.
     applicability: Option<(TokenStream, proc_macro::Span)>,
+
+    /// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error
+    /// during finalization if still `false`.
+    has_suggestion_parts: bool,
 }
 
 impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> {
@@ -216,8 +211,40 @@ fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
     }
 }
 
+/// Provides frequently-needed information about the diagnostic kinds being derived for this type.
+#[derive(Clone, Copy, Debug)]
+struct KindsStatistics {
+    has_multipart_suggestion: bool,
+    all_multipart_suggestions: bool,
+    has_normal_suggestion: bool,
+}
+
+impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
+    fn from_iter<T: IntoIterator<Item = &'a SubdiagnosticKind>>(kinds: T) -> Self {
+        let mut ret = Self {
+            has_multipart_suggestion: false,
+            all_multipart_suggestions: true,
+            has_normal_suggestion: false,
+        };
+        for kind in kinds {
+            if let SubdiagnosticKind::MultipartSuggestion { .. } = kind {
+                ret.has_multipart_suggestion = true;
+            } else {
+                ret.all_multipart_suggestions = false;
+            }
+
+            if let SubdiagnosticKind::Suggestion { .. } = kind {
+                ret.has_normal_suggestion = true;
+            }
+        }
+        ret
+    }
+}
+
 impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
-    fn identify_kind(&mut self) -> Result<(), DiagnosticDeriveError> {
+    fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
+        let mut kind_slugs = vec![];
+
         for attr in self.variant.ast().attrs {
             let span = attr.span().unwrap();
 
@@ -225,116 +252,121 @@ fn identify_kind(&mut self) -> Result<(), DiagnosticDeriveError> {
             let name = name.as_str();
 
             let meta = attr.parse_meta()?;
-            let kind = match meta {
-                Meta::List(MetaList { ref nested, .. }) => {
-                    let mut nested_iter = nested.into_iter();
-                    if let Some(nested_attr) = nested_iter.next() {
-                        match nested_attr {
-                            NestedMeta::Meta(Meta::Path(path)) => {
-                                self.slug.set_once((path.clone(), span));
-                            }
-                            NestedMeta::Meta(meta @ Meta::NameValue(_))
-                                if matches!(
-                                    meta.path().segments.last().unwrap().ident.to_string().as_str(),
-                                    "code" | "applicability"
-                                ) =>
-                            {
-                                // don't error for valid follow-up attributes
-                            }
-                            nested_attr => {
-                                throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                                    diag.help(
-                                        "first argument of the attribute should be the diagnostic \
-                                         slug",
-                                    )
-                                })
-                            }
-                        };
-                    }
+            let Meta::List(MetaList { ref nested, .. }) = meta else {
+                throw_invalid_attr!(attr, &meta);
+            };
 
-                    for nested_attr in nested_iter {
-                        let meta = match nested_attr {
-                            NestedMeta::Meta(ref meta) => meta,
-                            _ => throw_invalid_nested_attr!(attr, &nested_attr),
-                        };
-
-                        let span = meta.span().unwrap();
-                        let nested_name = meta.path().segments.last().unwrap().ident.to_string();
-                        let nested_name = nested_name.as_str();
-
-                        match meta {
-                            Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
-                                match nested_name {
-                                    "code" => {
-                                        let formatted_str = self.build_format(&s.value(), s.span());
-                                        self.code.set_once((formatted_str, span));
-                                    }
-                                    "applicability" => {
-                                        let value = match Applicability::from_str(&s.value()) {
-                                            Ok(v) => v,
-                                            Err(()) => {
-                                                span_err(span, "invalid applicability").emit();
-                                                Applicability::Unspecified
-                                            }
-                                        };
-                                        self.applicability.set_once((quote! { #value }, span));
-                                    }
-                                    _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                                        diag.help(
-                                            "only `code` and `applicability` are valid nested \
-                                             attributes",
-                                        )
-                                    }),
-                                }
-                            }
-                            _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                                if matches!(meta, Meta::Path(_)) {
-                                    diag.help(
-                                        "a diagnostic slug must be the first argument to the \
-                                         attribute",
-                                    )
-                                } else {
-                                    diag
-                                }
-                            }),
-                        }
+            let mut kind = match name {
+                "label" => SubdiagnosticKind::Label,
+                "note" => SubdiagnosticKind::Note,
+                "help" => SubdiagnosticKind::Help,
+                "warning" => SubdiagnosticKind::Warn,
+                _ => {
+                    if let Some(suggestion_kind) =
+                        name.strip_prefix("suggestion").and_then(|s| s.parse().ok())
+                    {
+                        SubdiagnosticKind::Suggestion { suggestion_kind, code: TokenStream::new() }
+                    } else if let Some(suggestion_kind) =
+                        name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
+                    {
+                        SubdiagnosticKind::MultipartSuggestion { suggestion_kind }
+                    } else {
+                        throw_invalid_attr!(attr, &meta);
                     }
-
-                    let Ok(kind) = SubdiagnosticKind::from_str(name) else {
-                        throw_invalid_attr!(attr, &meta)
-                    };
-
-                    kind
                 }
-                _ => throw_invalid_attr!(attr, &meta),
             };
 
-            if matches!(
-                kind,
-                SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note
-            ) && self.code.is_some()
-            {
-                throw_span_err!(
-                    span,
-                    &format!("`code` is not a valid nested attribute of a `{}` attribute", name)
-                );
+            let mut slug = None;
+            let mut code = None;
+
+            let mut nested_iter = nested.into_iter();
+            if let Some(nested_attr) = nested_iter.next() {
+                match nested_attr {
+                    NestedMeta::Meta(Meta::Path(path)) => {
+                        slug.set_once((path.clone(), span));
+                    }
+                    NestedMeta::Meta(meta @ Meta::NameValue(_))
+                        if matches!(
+                            meta.path().segments.last().unwrap().ident.to_string().as_str(),
+                            "code" | "applicability"
+                        ) =>
+                    {
+                        // Don't error for valid follow-up attributes.
+                    }
+                    nested_attr => {
+                        throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                            diag.help(
+                                "first argument of the attribute should be the diagnostic \
+                                 slug",
+                            )
+                        })
+                    }
+                };
             }
 
-            if matches!(
-                kind,
-                SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note
-            ) && self.applicability.is_some()
-            {
-                throw_span_err!(
-                    span,
-                    &format!(
-                        "`applicability` is not a valid nested attribute of a `{}` attribute",
-                        name
-                    )
-                );
+            for nested_attr in nested_iter {
+                let meta = match nested_attr {
+                    NestedMeta::Meta(ref meta) => meta,
+                    _ => throw_invalid_nested_attr!(attr, &nested_attr),
+                };
+
+                let span = meta.span().unwrap();
+                let nested_name = meta.path().segments.last().unwrap().ident.to_string();
+                let nested_name = nested_name.as_str();
+
+                let value = match meta {
+                    Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => value,
+                    Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                        diag.help("a diagnostic slug must be the first argument to the attribute")
+                    }),
+                    _ => throw_invalid_nested_attr!(attr, &nested_attr),
+                };
+
+                match nested_name {
+                    "code" => {
+                        if matches!(kind, SubdiagnosticKind::Suggestion { .. }) {
+                            let formatted_str = self.build_format(&value.value(), value.span());
+                            code.set_once((formatted_str, span));
+                        } else {
+                            span_err(
+                                span,
+                                &format!(
+                                    "`code` is not a valid nested attribute of a `{}` attribute",
+                                    name
+                                ),
+                            )
+                            .emit();
+                        }
+                    }
+                    "applicability" => {
+                        if matches!(
+                            kind,
+                            SubdiagnosticKind::Suggestion { .. }
+                                | SubdiagnosticKind::MultipartSuggestion { .. }
+                        ) {
+                            let value =
+                                Applicability::from_str(&value.value()).unwrap_or_else(|()| {
+                                    span_err(span, "invalid applicability").emit();
+                                    Applicability::Unspecified
+                                });
+                            self.applicability.set_once((quote! { #value }, span));
+                        } else {
+                            span_err(
+                                span,
+                                &format!(
+                                    "`applicability` is not a valid nested attribute of a `{}` attribute",
+                                    name
+                                )
+                            ).emit();
+                        }
+                    }
+                    _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                        diag.help("only `code` and `applicability` are valid nested attributes")
+                    }),
+                }
             }
 
-            if self.slug.is_none() {
+            let Some((slug, _)) = slug else {
                 throw_span_err!(
                     span,
                     &format!(
@@ -342,150 +374,334 @@ fn identify_kind(&mut self) -> Result<(), DiagnosticDeriveError> {
                         name
                     )
                 );
+            };
+
+            match kind {
+                SubdiagnosticKind::Suggestion { code: ref mut code_field, .. } => {
+                    let Some((code, _)) = code else {
+                        throw_span_err!(span, "suggestion without `code = \"...\"`");
+                    };
+                    *code_field = code;
+                }
+                SubdiagnosticKind::Label
+                | SubdiagnosticKind::Note
+                | SubdiagnosticKind::Help
+                | SubdiagnosticKind::Warn
+                | SubdiagnosticKind::MultipartSuggestion { .. } => {}
             }
 
-            self.kind.set_once((kind, span));
+            kind_slugs.push((kind, slug))
         }
 
-        Ok(())
+        Ok(kind_slugs)
     }
 
-    fn generate_field_code(
+    /// Generates the code for a field with no attributes.
+    fn generate_field_set_arg(&mut self, binding: &BindingInfo<'_>) -> TokenStream {
+        let ast = binding.ast();
+        assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg");
+
+        let diag = &self.diag;
+        let ident = ast.ident.as_ref().unwrap();
+        quote! {
+            #diag.set_arg(
+                stringify!(#ident),
+                #binding
+            );
+        }
+    }
+
+    /// Generates the necessary code for all attributes on a field.
+    fn generate_field_attr_code(
         &mut self,
         binding: &BindingInfo<'_>,
-        is_suggestion: bool,
-    ) -> Result<TokenStream, DiagnosticDeriveError> {
+        kind_stats: KindsStatistics,
+    ) -> TokenStream {
         let ast = binding.ast();
+        assert!(ast.attrs.len() > 0, "field without attributes generating attr code");
 
+        // Abstract over `Vec<T>` and `Option<T>` fields using `FieldInnerTy`, which will
+        // apply the generated code on each element in the `Vec` or `Option`.
         let inner_ty = FieldInnerTy::from_type(&ast.ty);
-        let info = FieldInfo {
-            binding: binding,
-            ty: inner_ty.inner_type().unwrap_or(&ast.ty),
-            span: &ast.span(),
-        };
+        ast.attrs
+            .iter()
+            .map(|attr| {
+                let info = FieldInfo {
+                    binding,
+                    ty: inner_ty.inner_type().unwrap_or(&ast.ty),
+                    span: &ast.span(),
+                };
 
-        for attr in &ast.attrs {
-            let name = attr.path.segments.last().unwrap().ident.to_string();
-            let name = name.as_str();
-            let span = attr.span().unwrap();
+                let generated = self
+                    .generate_field_code_inner(kind_stats, attr, info)
+                    .unwrap_or_else(|v| v.to_compile_error());
 
-            let meta = attr.parse_meta()?;
-            match meta {
-                Meta::Path(_) => match name {
-                    "primary_span" => {
-                        report_error_if_not_applied_to_span(attr, &info)?;
-                        self.span_field.set_once((binding.binding.clone(), span));
-                        return Ok(quote! {});
-                    }
-                    "applicability" if is_suggestion => {
-                        report_error_if_not_applied_to_applicability(attr, &info)?;
-                        let binding = binding.binding.clone();
-                        self.applicability.set_once((quote! { #binding }, span));
-                        return Ok(quote! {});
-                    }
-                    "applicability" => {
-                        span_err(span, "`#[applicability]` is only valid on suggestions").emit();
-                        return Ok(quote! {});
-                    }
-                    "skip_arg" => {
-                        return Ok(quote! {});
-                    }
-                    _ => throw_invalid_attr!(attr, &meta, |diag| {
+                inner_ty.with(binding, generated)
+            })
+            .collect()
+    }
+
+    fn generate_field_code_inner(
+        &mut self,
+        kind_stats: KindsStatistics,
+        attr: &Attribute,
+        info: FieldInfo<'_>,
+    ) -> Result<TokenStream, DiagnosticDeriveError> {
+        let meta = attr.parse_meta()?;
+        match meta {
+            Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path),
+            Meta::List(list @ MetaList { .. }) => {
+                self.generate_field_code_inner_list(kind_stats, attr, info, list)
+            }
+            _ => throw_invalid_attr!(attr, &meta),
+        }
+    }
+
+    /// Generates the code for a `[Meta::Path]`-like attribute on a field (e.g. `#[primary_span]`).
+    fn generate_field_code_inner_path(
+        &mut self,
+        kind_stats: KindsStatistics,
+        attr: &Attribute,
+        info: FieldInfo<'_>,
+        path: Path,
+    ) -> Result<TokenStream, DiagnosticDeriveError> {
+        let span = attr.span().unwrap();
+        let ident = &path.segments.last().unwrap().ident;
+        let name = ident.to_string();
+        let name = name.as_str();
+
+        match name {
+            "skip_arg" => Ok(quote! {}),
+            "primary_span" => {
+                if kind_stats.has_multipart_suggestion {
+                    throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
                         diag.help(
-                            "only `primary_span`, `applicability` and `skip_arg` are valid field \
-                             attributes",
+                            "multipart suggestions use one or more `#[suggestion_part]`s rather \
+                            than one `#[primary_span]`",
                         )
-                    }),
-                },
-                _ => throw_invalid_attr!(attr, &meta),
+                    })
+                }
+
+                report_error_if_not_applied_to_span(attr, &info)?;
+
+                let binding = info.binding.binding.clone();
+                self.span_field.set_once((binding, span));
+
+                Ok(quote! {})
+            }
+            "suggestion_part" => {
+                self.has_suggestion_parts = true;
+
+                if kind_stats.has_multipart_suggestion {
+                    span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
+                        .emit();
+                    Ok(quote! {})
+                } else {
+                    throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
+                        diag.help(
+                                "`#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead",
+                            )
+                    });
+                }
+            }
+            "applicability" => {
+                if kind_stats.has_multipart_suggestion || kind_stats.has_normal_suggestion {
+                    report_error_if_not_applied_to_applicability(attr, &info)?;
+
+                    let binding = info.binding.binding.clone();
+                    self.applicability.set_once((quote! { #binding }, span));
+                } else {
+                    span_err(span, "`#[applicability]` is only valid on suggestions").emit();
+                }
+
+                Ok(quote! {})
             }
+            _ => throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
+                let mut span_attrs = vec![];
+                if kind_stats.has_multipart_suggestion {
+                    span_attrs.push("suggestion_part");
+                }
+                if !kind_stats.all_multipart_suggestions {
+                    span_attrs.push("primary_span")
+                }
+                diag.help(format!(
+                    "only `{}`, `applicability` and `skip_arg` are valid field attributes",
+                    span_attrs.join(", ")
+                ))
+            }),
         }
+    }
 
-        let ident = ast.ident.as_ref().unwrap();
+    /// Generates the code for a `[Meta::List]`-like attribute on a field (e.g.
+    /// `#[suggestion_part(code = "...")]`).
+    fn generate_field_code_inner_list(
+        &mut self,
+        kind_stats: KindsStatistics,
+        attr: &Attribute,
+        info: FieldInfo<'_>,
+        list: MetaList,
+    ) -> Result<TokenStream, DiagnosticDeriveError> {
+        let span = attr.span().unwrap();
+        let ident = &list.path.segments.last().unwrap().ident;
+        let name = ident.to_string();
+        let name = name.as_str();
+
+        match name {
+            "suggestion_part" => {
+                if !kind_stats.has_multipart_suggestion {
+                    throw_invalid_attr!(attr, &Meta::List(list), |diag| {
+                        diag.help(
+                            "`#[suggestion_part(...)]` is only valid in multipart suggestions",
+                        )
+                    })
+                }
 
-        let diag = &self.diag;
-        let generated = quote! {
-            #diag.set_arg(
-                stringify!(#ident),
-                #binding
-            );
-        };
+                self.has_suggestion_parts = true;
+
+                report_error_if_not_applied_to_span(attr, &info)?;
+
+                let mut code = None;
+                for nested_attr in list.nested.iter() {
+                    let NestedMeta::Meta(ref meta) = nested_attr else {
+                        throw_invalid_nested_attr!(attr, &nested_attr);
+                    };
+
+                    let span = meta.span().unwrap();
+                    let nested_name = meta.path().segments.last().unwrap().ident.to_string();
+                    let nested_name = nested_name.as_str();
+
+                    let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) = meta else {
+                        throw_invalid_nested_attr!(attr, &nested_attr);
+                    };
+
+                    match nested_name {
+                        "code" => {
+                            let formatted_str = self.build_format(&value.value(), value.span());
+                            code.set_once((formatted_str, span));
+                        }
+                        _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                            diag.help("`code` is the only valid nested attribute")
+                        }),
+                    }
+                }
 
-        Ok(inner_ty.with(binding, generated))
+                let Some((code, _)) = code else {
+                    span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
+                        .emit();
+                    return Ok(quote! {});
+                };
+                let binding = info.binding;
+
+                Ok(quote! { suggestions.push((#binding, #code)); })
+            }
+            _ => throw_invalid_attr!(attr, &Meta::List(list), |diag| {
+                let mut span_attrs = vec![];
+                if kind_stats.has_multipart_suggestion {
+                    span_attrs.push("suggestion_part");
+                }
+                if !kind_stats.all_multipart_suggestions {
+                    span_attrs.push("primary_span")
+                }
+                diag.help(format!(
+                    "only `{}`, `applicability` and `skip_arg` are valid field attributes",
+                    span_attrs.join(", ")
+                ))
+            }),
+        }
     }
 
-    fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
-        self.identify_kind()?;
-        let Some(kind) = self.kind.map(|(kind, _)| kind) else {
+    pub fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
+        let kind_slugs = self.identify_kind()?;
+        if kind_slugs.is_empty() {
             throw_span_err!(
                 self.variant.ast().ident.span().unwrap(),
                 "subdiagnostic kind not specified"
             );
         };
 
-        let is_suggestion = matches!(kind, SubdiagnosticKind::Suggestion(_));
+        let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect();
 
-        let mut args = TokenStream::new();
-        for binding in self.variant.bindings() {
-            let arg = self
-                .generate_field_code(binding, is_suggestion)
-                .unwrap_or_else(|v| v.to_compile_error());
-            args.extend(arg);
-        }
-
-        // Missing slug errors will already have been reported.
-        let slug = self
-            .slug
-            .as_ref()
-            .map(|(slug, _)| slug.clone())
-            .unwrap_or_else(|| parse_quote! { you::need::to::specify::a::slug });
-        let code = match self.code.as_ref() {
-            Some((code, _)) => Some(quote! { #code }),
-            None if is_suggestion => {
-                span_err(self.span, "suggestion without `code = \"...\"`").emit();
-                Some(quote! { /* macro error */ "..." })
-            }
-            None => None,
+        let init = if kind_stats.has_multipart_suggestion {
+            quote! { let mut suggestions = Vec::new(); }
+        } else {
+            quote! {}
         };
 
+        let attr_args: TokenStream = self
+            .variant
+            .bindings()
+            .iter()
+            .filter(|binding| !binding.ast().attrs.is_empty())
+            .map(|binding| self.generate_field_attr_code(binding, kind_stats))
+            .collect();
+
         let span_field = self.span_field.as_ref().map(|(span, _)| span);
-        let applicability = match self.applicability.clone() {
-            Some((applicability, _)) => Some(applicability),
-            None if is_suggestion => {
-                span_err(self.span, "suggestion without `applicability`").emit();
-                Some(quote! { rustc_errors::Applicability::Unspecified })
-            }
-            None => None,
-        };
+        let applicability = self.applicability.take().map_or_else(
+            || quote! { rustc_errors::Applicability::Unspecified },
+            |(applicability, _)| applicability,
+        );
 
         let diag = &self.diag;
-        let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
-        let message = quote! { rustc_errors::fluent::#slug };
-        let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) {
-            if let Some(span) = span_field {
-                quote! { #diag.#name(#span, #message, #code, #applicability); }
-            } else {
-                span_err(self.span, "suggestion without `#[primary_span]` field").emit();
-                quote! { unreachable!(); }
-            }
-        } else if matches!(kind, SubdiagnosticKind::Label) {
-            if let Some(span) = span_field {
-                quote! { #diag.#name(#span, #message); }
-            } else {
-                span_err(self.span, "label without `#[primary_span]` field").emit();
-                quote! { unreachable!(); }
-            }
-        } else {
-            if let Some(span) = span_field {
-                quote! { #diag.#name(#span, #message); }
-            } else {
-                quote! { #diag.#name(#message); }
-            }
-        };
+        let mut calls = TokenStream::new();
+        for (kind, slug) in kind_slugs {
+            let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
+            let message = quote! { rustc_errors::fluent::#slug };
+            let call = match kind {
+                SubdiagnosticKind::Suggestion { suggestion_kind, code } => {
+                    if let Some(span) = span_field {
+                        let style = suggestion_kind.to_suggestion_style();
+
+                        quote! { #diag.#name(#span, #message, #code, #applicability, #style); }
+                    } else {
+                        span_err(self.span, "suggestion without `#[primary_span]` field").emit();
+                        quote! { unreachable!(); }
+                    }
+                }
+                SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => {
+                    if !self.has_suggestion_parts {
+                        span_err(
+                            self.span,
+                            "multipart suggestion without any `#[suggestion_part(...)]` fields",
+                        )
+                        .emit();
+                    }
+
+                    let style = suggestion_kind.to_suggestion_style();
+
+                    quote! { #diag.#name(#message, suggestions, #applicability, #style); }
+                }
+                SubdiagnosticKind::Label => {
+                    if let Some(span) = span_field {
+                        quote! { #diag.#name(#span, #message); }
+                    } else {
+                        span_err(self.span, "label without `#[primary_span]` field").emit();
+                        quote! { unreachable!(); }
+                    }
+                }
+                _ => {
+                    if let Some(span) = span_field {
+                        quote! { #diag.#name(#span, #message); }
+                    } else {
+                        quote! { #diag.#name(#message); }
+                    }
+                }
+            };
+            calls.extend(call);
+        }
+
+        let plain_args: TokenStream = self
+            .variant
+            .bindings()
+            .iter()
+            .filter(|binding| binding.ast().attrs.is_empty())
+            .map(|binding| self.generate_field_set_arg(binding))
+            .collect();
 
         Ok(quote! {
-            #call
-            #args
+            #init
+            #attr_args
+            #calls
+            #plain_args
         })
     }
 }
index 8faac8ef36a53a216a4787d7ecf58de0b252211f..20ee5dfc7279844b171ab30f71fd380fc101b0ed 100644 (file)
@@ -171,8 +171,13 @@ pub fn fluent_messages(input: TokenStream) -> TokenStream {
         suggestion_short,
         suggestion_hidden,
         suggestion_verbose,
+        multipart_suggestion,
+        multipart_suggestion_short,
+        multipart_suggestion_hidden,
+        multipart_suggestion_verbose,
         // field attributes
         skip_arg,
         primary_span,
+        suggestion_part,
         applicability)] => diagnostics::session_subdiagnostic_derive
 );
index 708d0b1fd8a301818b8b667233975772cfffe0ea..cfcceecbef40ee911e04d62d958d4d31076b4169 100644 (file)
@@ -1,5 +1,9 @@
 //! Validates all used crates and extern libraries and loads their metadata
 
+use crate::errors::{
+    ConflictingGlobalAlloc, CrateNotPanicRuntime, GlobalAllocRequired, NoMultipleGlobalAlloc,
+    NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime, ProfilerBuiltinsNeedsCore,
+};
 use crate::locator::{CrateError, CrateLocator, CratePaths};
 use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
 
@@ -29,7 +33,6 @@
 use std::ops::Fn;
 use std::path::Path;
 use std::{cmp, env};
-use tracing::{debug, info};
 
 #[derive(Clone)]
 pub struct CStore {
@@ -263,7 +266,7 @@ pub fn into_cstore(self) -> CStore {
     fn existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Option<CrateNum> {
         for (cnum, data) in self.cstore.iter_crate_data() {
             if data.name() != name {
-                tracing::trace!("{} did not match {}", data.name(), name);
+                trace!("{} did not match {}", data.name(), name);
                 continue;
             }
 
@@ -746,15 +749,10 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
         // Sanity check the loaded crate to ensure it is indeed a panic runtime
         // and the panic strategy is indeed what we thought it was.
         if !data.is_panic_runtime() {
-            self.sess.err(&format!("the crate `{}` is not a panic runtime", name));
+            self.sess.emit_err(CrateNotPanicRuntime { crate_name: name });
         }
         if data.required_panic_strategy() != Some(desired_strategy) {
-            self.sess.err(&format!(
-                "the crate `{}` does not have the panic \
-                                    strategy `{}`",
-                name,
-                desired_strategy.desc()
-            ));
+            self.sess.emit_err(NoPanicStrategy { crate_name: name, strategy: desired_strategy });
         }
 
         self.cstore.injected_panic_runtime = Some(cnum);
@@ -774,10 +772,7 @@ fn inject_profiler_runtime(&mut self, krate: &ast::Crate) {
 
         let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
         if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) {
-            self.sess.err(
-                "`profiler_builtins` crate (required by compiler options) \
-                        is not compatible with crate attribute `#![no_core]`",
-            );
+            self.sess.emit_err(ProfilerBuiltinsNeedsCore);
         }
 
         let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; };
@@ -785,18 +780,14 @@ fn inject_profiler_runtime(&mut self, krate: &ast::Crate) {
 
         // Sanity check the loaded crate to ensure it is indeed a profiler runtime
         if !data.is_profiler_runtime() {
-            self.sess.err(&format!("the crate `{}` is not a profiler runtime", name));
+            self.sess.emit_err(NotProfilerRuntime { crate_name: name });
         }
     }
 
     fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
         self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) {
             [span1, span2, ..] => {
-                self.sess
-                    .struct_span_err(*span2, "cannot define multiple global allocators")
-                    .span_label(*span2, "cannot define a new global allocator")
-                    .span_label(*span1, "previous global allocator defined here")
-                    .emit();
+                self.sess.emit_err(NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
                 true
             }
             spans => !spans.is_empty(),
@@ -832,11 +823,10 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
             if data.has_global_allocator() {
                 match global_allocator {
                     Some(other_crate) => {
-                        self.sess.err(&format!(
-                        "the `#[global_allocator]` in {} conflicts with global allocator in: {}",
-                        other_crate,
-                        data.name()
-                    ));
+                        self.sess.emit_err(ConflictingGlobalAlloc {
+                            crate_name: data.name(),
+                            other_crate_name: other_crate,
+                        });
                     }
                     None => global_allocator = Some(data.name()),
                 }
@@ -855,10 +845,7 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
         if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
             && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
         {
-            self.sess.err(
-                "no global memory allocator found but one is required; link to std or add \
-                 `#[global_allocator]` to a static item that implements the GlobalAlloc trait",
-            );
+            self.sess.emit_err(GlobalAllocRequired);
         }
         self.cstore.allocator_kind = Some(AllocatorKind::Default);
     }
@@ -882,14 +869,11 @@ fn inject_dependency_if(
         for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) {
             let data = self.cstore.get_crate_data(dep);
             if needs_dep(&data) {
-                self.sess.err(&format!(
-                    "the crate `{}` cannot depend \
-                                        on a crate that needs {}, but \
-                                        it depends on `{}`",
-                    self.cstore.get_crate_data(krate).name(),
-                    what,
-                    data.name()
-                ));
+                self.sess.emit_err(NoTransitiveNeedsDep {
+                    crate_name: self.cstore.get_crate_data(krate).name(),
+                    needs_crate_name: what,
+                    deps_crate_name: data.name(),
+                });
             }
         }
 
index b765c34f8e364d2d4ec15846bd5d4daa5718a9a9..6112ec9e4e948b6b8d01068f57336c7f83d84067 100644 (file)
 //! than finding a number of solutions (there are normally quite a few).
 
 use crate::creader::CStore;
+use crate::errors::{
+    BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired,
+    RequiredPanicStrategy, RlibRequired, TwoPanicRuntimes,
+};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::CrateNum;
@@ -136,11 +140,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
                 if src.rlib.is_some() {
                     continue;
                 }
-                sess.err(&format!(
-                    "crate `{}` required to be available in rlib format, \
-                                   but was not found in this form",
-                    tcx.crate_name(cnum)
-                ));
+                sess.emit_err(RlibRequired { crate_name: tcx.crate_name(cnum) });
             }
             return Vec::new();
         }
@@ -158,11 +158,11 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
         let name = tcx.crate_name(cnum);
         let src = tcx.used_crate_source(cnum);
         if src.dylib.is_some() {
-            tracing::info!("adding dylib: {}", name);
+            info!("adding dylib: {}", name);
             add_library(tcx, cnum, RequireDynamic, &mut formats);
             let deps = tcx.dylib_dependency_formats(cnum);
             for &(depnum, style) in deps.iter() {
-                tracing::info!("adding {:?}: {}", style, tcx.crate_name(depnum));
+                info!("adding {:?}: {}", style, tcx.crate_name(depnum));
                 add_library(tcx, depnum, style, &mut formats);
             }
         }
@@ -190,7 +190,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
             && tcx.dep_kind(cnum) == CrateDepKind::Explicit
         {
             assert!(src.rlib.is_some() || src.rmeta.is_some());
-            tracing::info!("adding staticlib: {}", tcx.crate_name(cnum));
+            info!("adding staticlib: {}", tcx.crate_name(cnum));
             add_library(tcx, cnum, RequireStatic, &mut formats);
             ret[cnum.as_usize() - 1] = Linkage::Static;
         }
@@ -224,12 +224,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
                     Linkage::Static => "rlib",
                     _ => "dylib",
                 };
-                sess.err(&format!(
-                    "crate `{}` required to be available in {} format, \
-                                   but was not found in this form",
-                    tcx.crate_name(cnum),
-                    kind
-                ));
+                sess.emit_err(LibRequired { crate_name: tcx.crate_name(cnum), kind: kind });
             }
         }
     }
@@ -253,17 +248,7 @@ fn add_library(
             // This error is probably a little obscure, but I imagine that it
             // can be refined over time.
             if link2 != link || link == RequireStatic {
-                tcx.sess
-                    .struct_err(&format!(
-                        "cannot satisfy dependencies so `{}` only \
-                                              shows up once",
-                        tcx.crate_name(cnum)
-                    ))
-                    .help(
-                        "having upstream crates all available in one format \
-                           will likely make this go away",
-                    )
-                    .emit();
+                tcx.sess.emit_err(CrateDepMultiple { crate_name: tcx.crate_name(cnum) });
             }
         }
         None => {
@@ -360,11 +345,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
             if let Some((prev, _)) = panic_runtime {
                 let prev_name = tcx.crate_name(prev);
                 let cur_name = tcx.crate_name(cnum);
-                sess.err(&format!(
-                    "cannot link together two \
-                                   panic runtimes: {} and {}",
-                    prev_name, cur_name
-                ));
+                sess.emit_err(TwoPanicRuntimes { prev_name, cur_name });
             }
             panic_runtime = Some((
                 cnum,
@@ -384,13 +365,10 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
         // First up, validate that our selected panic runtime is indeed exactly
         // our same strategy.
         if found_strategy != desired_strategy {
-            sess.err(&format!(
-                "the linked panic runtime `{}` is \
-                               not compiled with this crate's \
-                               panic strategy `{}`",
-                tcx.crate_name(runtime_cnum),
-                desired_strategy.desc()
-            ));
+            sess.emit_err(BadPanicStrategy {
+                runtime: tcx.crate_name(runtime_cnum),
+                strategy: desired_strategy,
+            });
         }
 
         // Next up, verify that all other crates are compatible with this panic
@@ -407,28 +385,19 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
             }
 
             if let Some(found_strategy) = tcx.required_panic_strategy(cnum) && desired_strategy != found_strategy {
-                sess.err(&format!(
-                    "the crate `{}` requires \
-                               panic strategy `{}` which is \
-                               incompatible with this crate's \
-                               strategy of `{}`",
-                    tcx.crate_name(cnum),
-                    found_strategy.desc(),
-                    desired_strategy.desc()
-                ));
+                sess.emit_err(RequiredPanicStrategy {
+                    crate_name: tcx.crate_name(cnum),
+                    found_strategy,
+                    desired_strategy});
             }
 
             let found_drop_strategy = tcx.panic_in_drop_strategy(cnum);
             if tcx.sess.opts.unstable_opts.panic_in_drop != found_drop_strategy {
-                sess.err(&format!(
-                    "the crate `{}` is compiled with the \
-                               panic-in-drop strategy `{}` which is \
-                               incompatible with this crate's \
-                               strategy of `{}`",
-                    tcx.crate_name(cnum),
-                    found_drop_strategy.desc(),
-                    tcx.sess.opts.unstable_opts.panic_in_drop.desc()
-                ));
+                sess.emit_err(IncompatiblePanicInDropStrategy {
+                    crate_name: tcx.crate_name(cnum),
+                    found_strategy: found_drop_strategy,
+                    desired_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
+                });
             }
         }
     }
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
new file mode 100644 (file)
index 0000000..18d0248
--- /dev/null
@@ -0,0 +1,672 @@
+use std::{
+    io::Error,
+    path::{Path, PathBuf},
+};
+
+use rustc_errors::{error_code, ErrorGuaranteed};
+use rustc_macros::SessionDiagnostic;
+use rustc_session::{config, SessionDiagnostic};
+use rustc_span::{sym, Span, Symbol};
+use rustc_target::spec::{PanicStrategy, TargetTriple};
+
+use crate::locator::CrateFlavor;
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::rlib_required)]
+pub struct RlibRequired {
+    pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::lib_required)]
+pub struct LibRequired<'a> {
+    pub crate_name: Symbol,
+    pub kind: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::crate_dep_multiple)]
+#[help]
+pub struct CrateDepMultiple {
+    pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::two_panic_runtimes)]
+pub struct TwoPanicRuntimes {
+    pub prev_name: Symbol,
+    pub cur_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::bad_panic_strategy)]
+pub struct BadPanicStrategy {
+    pub runtime: Symbol,
+    pub strategy: PanicStrategy,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::required_panic_strategy)]
+pub struct RequiredPanicStrategy {
+    pub crate_name: Symbol,
+    pub found_strategy: PanicStrategy,
+    pub desired_strategy: PanicStrategy,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::incompatible_panic_in_drop_strategy)]
+pub struct IncompatiblePanicInDropStrategy {
+    pub crate_name: Symbol,
+    pub found_strategy: PanicStrategy,
+    pub desired_strategy: PanicStrategy,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_names_in_link)]
+pub struct MultipleNamesInLink {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_kinds_in_link)]
+pub struct MultipleKindsInLink {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_name_form)]
+pub struct LinkNameForm {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_kind_form)]
+pub struct LinkKindForm {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_modifiers_form)]
+pub struct LinkModifiersForm {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_cfg_form)]
+pub struct LinkCfgForm {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::wasm_import_form)]
+pub struct WasmImportForm {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::empty_link_name, code = "E0454")]
+pub struct EmptyLinkName {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_framework_apple, code = "E0455")]
+pub struct LinkFrameworkApple {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::framework_only_windows, code = "E0455")]
+pub struct FrameworkOnlyWindows {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::unknown_link_kind, code = "E0458")]
+pub struct UnknownLinkKind<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub kind: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_link_modifiers)]
+pub struct MultipleLinkModifiers {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_cfgs)]
+pub struct MultipleCfgs {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_cfg_single_predicate)]
+pub struct LinkCfgSinglePredicate {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_wasm_import)]
+pub struct MultipleWasmImport {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::unexpected_link_arg)]
+pub struct UnexpectedLinkArg {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::invalid_link_modifier)]
+pub struct InvalidLinkModifier {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_modifiers)]
+pub struct MultipleModifiers<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub modifier: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::bundle_needs_static)]
+pub struct BundleNeedsStatic {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::whole_archive_needs_static)]
+pub struct WholeArchiveNeedsStatic {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::as_needed_compatibility)]
+pub struct AsNeededCompatibility {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::unknown_link_modifier)]
+pub struct UnknownLinkModifier<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub modifier: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::incompatible_wasm_link)]
+pub struct IncompatibleWasmLink {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_requires_name, code = "E0459")]
+pub struct LinkRequiresName {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::raw_dylib_no_nul)]
+pub struct RawDylibNoNul {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::link_ordinal_raw_dylib)]
+pub struct LinkOrdinalRawDylib {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::lib_framework_apple)]
+pub struct LibFrameworkApple;
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::empty_renaming_target)]
+pub struct EmptyRenamingTarget<'a> {
+    pub lib_name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::renaming_no_link)]
+pub struct RenamingNoLink<'a> {
+    pub lib_name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_renamings)]
+pub struct MultipleRenamings<'a> {
+    pub lib_name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::no_link_mod_override)]
+pub struct NoLinkModOverride {
+    #[primary_span]
+    pub span: Option<Span>,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::unsupported_abi_i686)]
+pub struct UnsupportedAbiI686 {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::unsupported_abi)]
+pub struct UnsupportedAbi {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::fail_create_file_encoder)]
+pub struct FailCreateFileEncoder {
+    pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::fail_seek_file)]
+pub struct FailSeekFile {
+    pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::fail_write_file)]
+pub struct FailWriteFile {
+    pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::crate_not_panic_runtime)]
+pub struct CrateNotPanicRuntime {
+    pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::no_panic_strategy)]
+pub struct NoPanicStrategy {
+    pub crate_name: Symbol,
+    pub strategy: PanicStrategy,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::profiler_builtins_needs_core)]
+pub struct ProfilerBuiltinsNeedsCore;
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::not_profiler_runtime)]
+pub struct NotProfilerRuntime {
+    pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::no_multiple_global_alloc)]
+pub struct NoMultipleGlobalAlloc {
+    #[primary_span]
+    #[label]
+    pub span2: Span,
+    #[label(metadata::prev_global_alloc)]
+    pub span1: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::conflicting_global_alloc)]
+pub struct ConflictingGlobalAlloc {
+    pub crate_name: Symbol,
+    pub other_crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::global_alloc_required)]
+pub struct GlobalAllocRequired;
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::no_transitive_needs_dep)]
+pub struct NoTransitiveNeedsDep<'a> {
+    pub crate_name: Symbol,
+    pub needs_crate_name: &'a str,
+    pub deps_crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::failed_write_error)]
+pub struct FailedWriteError {
+    pub filename: PathBuf,
+    pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::failed_create_tempdir)]
+pub struct FailedCreateTempdir {
+    pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::failed_create_file)]
+pub struct FailedCreateFile<'a> {
+    pub filename: &'a Path,
+    pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::failed_create_encoded_metadata)]
+pub struct FailedCreateEncodedMetadata {
+    pub err: Error,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::non_ascii_name)]
+pub struct NonAsciiName {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::extern_location_not_exist)]
+pub struct ExternLocationNotExist<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name: Symbol,
+    pub location: &'a Path,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::extern_location_not_file)]
+pub struct ExternLocationNotFile<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name: Symbol,
+    pub location: &'a Path,
+}
+
+pub(crate) struct MultipleCandidates {
+    pub span: Span,
+    pub flavor: CrateFlavor,
+    pub crate_name: Symbol,
+    pub candidates: Vec<PathBuf>,
+}
+
+impl SessionDiagnostic<'_> for MultipleCandidates {
+    fn into_diagnostic(
+        self,
+        sess: &'_ rustc_session::parse::ParseSess,
+    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = sess.struct_err(rustc_errors::fluent::metadata::multiple_candidates);
+        diag.set_arg("crate_name", self.crate_name);
+        diag.set_arg("flavor", self.flavor);
+        diag.code(error_code!(E0465));
+        diag.set_span(self.span);
+        for (i, candidate) in self.candidates.iter().enumerate() {
+            diag.span_note(self.span, &format!("candidate #{}: {}", i + 1, candidate.display()));
+        }
+        diag
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_matching_crates, code = "E0464")]
+#[note]
+pub struct MultipleMatchingCrates {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name: Symbol,
+    pub candidates: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::symbol_conflicts_current, code = "E0519")]
+pub struct SymbolConflictsCurrent {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::symbol_conflicts_others, code = "E0523")]
+pub struct SymbolConflictsOthers {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::stable_crate_id_collision)]
+pub struct StableCrateIdCollision {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name0: Symbol,
+    pub crate_name1: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::dl_error)]
+pub struct DlError {
+    #[primary_span]
+    pub span: Span,
+    pub err: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::newer_crate_version, code = "E0460")]
+#[note]
+#[note(metadata::found_crate_versions)]
+pub struct NewerCrateVersion {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name: Symbol,
+    pub add_info: String,
+    pub found_crates: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::no_crate_with_triple, code = "E0461")]
+#[note(metadata::found_crate_versions)]
+pub struct NoCrateWithTriple<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name: Symbol,
+    pub locator_triple: &'a str,
+    pub add_info: String,
+    pub found_crates: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::found_staticlib, code = "E0462")]
+#[note(metadata::found_crate_versions)]
+#[help]
+pub struct FoundStaticlib {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name: Symbol,
+    pub add_info: String,
+    pub found_crates: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::incompatible_rustc, code = "E0514")]
+#[note(metadata::found_crate_versions)]
+#[help]
+pub struct IncompatibleRustc {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name: Symbol,
+    pub add_info: String,
+    pub found_crates: String,
+    pub rustc_version: String,
+}
+
+pub struct InvalidMetadataFiles {
+    pub span: Span,
+    pub crate_name: Symbol,
+    pub add_info: String,
+    pub crate_rejections: Vec<String>,
+}
+
+impl SessionDiagnostic<'_> for InvalidMetadataFiles {
+    fn into_diagnostic(
+        self,
+        sess: &'_ rustc_session::parse::ParseSess,
+    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = sess.struct_err(rustc_errors::fluent::metadata::invalid_meta_files);
+        diag.set_arg("crate_name", self.crate_name);
+        diag.set_arg("add_info", self.add_info);
+        diag.code(error_code!(E0786));
+        diag.set_span(self.span);
+        for crate_rejection in self.crate_rejections {
+            diag.note(crate_rejection);
+        }
+        diag
+    }
+}
+
+pub struct CannotFindCrate {
+    pub span: Span,
+    pub crate_name: Symbol,
+    pub add_info: String,
+    pub missing_core: bool,
+    pub current_crate: String,
+    pub is_nightly_build: bool,
+    pub profiler_runtime: Symbol,
+    pub locator_triple: TargetTriple,
+}
+
+impl SessionDiagnostic<'_> for CannotFindCrate {
+    fn into_diagnostic(
+        self,
+        sess: &'_ rustc_session::parse::ParseSess,
+    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = sess.struct_err(rustc_errors::fluent::metadata::cannot_find_crate);
+        diag.set_arg("crate_name", self.crate_name);
+        diag.set_arg("add_info", self.add_info);
+        diag.set_arg("locator_triple", self.locator_triple.triple());
+        diag.code(error_code!(E0463));
+        diag.set_span(self.span);
+        if (self.crate_name == sym::std || self.crate_name == sym::core)
+            && self.locator_triple != TargetTriple::from_triple(config::host_triple())
+        {
+            if self.missing_core {
+                diag.note(rustc_errors::fluent::metadata::target_not_installed);
+            } else {
+                diag.note(rustc_errors::fluent::metadata::target_no_std_support);
+            }
+            // NOTE: this suggests using rustup, even though the user may not have it installed.
+            // That's because they could choose to install it; or this may give them a hint which
+            // target they need to install from their distro.
+            if self.missing_core {
+                diag.help(rustc_errors::fluent::metadata::consider_downloading_target);
+            }
+            // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway.
+            // NOTE: this is a dummy span if `extern crate std` was injected by the compiler.
+            // If it's not a dummy, that means someone added `extern crate std` explicitly and
+            // `#![no_std]` won't help.
+            if !self.missing_core && self.span.is_dummy() {
+                diag.note(rustc_errors::fluent::metadata::std_required);
+            }
+            if self.is_nightly_build {
+                diag.help(rustc_errors::fluent::metadata::consider_building_std);
+            }
+        } else if self.crate_name == self.profiler_runtime {
+            diag.note(rustc_errors::fluent::metadata::compiler_missing_profiler);
+        } else if self.crate_name.as_str().starts_with("rustc_") {
+            diag.help(rustc_errors::fluent::metadata::install_missing_components);
+        }
+        diag.span_label(self.span, rustc_errors::fluent::metadata::cant_find_crate);
+        diag
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::no_dylib_plugin, code = "E0457")]
+pub struct NoDylibPlugin {
+    #[primary_span]
+    pub span: Span,
+    pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::crate_location_unknown_type)]
+pub struct CrateLocationUnknownType<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub path: &'a Path,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::lib_filename_form)]
+pub struct LibFilenameForm<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub dll_prefix: &'a str,
+    pub dll_suffix: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::multiple_import_name_type)]
+pub struct MultipleImportNameType {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::import_name_type_form)]
+pub struct ImportNameTypeForm {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::import_name_type_x86)]
+pub struct ImportNameTypeX86 {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::unknown_import_name_type)]
+pub struct UnknownImportNameType<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub import_name_type: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(metadata::import_name_type_raw)]
+pub struct ImportNameTypeRaw {
+    #[primary_span]
+    pub span: Span,
+}
index e6072901aaa43df068a8df0f72d27de5f9980471..f360a586476e70bf4a2e9da3bd4426351d834880 100644 (file)
@@ -1,3 +1,6 @@
+use crate::errors::{
+    FailedCreateEncodedMetadata, FailedCreateFile, FailedCreateTempdir, FailedWriteError,
+};
 use crate::{encode_metadata, EncodedMetadata};
 
 use rustc_data_structures::temp_dir::MaybeTempDir;
@@ -23,8 +26,8 @@ pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) ->
     let out_filename = tmpdir.as_ref().join(METADATA_FILENAME);
     let result = fs::write(&out_filename, metadata);
 
-    if let Err(e) = result {
-        sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
+    if let Err(err) = result {
+        sess.emit_fatal(FailedWriteError { filename: out_filename, err });
     }
 
     out_filename
@@ -65,7 +68,7 @@ enum MetadataKind {
     let metadata_tmpdir = TempFileBuilder::new()
         .prefix("rmeta")
         .tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new("")))
-        .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
+        .unwrap_or_else(|err| tcx.sess.emit_fatal(FailedCreateTempdir { err }));
     let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
     let metadata_filename = metadata_tmpdir.as_ref().join(METADATA_FILENAME);
 
@@ -73,12 +76,8 @@ enum MetadataKind {
     // This simplifies the creation of the output `out_filename` when requested.
     match metadata_kind {
         MetadataKind::None => {
-            std::fs::File::create(&metadata_filename).unwrap_or_else(|e| {
-                tcx.sess.fatal(&format!(
-                    "failed to create the file {}: {}",
-                    metadata_filename.display(),
-                    e
-                ))
+            std::fs::File::create(&metadata_filename).unwrap_or_else(|err| {
+                tcx.sess.emit_fatal(FailedCreateFile { filename: &metadata_filename, err });
             });
         }
         MetadataKind::Uncompressed | MetadataKind::Compressed => {
@@ -93,8 +92,8 @@ enum MetadataKind {
     // this file always exists.
     let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
     let (metadata_filename, metadata_tmpdir) = if need_metadata_file {
-        if let Err(e) = non_durable_rename(&metadata_filename, &out_filename) {
-            tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
+        if let Err(err) = non_durable_rename(&metadata_filename, &out_filename) {
+            tcx.sess.emit_fatal(FailedWriteError { filename: out_filename, err });
         }
         if tcx.sess.opts.json_artifact_notifications {
             tcx.sess
@@ -109,8 +108,8 @@ enum MetadataKind {
 
     // Load metadata back to memory: codegen may need to include it in object files.
     let metadata =
-        EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|e| {
-            tcx.sess.fatal(&format!("failed to create encoded metadata from file: {}", e))
+        EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|err| {
+            tcx.sess.emit_fatal(FailedCreateEncodedMetadata { err });
         });
 
     let need_metadata_module = metadata_kind == MetadataKind::Compressed;
index 75069a5f0dc015f56c9d8026bdf020f69ae0ae70..8e0291fc3ad18291ada2d7e141762bb242142bb1 100644 (file)
@@ -4,6 +4,7 @@
 #![feature(generators)]
 #![feature(generic_associated_types)]
 #![feature(iter_from_generator)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(once_cell)]
 #![feature(proc_macro_internals)]
@@ -15,6 +16,8 @@
 #![feature(never_type)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 
 extern crate proc_macro;
 
@@ -25,6 +28,9 @@
 #[macro_use]
 extern crate rustc_data_structures;
 
+#[macro_use]
+extern crate tracing;
+
 pub use rmeta::{provide, provide_extern};
 
 mod dependency_format;
@@ -33,6 +39,7 @@
 mod rmeta;
 
 pub mod creader;
+pub mod errors;
 pub mod fs;
 pub mod locator;
 
index 2c1c84b0be26a874d7d9e6657f6a05f105381460..35f9ef92a1c425fb74eb8b4866ee187df9b27957 100644 (file)
 //! metadata::locator or metadata::creader for all the juicy details!
 
 use crate::creader::Library;
+use crate::errors::{
+    CannotFindCrate, CrateLocationUnknownType, DlError, ExternLocationNotExist,
+    ExternLocationNotFile, FoundStaticlib, IncompatibleRustc, InvalidMetadataFiles,
+    LibFilenameForm, MultipleCandidates, MultipleMatchingCrates, NewerCrateVersion,
+    NoCrateWithTriple, NoDylibPlugin, NonAsciiName, StableCrateIdCollision, SymbolConflictsCurrent,
+    SymbolConflictsOthers,
+};
 use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::owning_ref::OwningRef;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::MetadataRef;
-use rustc_errors::{struct_span_err, FatalError};
+use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg};
 use rustc_session::config::{self, CrateType};
 use rustc_session::cstore::{CrateSource, MetadataLoader};
 use rustc_session::filesearch::FileSearch;
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::CanonicalizedPath;
 use rustc_session::Session;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 use rustc_target::spec::{Target, TargetTriple};
 
 use snap::read::FrameDecoder;
+use std::borrow::Cow;
 use std::fmt::Write as _;
 use std::io::{Read, Result as IoResult, Write};
 use std::path::{Path, PathBuf};
 use std::{cmp, fmt, fs};
-use tracing::{debug, info};
 
 #[derive(Clone)]
 pub(crate) struct CrateLocator<'a> {
@@ -288,6 +295,16 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+impl IntoDiagnosticArg for CrateFlavor {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        match self {
+            CrateFlavor::Rlib => DiagnosticArgValue::Str(Cow::Borrowed("rlib")),
+            CrateFlavor::Rmeta => DiagnosticArgValue::Str(Cow::Borrowed("rmeta")),
+            CrateFlavor::Dylib => DiagnosticArgValue::Str(Cow::Borrowed("dylib")),
+        }
+    }
+}
+
 impl<'a> CrateLocator<'a> {
     pub(crate) fn new(
         sess: &'a Session,
@@ -938,41 +955,20 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 impl CrateError {
     pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
-        let mut diag = match self {
-            CrateError::NonAsciiName(crate_name) => sess.struct_span_err(
-                span,
-                &format!("cannot load a crate with a non-ascii name `{}`", crate_name),
-            ),
-            CrateError::ExternLocationNotExist(crate_name, loc) => sess.struct_span_err(
-                span,
-                &format!("extern location for {} does not exist: {}", crate_name, loc.display()),
-            ),
-            CrateError::ExternLocationNotFile(crate_name, loc) => sess.struct_span_err(
-                span,
-                &format!("extern location for {} is not a file: {}", crate_name, loc.display()),
-            ),
+        match self {
+            CrateError::NonAsciiName(crate_name) => {
+                sess.emit_err(NonAsciiName { span, crate_name });
+            }
+            CrateError::ExternLocationNotExist(crate_name, loc) => {
+                sess.emit_err(ExternLocationNotExist { span, crate_name, location: &loc });
+            }
+            CrateError::ExternLocationNotFile(crate_name, loc) => {
+                sess.emit_err(ExternLocationNotFile { span, crate_name, location: &loc });
+            }
             CrateError::MultipleCandidates(crate_name, flavor, candidates) => {
-                let mut err = struct_span_err!(
-                    sess,
-                    span,
-                    E0465,
-                    "multiple {} candidates for `{}` found",
-                    flavor,
-                    crate_name,
-                );
-                for (i, candidate) in candidates.iter().enumerate() {
-                    err.span_note(span, &format!("candidate #{}: {}", i + 1, candidate.display()));
-                }
-                err
+                sess.emit_err(MultipleCandidates { span, flavor: flavor, crate_name, candidates });
             }
             CrateError::MultipleMatchingCrates(crate_name, libraries) => {
-                let mut err = struct_span_err!(
-                    sess,
-                    span,
-                    E0464,
-                    "multiple matching crates for `{}`",
-                    crate_name
-                );
                 let mut libraries: Vec<_> = libraries.into_values().collect();
                 // Make ordering of candidates deterministic.
                 // This has to `clone()` to work around lifetime restrictions with `sort_by_key()`.
@@ -1000,223 +996,142 @@ pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
                         s
                     })
                     .collect::<String>();
-                err.note(&format!("candidates:{}", candidates));
-                err
+                sess.emit_err(MultipleMatchingCrates { span, crate_name, candidates });
+            }
+            CrateError::SymbolConflictsCurrent(root_name) => {
+                sess.emit_err(SymbolConflictsCurrent { span, crate_name: root_name });
+            }
+            CrateError::SymbolConflictsOthers(root_name) => {
+                sess.emit_err(SymbolConflictsOthers { span, crate_name: root_name });
             }
-            CrateError::SymbolConflictsCurrent(root_name) => struct_span_err!(
-                sess,
-                span,
-                E0519,
-                "the current crate is indistinguishable from one of its dependencies: it has the \
-                 same crate-name `{}` and was compiled with the same `-C metadata` arguments. \
-                 This will result in symbol conflicts between the two.",
-                root_name,
-            ),
-            CrateError::SymbolConflictsOthers(root_name) => struct_span_err!(
-                sess,
-                span,
-                E0523,
-                "found two different crates with name `{}` that are not distinguished by differing \
-                 `-C metadata`. This will result in symbol conflicts between the two.",
-                root_name,
-            ),
             CrateError::StableCrateIdCollision(crate_name0, crate_name1) => {
-                let msg = format!(
-                    "found crates (`{}` and `{}`) with colliding StableCrateId values.",
-                    crate_name0, crate_name1
-                );
-                sess.struct_span_err(span, &msg)
+                sess.emit_err(StableCrateIdCollision {
+                    span,
+                    crate_name0: crate_name0,
+                    crate_name1: crate_name1,
+                });
+            }
+            CrateError::DlOpen(s) | CrateError::DlSym(s) => {
+                sess.emit_err(DlError { span, err: s });
             }
-            CrateError::DlOpen(s) | CrateError::DlSym(s) => sess.struct_span_err(span, &s),
             CrateError::LocatorCombined(locator) => {
                 let crate_name = locator.crate_name;
-                let add = match &locator.root {
+                let add_info = match &locator.root {
                     None => String::new(),
                     Some(r) => format!(" which `{}` depends on", r.name),
                 };
-                let mut msg = "the following crate versions were found:".to_string();
-                let mut err = if !locator.crate_rejections.via_hash.is_empty() {
-                    let mut err = struct_span_err!(
-                        sess,
-                        span,
-                        E0460,
-                        "found possibly newer version of crate `{}`{}",
-                        crate_name,
-                        add,
-                    );
-                    err.note("perhaps that crate needs to be recompiled?");
+                // FIXME: There are no tests for CrateLocationUnknownType or LibFilenameForm
+                if !locator.crate_rejections.via_filename.is_empty() {
+                    let mismatches = locator.crate_rejections.via_filename.iter();
+                    for CrateMismatch { path, .. } in mismatches {
+                        sess.emit_err(CrateLocationUnknownType { span, path: &path });
+                        sess.emit_err(LibFilenameForm {
+                            span,
+                            dll_prefix: &locator.dll_prefix,
+                            dll_suffix: &locator.dll_suffix,
+                        });
+                    }
+                }
+                let mut found_crates = String::new();
+                if !locator.crate_rejections.via_hash.is_empty() {
                     let mismatches = locator.crate_rejections.via_hash.iter();
                     for CrateMismatch { path, .. } in mismatches {
-                        msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display()));
+                        found_crates.push_str(&format!(
+                            "\ncrate `{}`: {}",
+                            crate_name,
+                            path.display()
+                        ));
                     }
                     if let Some(r) = locator.root {
                         for path in r.source.paths() {
-                            msg.push_str(&format!("\ncrate `{}`: {}", r.name, path.display()));
+                            found_crates.push_str(&format!(
+                                "\ncrate `{}`: {}",
+                                r.name,
+                                path.display()
+                            ));
                         }
                     }
-                    err.note(&msg);
-                    err
-                } else if !locator.crate_rejections.via_triple.is_empty() {
-                    let mut err = struct_span_err!(
-                        sess,
+                    sess.emit_err(NewerCrateVersion {
                         span,
-                        E0461,
-                        "couldn't find crate `{}` with expected target triple {}{}",
-                        crate_name,
-                        locator.triple,
-                        add,
-                    );
+                        crate_name: crate_name,
+                        add_info,
+                        found_crates,
+                    });
+                } else if !locator.crate_rejections.via_triple.is_empty() {
                     let mismatches = locator.crate_rejections.via_triple.iter();
                     for CrateMismatch { path, got } in mismatches {
-                        msg.push_str(&format!(
+                        found_crates.push_str(&format!(
                             "\ncrate `{}`, target triple {}: {}",
                             crate_name,
                             got,
                             path.display(),
                         ));
                     }
-                    err.note(&msg);
-                    err
-                } else if !locator.crate_rejections.via_kind.is_empty() {
-                    let mut err = struct_span_err!(
-                        sess,
+                    sess.emit_err(NoCrateWithTriple {
                         span,
-                        E0462,
-                        "found staticlib `{}` instead of rlib or dylib{}",
-                        crate_name,
-                        add,
-                    );
-                    err.help("please recompile that crate using --crate-type lib");
+                        crate_name: crate_name,
+                        locator_triple: locator.triple.triple(),
+                        add_info,
+                        found_crates,
+                    });
+                } else if !locator.crate_rejections.via_kind.is_empty() {
                     let mismatches = locator.crate_rejections.via_kind.iter();
                     for CrateMismatch { path, .. } in mismatches {
-                        msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display()));
+                        found_crates.push_str(&format!(
+                            "\ncrate `{}`: {}",
+                            crate_name,
+                            path.display()
+                        ));
                     }
-                    err.note(&msg);
-                    err
+                    sess.emit_err(FoundStaticlib { span, crate_name, add_info, found_crates });
                 } else if !locator.crate_rejections.via_version.is_empty() {
-                    let mut err = struct_span_err!(
-                        sess,
-                        span,
-                        E0514,
-                        "found crate `{}` compiled by an incompatible version of rustc{}",
-                        crate_name,
-                        add,
-                    );
-                    err.help(&format!(
-                        "please recompile that crate using this compiler ({}) \
-                         (consider running `cargo clean` first)",
-                        rustc_version(),
-                    ));
                     let mismatches = locator.crate_rejections.via_version.iter();
                     for CrateMismatch { path, got } in mismatches {
-                        msg.push_str(&format!(
+                        found_crates.push_str(&format!(
                             "\ncrate `{}` compiled by {}: {}",
                             crate_name,
                             got,
                             path.display(),
                         ));
                     }
-                    err.note(&msg);
-                    err
-                } else if !locator.crate_rejections.via_invalid.is_empty() {
-                    let mut err = struct_span_err!(
-                        sess,
+                    sess.emit_err(IncompatibleRustc {
                         span,
-                        E0786,
-                        "found invalid metadata files for crate `{}`{}",
                         crate_name,
-                        add,
-                    );
+                        add_info,
+                        found_crates,
+                        rustc_version: rustc_version(),
+                    });
+                } else if !locator.crate_rejections.via_invalid.is_empty() {
+                    let mut crate_rejections = Vec::new();
                     for CrateMismatch { path: _, got } in locator.crate_rejections.via_invalid {
-                        err.note(&got);
+                        crate_rejections.push(got);
                     }
-                    err
+                    sess.emit_err(InvalidMetadataFiles {
+                        span,
+                        crate_name,
+                        add_info,
+                        crate_rejections,
+                    });
                 } else {
-                    let mut err = struct_span_err!(
-                        sess,
+                    sess.emit_err(CannotFindCrate {
                         span,
-                        E0463,
-                        "can't find crate for `{}`{}",
                         crate_name,
-                        add,
-                    );
-
-                    if (crate_name == sym::std || crate_name == sym::core)
-                        && locator.triple != TargetTriple::from_triple(config::host_triple())
-                    {
-                        if missing_core {
-                            err.note(&format!(
-                                "the `{}` target may not be installed",
-                                locator.triple
-                            ));
-                        } else {
-                            err.note(&format!(
-                                "the `{}` target may not support the standard library",
-                                locator.triple
-                            ));
-                        }
-                        // NOTE: this suggests using rustup, even though the user may not have it installed.
-                        // That's because they could choose to install it; or this may give them a hint which
-                        // target they need to install from their distro.
-                        if missing_core {
-                            err.help(&format!(
-                                "consider downloading the target with `rustup target add {}`",
-                                locator.triple
-                            ));
-                        }
-                        // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway.
-                        // NOTE: this is a dummy span if `extern crate std` was injected by the compiler.
-                        // If it's not a dummy, that means someone added `extern crate std` explicitly and `#![no_std]` won't help.
-                        if !missing_core && span.is_dummy() {
-                            let current_crate =
-                                sess.opts.crate_name.as_deref().unwrap_or("<unknown>");
-                            err.note(&format!(
-                                "`std` is required by `{}` because it does not declare `#![no_std]`",
-                                current_crate
-                            ));
-                        }
-                        if sess.is_nightly_build() {
-                            err.help("consider building the standard library from source with `cargo build -Zbuild-std`");
-                        }
-                    } else if crate_name
-                        == Symbol::intern(&sess.opts.unstable_opts.profiler_runtime)
-                    {
-                        err.note("the compiler may have been built without the profiler runtime");
-                    } else if crate_name.as_str().starts_with("rustc_") {
-                        err.help(
-                            "maybe you need to install the missing components with: \
-                             `rustup component add rust-src rustc-dev llvm-tools-preview`",
-                        );
-                    }
-                    err.span_label(span, "can't find crate");
-                    err
-                };
-
-                if !locator.crate_rejections.via_filename.is_empty() {
-                    let mismatches = locator.crate_rejections.via_filename.iter();
-                    for CrateMismatch { path, .. } in mismatches {
-                        err.note(&format!(
-                            "extern location for {} is of an unknown type: {}",
-                            crate_name,
-                            path.display(),
-                        ))
-                        .help(&format!(
-                            "file name should be lib*.rlib or {}*.{}",
-                            locator.dll_prefix, locator.dll_suffix
-                        ));
-                    }
+                        add_info,
+                        missing_core,
+                        current_crate: sess
+                            .opts
+                            .crate_name
+                            .clone()
+                            .unwrap_or("<unknown>".to_string()),
+                        is_nightly_build: sess.is_nightly_build(),
+                        profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime),
+                        locator_triple: locator.triple,
+                    });
                 }
-                err
             }
-            CrateError::NonDylibPlugin(crate_name) => struct_span_err!(
-                sess,
-                span,
-                E0457,
-                "plugin `{}` only found in rlib format, but must be available in dylib format",
-                crate_name,
-            ),
-        };
-
-        diag.emit();
+            CrateError::NonDylibPlugin(crate_name) => {
+                sess.emit_err(NoDylibPlugin { span, crate_name });
+            }
+        }
     }
 }
index 8bafe203748f37784dc703b62d22d601ad07e6f1..87b5e750f1cb14fba7110775e572e53af2aa34ae 100644 (file)
@@ -1,7 +1,6 @@
 use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
+use crate::errors::{
+    AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, EmptyRenamingTarget,
+    FrameworkOnlyWindows, ImportNameTypeForm, ImportNameTypeRaw, ImportNameTypeX86,
+    IncompatibleWasmLink, InvalidLinkModifier, LibFrameworkApple, LinkCfgForm,
+    LinkCfgSinglePredicate, LinkFrameworkApple, LinkKindForm, LinkModifiersForm, LinkNameForm,
+    LinkOrdinalRawDylib, LinkRequiresName, MultipleCfgs, MultipleImportNameType,
+    MultipleKindsInLink, MultipleLinkModifiers, MultipleModifiers, MultipleNamesInLink,
+    MultipleRenamings, MultipleWasmImport, NoLinkModOverride, RawDylibNoNul, RenamingNoLink,
+    UnexpectedLinkArg, UnknownImportNameType, UnknownLinkKind, UnknownLinkModifier, UnsupportedAbi,
+    UnsupportedAbiI686, WasmImportForm, WholeArchiveNeedsStatic,
+};
+
 pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
     let mut collector = Collector { tcx, libs: Vec::new() };
     for id in tcx.hir().items() {
@@ -66,32 +77,26 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                 match item.name_or_empty() {
                     sym::name => {
                         if name.is_some() {
-                            let msg = "multiple `name` arguments in a single `#[link]` attribute";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(MultipleNamesInLink { span: item.span() });
                             continue;
                         }
                         let Some(link_name) = item.value_str() else {
-                            let msg = "link name must be of the form `name = \"string\"`";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(LinkNameForm { span: item.span() });
                             continue;
                         };
                         let span = item.name_value_literal_span().unwrap();
                         if link_name.is_empty() {
-                            struct_span_err!(sess, span, E0454, "link name must not be empty")
-                                .span_label(span, "empty link name")
-                                .emit();
+                            sess.emit_err(EmptyLinkName { span });
                         }
                         name = Some((link_name, span));
                     }
                     sym::kind => {
                         if kind.is_some() {
-                            let msg = "multiple `kind` arguments in a single `#[link]` attribute";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(MultipleKindsInLink { span: item.span() });
                             continue;
                         }
                         let Some(link_kind) = item.value_str() else {
-                            let msg = "link kind must be of the form `kind = \"string\"`";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(LinkKindForm { span: item.span() });
                             continue;
                         };
 
@@ -101,25 +106,13 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                             "dylib" => NativeLibKind::Dylib { as_needed: None },
                             "framework" => {
                                 if !sess.target.is_like_osx {
-                                    struct_span_err!(
-                                        sess,
-                                        span,
-                                        E0455,
-                                        "link kind `framework` is only supported on Apple targets"
-                                    )
-                                    .emit();
+                                    sess.emit_err(LinkFrameworkApple { span });
                                 }
                                 NativeLibKind::Framework { as_needed: None }
                             }
                             "raw-dylib" => {
                                 if !sess.target.is_like_windows {
-                                    struct_span_err!(
-                                        sess,
-                                        span,
-                                        E0455,
-                                        "link kind `raw-dylib` is only supported on Windows targets"
-                                    )
-                                    .emit();
+                                    sess.emit_err(FrameworkOnlyWindows { span });
                                 } else if !features.raw_dylib {
                                     feature_err(
                                         &sess.parse_sess,
@@ -132,13 +125,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                                 NativeLibKind::RawDylib
                             }
                             kind => {
-                                let msg = format!(
-                                    "unknown link kind `{kind}`, expected one of: \
-                                     static, dylib, framework, raw-dylib"
-                                );
-                                struct_span_err!(sess, span, E0458, "{}", msg)
-                                    .span_label(span, "unknown link kind")
-                                    .emit();
+                                sess.emit_err(UnknownLinkKind { span, kind });
                                 continue;
                             }
                         };
@@ -146,32 +133,26 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                     }
                     sym::modifiers => {
                         if modifiers.is_some() {
-                            let msg =
-                                "multiple `modifiers` arguments in a single `#[link]` attribute";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(MultipleLinkModifiers { span: item.span() });
                             continue;
                         }
                         let Some(link_modifiers) = item.value_str() else {
-                            let msg = "link modifiers must be of the form `modifiers = \"string\"`";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(LinkModifiersForm { span: item.span() });
                             continue;
                         };
                         modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
                     }
                     sym::cfg => {
                         if cfg.is_some() {
-                            let msg = "multiple `cfg` arguments in a single `#[link]` attribute";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(MultipleCfgs { span: item.span() });
                             continue;
                         }
                         let Some(link_cfg) = item.meta_item_list() else {
-                            let msg = "link cfg must be of the form `cfg(/* predicate */)`";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(LinkCfgForm { span: item.span() });
                             continue;
                         };
                         let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
-                            let msg = "link cfg must have a single predicate argument";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(LinkCfgSinglePredicate { span: item.span() });
                             continue;
                         };
                         if !features.link_cfg {
@@ -187,33 +168,26 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                     }
                     sym::wasm_import_module => {
                         if wasm_import_module.is_some() {
-                            let msg = "multiple `wasm_import_module` arguments \
-                                       in a single `#[link]` attribute";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(MultipleWasmImport { span: item.span() });
                             continue;
                         }
                         let Some(link_wasm_import_module) = item.value_str() else {
-                            let msg = "wasm import module must be of the form \
-                                       `wasm_import_module = \"string\"`";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(WasmImportForm { span: item.span() });
                             continue;
                         };
                         wasm_import_module = Some((link_wasm_import_module, item.span()));
                     }
                     sym::import_name_type => {
                         if import_name_type.is_some() {
-                            let msg = "multiple `import_name_type` arguments in a single `#[link]` attribute";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(MultipleImportNameType { span: item.span() });
                             continue;
                         }
                         let Some(link_import_name_type) = item.value_str() else {
-                            let msg = "import name type must be of the form `import_name_type = \"string\"`";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(ImportNameTypeForm { span: item.span() });
                             continue;
                         };
                         if self.tcx.sess.target.arch != "x86" {
-                            let msg = "import name type is only supported on x86";
-                            sess.span_err(item.span(), msg);
+                            sess.emit_err(ImportNameTypeX86 { span: item.span() });
                             continue;
                         }
 
@@ -222,11 +196,10 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                             "noprefix" => PeImportNameType::NoPrefix,
                             "undecorated" => PeImportNameType::Undecorated,
                             import_name_type => {
-                                let msg = format!(
-                                    "unknown import name type `{import_name_type}`, expected one of: \
-                                     decorated, noprefix, undecorated"
-                                );
-                                sess.span_err(item.span(), msg);
+                                sess.emit_err(UnknownImportNameType {
+                                    span: item.span(),
+                                    import_name_type,
+                                });
                                 continue;
                             }
                         };
@@ -243,9 +216,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                         import_name_type = Some((link_import_name_type, item.span()));
                     }
                     _ => {
-                        let msg = "unexpected `#[link]` argument, expected one of: \
-                                   name, kind, modifiers, cfg, wasm_import_module, import_name_type";
-                        sess.span_err(item.span(), msg);
+                        sess.emit_err(UnexpectedLinkArg { span: item.span() });
                     }
                 }
             }
@@ -257,11 +228,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                     let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
                         Some(m) => (m, modifier.starts_with('+')),
                         None => {
-                            sess.span_err(
-                                span,
-                                "invalid linking modifier syntax, expected '+' or '-' prefix \
-                                before one of: bundle, verbatim, whole-archive, as-needed",
-                            );
+                            sess.emit_err(InvalidLinkModifier { span });
                             continue;
                         }
                     };
@@ -279,10 +246,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                     }
                     let assign_modifier = |dst: &mut Option<bool>| {
                         if dst.is_some() {
-                            let msg = format!(
-                                "multiple `{modifier}` modifiers in a single `modifiers` argument"
-                            );
-                            sess.span_err(span, &msg);
+                            sess.emit_err(MultipleModifiers { span, modifier });
                         } else {
                             *dst = Some(value);
                         }
@@ -292,11 +256,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                             assign_modifier(bundle)
                         }
                         ("bundle", _) => {
-                            sess.span_err(
-                                span,
-                                "linking modifier `bundle` is only compatible with \
-                                 `static` linking kind",
-                            );
+                            sess.emit_err(BundleNeedsStatic { span });
                         }
 
                         ("verbatim", _) => {
@@ -308,11 +268,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                             assign_modifier(whole_archive)
                         }
                         ("whole-archive", _) => {
-                            sess.span_err(
-                                span,
-                                "linking modifier `whole-archive` is only compatible with \
-                                 `static` linking kind",
-                            );
+                            sess.emit_err(WholeArchiveNeedsStatic { span });
                         }
 
                         ("as-needed", Some(NativeLibKind::Dylib { as_needed }))
@@ -321,21 +277,11 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                             assign_modifier(as_needed)
                         }
                         ("as-needed", _) => {
-                            sess.span_err(
-                                span,
-                                "linking modifier `as-needed` is only compatible with \
-                                 `dylib` and `framework` linking kinds",
-                            );
+                            sess.emit_err(AsNeededCompatibility { span });
                         }
 
                         _ => {
-                            sess.span_err(
-                                span,
-                                format!(
-                                    "unknown linking modifier `{modifier}`, expected one of: \
-                                     bundle, verbatim, whole-archive, as-needed"
-                                ),
-                            );
+                            sess.emit_err(UnknownLinkModifier { span, modifier });
                         }
                     }
                 }
@@ -343,36 +289,23 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
 
             if let Some((_, span)) = wasm_import_module {
                 if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
-                    let msg = "`wasm_import_module` is incompatible with \
-                               other arguments in `#[link]` attributes";
-                    sess.span_err(span, msg);
+                    sess.emit_err(IncompatibleWasmLink { span });
                 }
             } else if name.is_none() {
-                struct_span_err!(
-                    sess,
-                    m.span,
-                    E0459,
-                    "`#[link]` attribute requires a `name = \"string\"` argument"
-                )
-                .span_label(m.span, "missing `name` argument")
-                .emit();
+                sess.emit_err(LinkRequiresName { span: m.span });
             }
 
             // Do this outside of the loop so that `import_name_type` can be specified before `kind`.
             if let Some((_, span)) = import_name_type {
                 if kind != Some(NativeLibKind::RawDylib) {
-                    let msg = "import name type can only be used with link kind `raw-dylib`";
-                    sess.span_err(span, msg);
+                    sess.emit_err(ImportNameTypeRaw { span });
                 }
             }
 
             let dll_imports = match kind {
                 Some(NativeLibKind::RawDylib) => {
                     if let Some((name, span)) = name && name.as_str().contains('\0') {
-                        sess.span_err(
-                            span,
-                            "link name must not contain NUL characters if link kind is `raw-dylib`",
-                        );
+                        sess.emit_err(RawDylibNoNul { span });
                     }
                     foreign_mod_items
                         .iter()
@@ -401,10 +334,7 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
                                 .iter()
                                 .find(|a| a.has_name(sym::link_ordinal))
                                 .unwrap();
-                            sess.span_err(
-                                link_ordinal_attr.span,
-                                "`#[link_ordinal]` is only supported if link kind is `raw-dylib`",
-                            );
+                            sess.emit_err(LinkOrdinalRawDylib { span: link_ordinal_attr.span });
                         }
                     }
 
@@ -430,7 +360,7 @@ fn process_command_line(&mut self) {
         for lib in &self.tcx.sess.opts.libs {
             if let NativeLibKind::Framework { .. } = lib.kind && !self.tcx.sess.target.is_like_osx {
                 // Cannot check this when parsing options because the target is not yet available.
-                self.tcx.sess.err("library kind `framework` is only supported on Apple targets");
+                self.tcx.sess.emit_err(LibFrameworkApple);
             }
             if let Some(ref new_name) = lib.new_name {
                 let any_duplicate = self
@@ -439,23 +369,11 @@ fn process_command_line(&mut self) {
                     .filter_map(|lib| lib.name.as_ref())
                     .any(|n| n.as_str() == lib.name);
                 if new_name.is_empty() {
-                    self.tcx.sess.err(format!(
-                        "an empty renaming target was specified for library `{}`",
-                        lib.name
-                    ));
+                    self.tcx.sess.emit_err(EmptyRenamingTarget { lib_name: &lib.name });
                 } else if !any_duplicate {
-                    self.tcx.sess.err(format!(
-                        "renaming of the library `{}` was specified, \
-                                                however this crate contains no `#[link(...)]` \
-                                                attributes referencing this library",
-                        lib.name
-                    ));
+                    self.tcx.sess.emit_err(RenamingNoLink { lib_name: &lib.name });
                 } else if !renames.insert(&lib.name) {
-                    self.tcx.sess.err(format!(
-                        "multiple renamings were \
-                                                specified for library `{}`",
-                        lib.name
-                    ));
+                    self.tcx.sess.emit_err(MultipleRenamings { lib_name: &lib.name });
                 }
             }
         }
@@ -480,10 +398,13 @@ fn process_command_line(&mut self) {
                             // involved or not, library reordering and kind overriding without
                             // explicit `:rename` in particular.
                             if lib.has_modifiers() || passed_lib.has_modifiers() {
-                                let msg = "overriding linking modifiers from command line is not supported";
                                 match lib.foreign_module {
-                                    Some(def_id) => self.tcx.sess.span_err(self.tcx.def_span(def_id), msg),
-                                    None => self.tcx.sess.err(msg),
+                                    Some(def_id) => self.tcx.sess.emit_err(NoLinkModOverride {
+                                        span: Some(self.tcx.def_span(def_id)),
+                                    }),
+                                    None => {
+                                        self.tcx.sess.emit_err(NoLinkModOverride { span: None })
+                                    }
                                 };
                             }
                             if passed_lib.kind != NativeLibKind::Unspecified {
@@ -562,20 +483,14 @@ fn build_dll_import(
                     DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
                 }
                 _ => {
-                    self.tcx.sess.span_fatal(
-                        item.span,
-                        r#"ABI not supported by `#[link(kind = "raw-dylib")]` on i686"#,
-                    );
+                    self.tcx.sess.emit_fatal(UnsupportedAbiI686 { span: item.span });
                 }
             }
         } else {
             match abi {
                 Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C,
                 _ => {
-                    self.tcx.sess.span_fatal(
-                        item.span,
-                        r#"ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture"#,
-                    );
+                    self.tcx.sess.emit_fatal(UnsupportedAbi { span: item.span });
                 }
             }
         };
index d0e0aa91480c917eb56c5243795c9c5ef5c3c1f3..6f026678170b7af312fbde3ba26f97d40ebf3982 100644 (file)
@@ -4,7 +4,6 @@
 use crate::rmeta::*;
 
 use rustc_ast as ast;
-use rustc_ast::ptr::P;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
@@ -33,7 +32,7 @@
 use rustc_session::Session;
 use rustc_span::hygiene::{ExpnIndex, MacroKind};
 use rustc_span::source_map::{respan, Spanned};
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{self, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP};
 
 use proc_macro::bridge::client::ProcMacro;
@@ -42,7 +41,6 @@
 use std::mem;
 use std::num::NonZeroUsize;
 use std::path::Path;
-use tracing::debug;
 
 pub(super) use cstore_impl::provide;
 pub use cstore_impl::provide_extern;
@@ -786,26 +784,11 @@ fn item_ident(self, item_index: DefIndex, sess: &Session) -> Ident {
         self.opt_item_ident(item_index, sess).expect("no encoded ident for item")
     }
 
-    fn maybe_kind(self, item_id: DefIndex) -> Option<EntryKind> {
-        self.root.tables.kind.get(self, item_id).map(|k| k.decode(self))
-    }
-
     #[inline]
     pub(super) fn map_encoded_cnum_to_current(self, cnum: CrateNum) -> CrateNum {
         if cnum == LOCAL_CRATE { self.cnum } else { self.cnum_map[cnum] }
     }
 
-    fn kind(self, item_id: DefIndex) -> EntryKind {
-        self.maybe_kind(item_id).unwrap_or_else(|| {
-            bug!(
-                "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}",
-                item_id,
-                self.root.name,
-                self.cnum,
-            )
-        })
-    }
-
     fn def_kind(self, item_id: DefIndex) -> DefKind {
         self.root.tables.opt_def_kind.get(self, item_id).unwrap_or_else(|| {
             bug!(
@@ -857,21 +840,16 @@ fn load_proc_macro(self, id: DefIndex, sess: &Session) -> SyntaxExtension {
         )
     }
 
-    fn get_variant(self, kind: &EntryKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef {
-        let data = match kind {
-            EntryKind::Variant(data) | EntryKind::Struct(data) | EntryKind::Union(data) => {
-                data.decode(self)
-            }
-            _ => bug!(),
-        };
-
+    fn get_variant(self, kind: &DefKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef {
         let adt_kind = match kind {
-            EntryKind::Variant(_) => ty::AdtKind::Enum,
-            EntryKind::Struct(..) => ty::AdtKind::Struct,
-            EntryKind::Union(..) => ty::AdtKind::Union,
+            DefKind::Variant => ty::AdtKind::Enum,
+            DefKind::Struct => ty::AdtKind::Struct,
+            DefKind::Union => ty::AdtKind::Union,
             _ => bug!(),
         };
 
+        let data = self.root.tables.variant_data.get(self, index).unwrap().decode(self);
+
         let variant_did =
             if adt_kind == ty::AdtKind::Enum { Some(self.local_def_id(index)) } else { None };
         let ctor_did = data.ctor.map(|index| self.local_def_id(index));
@@ -902,13 +880,13 @@ fn get_variant(self, kind: &EntryKind, index: DefIndex, parent_did: DefId) -> ty
     }
 
     fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<'tcx> {
-        let kind = self.kind(item_id);
+        let kind = self.def_kind(item_id);
         let did = self.local_def_id(item_id);
 
         let adt_kind = match kind {
-            EntryKind::Enum => ty::AdtKind::Enum,
-            EntryKind::Struct(_) => ty::AdtKind::Struct,
-            EntryKind::Union(_) => ty::AdtKind::Union,
+            DefKind::Enum => ty::AdtKind::Enum,
+            DefKind::Struct => ty::AdtKind::Struct,
+            DefKind::Union => ty::AdtKind::Union,
             _ => bug!("get_adt_def called on a non-ADT {:?}", did),
         };
         let repr = self.root.tables.repr_options.get(self, item_id).unwrap().decode(self);
@@ -920,7 +898,7 @@ fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<'tcx> {
                 .get(self, item_id)
                 .unwrap_or_else(LazyArray::empty)
                 .decode(self)
-                .map(|index| self.get_variant(&self.kind(index), index, did))
+                .map(|index| self.get_variant(&self.def_kind(index), index, did))
                 .collect()
         } else {
             std::iter::once(self.get_variant(&kind, item_id, did)).collect()
@@ -1030,10 +1008,9 @@ fn for_each_module_child(
                 let vis = self.get_visibility(child_index);
                 let span = self.get_span(child_index, sess);
                 let macro_rules = match kind {
-                    DefKind::Macro(..) => match self.kind(child_index) {
-                        EntryKind::MacroDef(_, macro_rules) => macro_rules,
-                        _ => unreachable!(),
-                    },
+                    DefKind::Macro(..) => {
+                        self.root.tables.macro_rules.get(self, child_index).is_some()
+                    }
                     _ => false,
                 };
 
@@ -1087,14 +1064,10 @@ fn for_each_module_child(
             }
         }
 
-        match self.kind(id) {
-            EntryKind::Mod(exports) => {
-                for exp in exports.decode((self, sess)) {
-                    callback(exp);
-                }
+        if let Some(exports) = self.root.tables.module_reexports.get(self, id) {
+            for exp in exports.decode((self, sess)) {
+                callback(exp);
             }
-            EntryKind::Enum | EntryKind::Trait => {}
-            _ => bug!("`for_each_module_child` is called on a non-module: {:?}", self.def_kind(id)),
         }
     }
 
@@ -1107,19 +1080,21 @@ fn is_item_mir_available(self, id: DefIndex) -> bool {
     }
 
     fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId {
-        match self.kind(id) {
-            EntryKind::Mod(_) | EntryKind::Enum | EntryKind::Trait => {
-                self.get_expn_that_defined(id, sess)
-            }
+        match self.def_kind(id) {
+            DefKind::Mod | DefKind::Enum | DefKind::Trait => self.get_expn_that_defined(id, sess),
             _ => panic!("Expected module, found {:?}", self.local_def_id(id)),
         }
     }
 
-    fn get_fn_has_self_parameter(self, id: DefIndex) -> bool {
-        match self.kind(id) {
-            EntryKind::AssocFn { has_self, .. } => has_self,
-            _ => false,
-        }
+    fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool {
+        self.root
+            .tables
+            .fn_arg_names
+            .get(self, id)
+            .unwrap_or_else(LazyArray::empty)
+            .decode((self, sess))
+            .nth(0)
+            .map_or(false, |ident| ident.name == kw::SelfLower)
     }
 
     fn get_associated_item_def_ids(
@@ -1136,15 +1111,17 @@ fn get_associated_item_def_ids(
             .map(move |child_index| self.local_def_id(child_index))
     }
 
-    fn get_associated_item(self, id: DefIndex) -> ty::AssocItem {
+    fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem {
         let name = self.item_name(id);
 
-        let (kind, container, has_self) = match self.kind(id) {
-            EntryKind::AssocConst(container) => (ty::AssocKind::Const, container, false),
-            EntryKind::AssocFn { container, has_self } => (ty::AssocKind::Fn, container, has_self),
-            EntryKind::AssocType(container) => (ty::AssocKind::Type, container, false),
-            _ => bug!("cannot get associated-item of `{:?}`", id),
+        let kind = match self.def_kind(id) {
+            DefKind::AssocConst => ty::AssocKind::Const,
+            DefKind::AssocFn => ty::AssocKind::Fn,
+            DefKind::AssocTy => ty::AssocKind::Type,
+            _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
         };
+        let has_self = self.get_fn_has_self_parameter(id, sess);
+        let container = self.root.tables.assoc_container.get(self, id).unwrap();
 
         ty::AssocItem {
             name,
@@ -1157,9 +1134,9 @@ fn get_associated_item(self, id: DefIndex) -> ty::AssocItem {
     }
 
     fn get_ctor_def_id_and_kind(self, node_id: DefIndex) -> Option<(DefId, CtorKind)> {
-        match self.kind(node_id) {
-            EntryKind::Struct(data) | EntryKind::Variant(data) => {
-                let vdata = data.decode(self);
+        match self.def_kind(node_id) {
+            DefKind::Struct | DefKind::Variant => {
+                let vdata = self.root.tables.variant_data.get(self, node_id).unwrap().decode(self);
                 vdata.ctor.map(|index| (self.local_def_id(index), vdata.ctor_kind))
             }
             _ => None,
@@ -1347,18 +1324,22 @@ fn exported_symbols(
     }
 
     fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef {
-        match self.kind(id) {
-            EntryKind::MacroDef(mac_args, macro_rules) => {
-                ast::MacroDef { body: P(mac_args.decode((self, sess))), macro_rules }
+        match self.def_kind(id) {
+            DefKind::Macro(_) => {
+                let macro_rules = self.root.tables.macro_rules.get(self, id).is_some();
+                let body =
+                    self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess));
+                ast::MacroDef { macro_rules, body: ast::ptr::P(body) }
             }
             _ => bug!(),
         }
     }
 
     fn is_foreign_item(self, id: DefIndex) -> bool {
-        match self.kind(id) {
-            EntryKind::ForeignStatic | EntryKind::ForeignFn => true,
-            _ => false,
+        if let Some(parent) = self.def_key(id).parent {
+            matches!(self.def_kind(parent), DefKind::ForeignMod)
+        } else {
+            false
         }
     }
 
index 643294cace43bd4f2fd53631a8c17e9c47ee04ba..6b447ebd99910ae21f348d34728e24b00095168f 100644 (file)
@@ -199,6 +199,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
     codegen_fn_attrs => { table }
     impl_trait_ref => { table }
     const_param_default => { table }
+    object_lifetime_default => { table }
     thir_abstract_const => { table }
     optimized_mir => { table }
     mir_for_ctfe => { table }
@@ -232,7 +233,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
     associated_item_def_ids => {
         tcx.arena.alloc_from_iter(cdata.get_associated_item_def_ids(def_id.index, tcx.sess))
     }
-    associated_item => { cdata.get_associated_item(def_id.index) }
+    associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) }
     inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
     is_foreign_item => { cdata.is_foreign_item(def_id.index) }
     item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) }
@@ -534,8 +535,8 @@ pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
         )
     }
 
-    pub fn fn_has_self_parameter_untracked(&self, def: DefId) -> bool {
-        self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index)
+    pub fn fn_has_self_parameter_untracked(&self, def: DefId, sess: &Session) -> bool {
+        self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index, sess)
     }
 
     pub fn crate_source_untracked(&self, cnum: CrateNum) -> Lrc<CrateSource> {
index cd5da40150d4e15ba1fb896c5fe1af6fdb7d7f90..8dc5ed2db7e494190f9a51952dc1b32516798160 100644 (file)
@@ -1,3 +1,4 @@
+use crate::errors::{FailCreateFileEncoder, FailSeekFile, FailWriteFile};
 use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
 use crate::rmeta::table::TableBuilder;
 use crate::rmeta::*;
@@ -16,7 +17,6 @@
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::lang_items;
-use rustc_hir::{AnonConst, GenericParamKind};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::{
@@ -44,7 +44,6 @@
 use std::iter;
 use std::num::NonZeroUsize;
 use std::path::{Path, PathBuf};
-use tracing::{debug, trace};
 
 pub(super) struct EncodeContext<'a, 'tcx> {
     opaque: opaque::FileEncoder,
@@ -1020,6 +1019,89 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
     }
 }
 
+fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> bool {
+    match def_kind {
+        DefKind::Struct
+        | DefKind::Union
+        | DefKind::Enum
+        | DefKind::Variant
+        | DefKind::Ctor(..)
+        | DefKind::Field
+        | DefKind::Fn
+        | DefKind::Const
+        | DefKind::Static(..)
+        | DefKind::TyAlias
+        | DefKind::OpaqueTy
+        | DefKind::ForeignTy
+        | DefKind::Impl
+        | DefKind::AssocFn
+        | DefKind::AssocConst
+        | DefKind::Closure
+        | DefKind::Generator
+        | DefKind::ConstParam
+        | DefKind::AnonConst
+        | DefKind::InlineConst => true,
+
+        DefKind::AssocTy => {
+            let assoc_item = tcx.associated_item(def_id);
+            match assoc_item.container {
+                ty::AssocItemContainer::ImplContainer => true,
+                ty::AssocItemContainer::TraitContainer => assoc_item.defaultness(tcx).has_value(),
+            }
+        }
+        DefKind::TyParam => {
+            let hir::Node::GenericParam(param) = tcx.hir().get_by_def_id(def_id) else { bug!() };
+            let hir::GenericParamKind::Type { default, .. } = param.kind else { bug!() };
+            default.is_some()
+        }
+
+        DefKind::Trait
+        | DefKind::TraitAlias
+        | DefKind::Mod
+        | DefKind::ForeignMod
+        | DefKind::Macro(..)
+        | DefKind::Use
+        | DefKind::LifetimeParam
+        | DefKind::GlobalAsm
+        | DefKind::ExternCrate => false,
+    }
+}
+
+fn should_encode_const(def_kind: DefKind) -> bool {
+    match def_kind {
+        DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => true,
+
+        DefKind::Struct
+        | DefKind::Union
+        | DefKind::Enum
+        | DefKind::Variant
+        | DefKind::Ctor(..)
+        | DefKind::Field
+        | DefKind::Fn
+        | DefKind::Static(..)
+        | DefKind::TyAlias
+        | DefKind::OpaqueTy
+        | DefKind::ForeignTy
+        | DefKind::Impl
+        | DefKind::AssocFn
+        | DefKind::Closure
+        | DefKind::Generator
+        | DefKind::ConstParam
+        | DefKind::InlineConst
+        | DefKind::AssocTy
+        | DefKind::TyParam
+        | DefKind::Trait
+        | DefKind::TraitAlias
+        | DefKind::Mod
+        | DefKind::ForeignMod
+        | DefKind::Macro(..)
+        | DefKind::Use
+        | DefKind::LifetimeParam
+        | DefKind::GlobalAsm
+        | DefKind::ExternCrate => false,
+    }
+}
+
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     fn encode_attrs(&mut self, def_id: LocalDefId) {
         let mut attrs = self
@@ -1045,7 +1127,8 @@ fn encode_def_ids(&mut self) {
             let def_kind = tcx.opt_def_kind(local_id);
             let Some(def_kind) = def_kind else { continue };
             self.tables.opt_def_kind.set(def_id.index, def_kind);
-            record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
+            let def_span = tcx.def_span(local_id);
+            record!(self.tables.def_span[def_id] <- def_span);
             self.encode_attrs(local_id);
             record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
             if let Some(ident_span) = tcx.def_ident_span(def_id) {
@@ -1076,6 +1159,14 @@ fn encode_def_ids(&mut self) {
                     record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
                 }
             }
+            if should_encode_type(tcx, local_id, def_kind) {
+                record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id));
+            }
+            if let DefKind::TyParam | DefKind::ConstParam = def_kind {
+                if let Some(default) = self.tcx.object_lifetime_default(def_id) {
+                    record!(self.tables.object_lifetime_default[def_id] <- default);
+                }
+            }
             if let DefKind::Trait | DefKind::TraitAlias = def_kind {
                 record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
             }
@@ -1092,11 +1183,6 @@ fn encode_def_ids(&mut self) {
         }
     }
 
-    fn encode_item_type(&mut self, def_id: DefId) {
-        debug!("EncodeContext::encode_item_type({:?})", def_id);
-        record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id));
-    }
-
     fn encode_enum_variant_info(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) {
         let tcx = self.tcx;
         let variant = &def.variant(index);
@@ -1110,13 +1196,12 @@ fn encode_enum_variant_info(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx)
             is_non_exhaustive: variant.is_field_list_non_exhaustive(),
         };
 
-        record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
+        record!(self.tables.variant_data[def_id] <- data);
         self.tables.constness.set(def_id.index, hir::Constness::Const);
         record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
             assert!(f.did.is_local());
             f.did.index
         }));
-        self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
             if let Some(ctor_def_id) = variant.ctor_def_id {
@@ -1139,9 +1224,8 @@ fn encode_enum_variant_ctor(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx)
             is_non_exhaustive: variant.is_field_list_non_exhaustive(),
         };
 
-        record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
+        record!(self.tables.variant_data[def_id] <- data);
         self.tables.constness.set(def_id.index, hir::Constness::Const);
-        self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
         }
@@ -1158,15 +1242,12 @@ fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
         // code uses it). However, we skip encoding anything relating to child
         // items - we encode information about proc-macros later on.
         let reexports = if !self.is_proc_macro {
-            match tcx.module_reexports(local_def_id) {
-                Some(exports) => self.lazy_array(exports),
-                _ => LazyArray::empty(),
-            }
+            tcx.module_reexports(local_def_id).unwrap_or(&[])
         } else {
-            LazyArray::empty()
+            &[]
         };
 
-        record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports));
+        record_array!(self.tables.module_reexports[def_id] <- reexports);
         if self.is_proc_macro {
             // Encode this here because we don't do it in encode_def_ids.
             record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
@@ -1194,22 +1275,6 @@ fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
         }
     }
 
-    fn encode_field(
-        &mut self,
-        adt_def: ty::AdtDef<'tcx>,
-        variant_index: VariantIdx,
-        field_index: usize,
-    ) {
-        let variant = &adt_def.variant(variant_index);
-        let field = &variant.fields[field_index];
-
-        let def_id = field.did;
-        debug!("EncodeContext::encode_field({:?})", def_id);
-
-        record!(self.tables.kind[def_id] <- EntryKind::Field);
-        self.encode_item_type(def_id);
-    }
-
     fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>, def_id: DefId) {
         debug!("EncodeContext::encode_struct_ctor({:?})", def_id);
         let tcx = self.tcx;
@@ -1223,9 +1288,8 @@ fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>, def_id: DefId) {
         };
 
         record!(self.tables.repr_options[def_id] <- adt_def.repr());
+        record!(self.tables.variant_data[def_id] <- data);
         self.tables.constness.set(def_id.index, hir::Constness::Const);
-        record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data)));
-        self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
         }
@@ -1246,18 +1310,10 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) {
         let ast_item = tcx.hir().expect_trait_item(def_id.expect_local());
         self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
         let trait_item = tcx.associated_item(def_id);
+        self.tables.assoc_container.set(def_id.index, trait_item.container);
 
         match trait_item.kind {
-            ty::AssocKind::Const => {
-                let rendered = rustc_hir_pretty::to_string(
-                    &(&self.tcx.hir() as &dyn intravisit::Map<'_>),
-                    |s| s.print_trait_item(ast_item),
-                );
-
-                record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::TraitContainer));
-                record!(self.tables.mir_const_qualif[def_id] <- mir::ConstQualifs::default());
-                record!(self.tables.rendered_const[def_id] <- rendered);
-            }
+            ty::AssocKind::Const => {}
             ty::AssocKind::Fn => {
                 let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind else { bug!() };
                 match *m {
@@ -1270,24 +1326,9 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) {
                 };
                 self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
                 self.tables.constness.set(def_id.index, hir::Constness::NotConst);
-                record!(self.tables.kind[def_id] <- EntryKind::AssocFn {
-                    container: ty::AssocItemContainer::TraitContainer,
-                    has_self: trait_item.fn_has_self_parameter,
-                });
             }
             ty::AssocKind::Type => {
                 self.encode_explicit_item_bounds(def_id);
-                record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::TraitContainer));
-            }
-        }
-        match trait_item.kind {
-            ty::AssocKind::Const | ty::AssocKind::Fn => {
-                self.encode_item_type(def_id);
-            }
-            ty::AssocKind::Type => {
-                if ast_item.defaultness.has_value() {
-                    self.encode_item_type(def_id);
-                }
             }
         }
         if trait_item.kind == ty::AssocKind::Fn {
@@ -1302,20 +1343,9 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
         let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
         self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
         let impl_item = self.tcx.associated_item(def_id);
+        self.tables.assoc_container.set(def_id.index, impl_item.container);
 
         match impl_item.kind {
-            ty::AssocKind::Const => {
-                if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind {
-                    let qualifs = self.tcx.at(ast_item.span).mir_const_qualif(def_id);
-                    let const_data = self.encode_rendered_const_for_body(body_id);
-
-                    record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::ImplContainer));
-                    record!(self.tables.mir_const_qualif[def_id] <- qualifs);
-                    record!(self.tables.rendered_const[def_id] <- const_data);
-                } else {
-                    bug!()
-                }
-            }
             ty::AssocKind::Fn => {
                 let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
                 self.tables.asyncness.set(def_id.index, sig.header.asyncness);
@@ -1327,16 +1357,9 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
                     hir::Constness::NotConst
                 };
                 self.tables.constness.set(def_id.index, constness);
-                record!(self.tables.kind[def_id] <- EntryKind::AssocFn {
-                    container: ty::AssocItemContainer::ImplContainer,
-                    has_self: impl_item.fn_has_self_parameter,
-                });
-            }
-            ty::AssocKind::Type => {
-                record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::ImplContainer));
             }
+            ty::AssocKind::Const | ty::AssocKind::Type => {}
         }
-        self.encode_item_type(def_id);
         if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
             self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into());
         }
@@ -1353,12 +1376,13 @@ fn encode_mir(&mut self) {
             return;
         }
 
-        let keys_and_jobs = self
-            .tcx
+        let tcx = self.tcx;
+
+        let keys_and_jobs = tcx
             .mir_keys(())
             .iter()
             .filter_map(|&def_id| {
-                let (encode_const, encode_opt) = should_encode_mir(self.tcx, def_id);
+                let (encode_const, encode_opt) = should_encode_mir(tcx, def_id);
                 if encode_const || encode_opt {
                     Some((def_id, encode_const, encode_opt))
                 } else {
@@ -1371,22 +1395,32 @@ fn encode_mir(&mut self) {
 
             debug!("EntryBuilder::encode_mir({:?})", def_id);
             if encode_opt {
-                record!(self.tables.optimized_mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
+                record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id));
             }
             if encode_const {
-                record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
+                record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id));
 
                 // FIXME(generic_const_exprs): this feels wrong to have in `encode_mir`
-                let abstract_const = self.tcx.thir_abstract_const(def_id);
+                let abstract_const = tcx.thir_abstract_const(def_id);
                 if let Ok(Some(abstract_const)) = abstract_const {
                     record!(self.tables.thir_abstract_const[def_id.to_def_id()] <- abstract_const);
                 }
+
+                if should_encode_const(tcx.def_kind(def_id)) {
+                    let qualifs = tcx.mir_const_qualif(def_id);
+                    record!(self.tables.mir_const_qualif[def_id.to_def_id()] <- qualifs);
+                    let body_id = tcx.hir().maybe_body_owned_by(def_id);
+                    if let Some(body_id) = body_id {
+                        let const_data = self.encode_rendered_const_for_body(body_id);
+                        record!(self.tables.rendered_const[def_id.to_def_id()] <- const_data);
+                    }
+                }
             }
-            record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
+            record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id));
 
             let instance =
                 ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id()));
-            let unused = self.tcx.unused_generic_params(instance);
+            let unused = tcx.unused_generic_params(instance);
             if !unused.is_empty() {
                 record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
             }
@@ -1449,38 +1483,27 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
 
         debug!("EncodeContext::encode_info_for_item({:?})", def_id);
 
-        let entry_kind = match item.kind {
-            hir::ItemKind::Static(..) => EntryKind::Static,
-            hir::ItemKind::Const(_, body_id) => {
-                let qualifs = self.tcx.at(item.span).mir_const_qualif(def_id);
-                let const_data = self.encode_rendered_const_for_body(body_id);
-                record!(self.tables.mir_const_qualif[def_id] <- qualifs);
-                record!(self.tables.rendered_const[def_id] <- const_data);
-                EntryKind::Const
-            }
+        match item.kind {
             hir::ItemKind::Fn(ref sig, .., body) => {
                 self.tables.asyncness.set(def_id.index, sig.header.asyncness);
                 record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
                 self.tables.constness.set(def_id.index, sig.header.constness);
-                EntryKind::Fn
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
-                EntryKind::MacroDef(self.lazy(&*macro_def.body), macro_def.macro_rules)
+                if macro_def.macro_rules {
+                    self.tables.macro_rules.set(def_id.index, ());
+                }
+                record!(self.tables.macro_definition[def_id] <- &*macro_def.body);
             }
             hir::ItemKind::Mod(ref m) => {
                 return self.encode_info_for_mod(item.def_id, m);
             }
-            hir::ItemKind::ForeignMod { .. } => EntryKind::ForeignMod,
-            hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm,
-            hir::ItemKind::TyAlias(..) => EntryKind::Type,
             hir::ItemKind::OpaqueTy(..) => {
                 self.encode_explicit_item_bounds(def_id);
-                EntryKind::OpaqueTy
             }
             hir::ItemKind::Enum(..) => {
                 let adt_def = self.tcx.adt_def(def_id);
                 record!(self.tables.repr_options[def_id] <- adt_def.repr());
-                EntryKind::Enum
             }
             hir::ItemKind::Struct(ref struct_def, _) => {
                 let adt_def = self.tcx.adt_def(def_id);
@@ -1495,24 +1518,24 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
                     .map(|ctor_hir_id| self.tcx.hir().local_def_id(ctor_hir_id).local_def_index);
 
                 let variant = adt_def.non_enum_variant();
-                EntryKind::Struct(self.lazy(VariantData {
+                record!(self.tables.variant_data[def_id] <- VariantData {
                     ctor_kind: variant.ctor_kind,
                     discr: variant.discr,
                     ctor,
                     is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-                }))
+                });
             }
             hir::ItemKind::Union(..) => {
                 let adt_def = self.tcx.adt_def(def_id);
                 record!(self.tables.repr_options[def_id] <- adt_def.repr());
 
                 let variant = adt_def.non_enum_variant();
-                EntryKind::Union(self.lazy(VariantData {
+                record!(self.tables.variant_data[def_id] <- VariantData {
                     ctor_kind: variant.ctor_kind,
                     discr: variant.discr,
                     ctor: None,
                     is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-                }))
+                });
             }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
                 self.tables.impl_defaultness.set(def_id.index, *defaultness);
@@ -1538,26 +1561,24 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
 
                 let polarity = self.tcx.impl_polarity(def_id);
                 self.tables.impl_polarity.set(def_id.index, polarity);
-
-                EntryKind::Impl
             }
             hir::ItemKind::Trait(..) => {
                 let trait_def = self.tcx.trait_def(def_id);
                 record!(self.tables.trait_def[def_id] <- trait_def);
-
-                EntryKind::Trait
             }
             hir::ItemKind::TraitAlias(..) => {
                 let trait_def = self.tcx.trait_def(def_id);
                 record!(self.tables.trait_def[def_id] <- trait_def);
-
-                EntryKind::TraitAlias
             }
             hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {
                 bug!("cannot encode info for item {:?}", item)
             }
+            hir::ItemKind::Static(..)
+            | hir::ItemKind::Const(..)
+            | hir::ItemKind::ForeignMod { .. }
+            | hir::ItemKind::GlobalAsm(..)
+            | hir::ItemKind::TyAlias(..) => {}
         };
-        record!(self.tables.kind[def_id] <- entry_kind);
         // FIXME(eddyb) there should be a nicer way to do this.
         match item.kind {
             hir::ItemKind::Enum(..) => record_array!(self.tables.children[def_id] <-
@@ -1585,18 +1606,6 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
             }
             _ => {}
         }
-        match item.kind {
-            hir::ItemKind::Static(..)
-            | hir::ItemKind::Const(..)
-            | hir::ItemKind::Fn(..)
-            | hir::ItemKind::TyAlias(..)
-            | hir::ItemKind::OpaqueTy(..)
-            | hir::ItemKind::Enum(..)
-            | hir::ItemKind::Struct(..)
-            | hir::ItemKind::Union(..)
-            | hir::ItemKind::Impl { .. } => self.encode_item_type(def_id),
-            _ => {}
-        }
         if let hir::ItemKind::Fn(..) = item.kind {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
             if tcx.is_intrinsic(def_id) {
@@ -1608,12 +1617,43 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
                 record!(self.tables.impl_trait_ref[def_id] <- trait_ref);
             }
         }
-    }
+        // In some cases, along with the item itself, we also
+        // encode some sub-items. Usually we want some info from the item
+        // so it's easier to do that here then to wait until we would encounter
+        // normally in the visitor walk.
+        match item.kind {
+            hir::ItemKind::Enum(..) => {
+                let def = self.tcx.adt_def(item.def_id.to_def_id());
+                for (i, variant) in def.variants().iter_enumerated() {
+                    self.encode_enum_variant_info(def, i);
 
-    fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, encode_type: bool) {
-        record!(self.tables.kind[def_id] <- kind);
-        if encode_type {
-            self.encode_item_type(def_id);
+                    if let Some(_ctor_def_id) = variant.ctor_def_id {
+                        self.encode_enum_variant_ctor(def, i);
+                    }
+                }
+            }
+            hir::ItemKind::Struct(ref struct_def, _) => {
+                let def = self.tcx.adt_def(item.def_id.to_def_id());
+                // If the struct has a constructor, encode it.
+                if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
+                    let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
+                    self.encode_struct_ctor(def, ctor_def_id.to_def_id());
+                }
+            }
+            hir::ItemKind::Impl { .. } => {
+                for &trait_item_def_id in
+                    self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
+                {
+                    self.encode_info_for_impl_item(trait_item_def_id);
+                }
+            }
+            hir::ItemKind::Trait(..) => {
+                for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
+                {
+                    self.encode_info_for_trait_item(item_def_id);
+                }
+            }
+            _ => {}
         }
     }
 
@@ -1628,34 +1668,16 @@ fn encode_info_for_closure(&mut self, hir_id: hir::HirId) {
             ty::Generator(..) => {
                 let data = self.tcx.generator_kind(def_id).unwrap();
                 let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data();
-                record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Generator);
                 record!(self.tables.generator_kind[def_id.to_def_id()] <- data);
                 record!(self.tables.generator_diagnostic_data[def_id.to_def_id()]  <- generator_diagnostic_data);
             }
 
-            ty::Closure(..) => {
-                record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Closure);
+            ty::Closure(_, substs) => {
+                record!(self.tables.fn_sig[def_id.to_def_id()] <- substs.as_closure().sig());
             }
 
             _ => bug!("closure that is neither generator nor closure"),
         }
-        self.encode_item_type(def_id.to_def_id());
-        if let ty::Closure(def_id, substs) = *ty.kind() {
-            record!(self.tables.fn_sig[def_id] <- substs.as_closure().sig());
-        }
-    }
-
-    fn encode_info_for_anon_const(&mut self, id: hir::HirId) {
-        let def_id = self.tcx.hir().local_def_id(id);
-        debug!("EncodeContext::encode_info_for_anon_const({:?})", def_id);
-        let body_id = self.tcx.hir().body_owned_by(def_id);
-        let const_data = self.encode_rendered_const_for_body(body_id);
-        let qualifs = self.tcx.mir_const_qualif(def_id);
-
-        record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst);
-        record!(self.tables.mir_const_qualif[def_id.to_def_id()] <- qualifs);
-        record!(self.tables.rendered_const[def_id.to_def_id()] <- const_data);
-        self.encode_item_type(def_id.to_def_id());
     }
 
     fn encode_native_libraries(&mut self) -> LazyArray<NativeLib> {
@@ -1753,7 +1775,7 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
 
                 let def_id = id.to_def_id();
                 self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind));
-                record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
+                self.tables.proc_macro.set(def_id.index, macro_kind);
                 self.encode_attrs(id);
                 record!(self.tables.def_keys[def_id] <- def_key);
                 record!(self.tables.def_ident_span[def_id] <- span);
@@ -1991,18 +2013,11 @@ fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignIt
                     hir::Constness::NotConst
                 };
                 self.tables.constness.set(def_id.index, constness);
-                record!(self.tables.kind[def_id] <- EntryKind::ForeignFn);
-            }
-            hir::ForeignItemKind::Static(..) => {
-                record!(self.tables.kind[def_id] <- EntryKind::ForeignStatic);
-            }
-            hir::ForeignItemKind::Type => {
-                record!(self.tables.kind[def_id] <- EntryKind::ForeignType);
+                record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
             }
+            hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => {}
         }
-        self.encode_item_type(def_id);
         if let hir::ForeignItemKind::Fn(..) = nitem.kind {
-            record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
             if tcx.is_intrinsic(def_id) {
                 self.tables.is_intrinsic.set(def_id.index, ());
             }
@@ -2021,17 +2036,12 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         intravisit::walk_expr(self, ex);
         self.encode_info_for_expr(ex);
     }
-    fn visit_anon_const(&mut self, c: &'tcx AnonConst) {
-        intravisit::walk_anon_const(self, c);
-        self.encode_info_for_anon_const(c.hir_id);
-    }
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         intravisit::walk_item(self, item);
         match item.kind {
             hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these
             _ => self.encode_info_for_item(item.def_id.to_def_id(), item),
         }
-        self.encode_addl_info_for_item(item);
     }
     fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) {
         intravisit::walk_foreign_item(self, ni);
@@ -2044,29 +2054,13 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
 }
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
-    fn encode_fields(&mut self, adt_def: ty::AdtDef<'tcx>) {
-        for (variant_index, variant) in adt_def.variants().iter_enumerated() {
-            for (field_index, _field) in variant.fields.iter().enumerate() {
-                self.encode_field(adt_def, variant_index, field_index);
-            }
-        }
-    }
-
     fn encode_info_for_generics(&mut self, generics: &hir::Generics<'tcx>) {
         for param in generics.params {
             let def_id = self.tcx.hir().local_def_id(param.hir_id);
             match param.kind {
-                GenericParamKind::Lifetime { .. } => continue,
-                GenericParamKind::Type { default, .. } => {
-                    self.encode_info_for_generic_param(
-                        def_id.to_def_id(),
-                        EntryKind::TypeParam,
-                        default.is_some(),
-                    );
-                }
-                GenericParamKind::Const { ref default, .. } => {
+                hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => {}
+                hir::GenericParamKind::Const { ref default, .. } => {
                     let def_id = def_id.to_def_id();
-                    self.encode_info_for_generic_param(def_id, EntryKind::ConstParam, true);
                     if default.is_some() {
                         record!(self.tables.const_param_default[def_id] <- self.tcx.const_param_default(def_id))
                     }
@@ -2080,68 +2074,6 @@ fn encode_info_for_expr(&mut self, expr: &hir::Expr<'_>) {
             self.encode_info_for_closure(expr.hir_id);
         }
     }
-
-    /// In some cases, along with the item itself, we also
-    /// encode some sub-items. Usually we want some info from the item
-    /// so it's easier to do that here then to wait until we would encounter
-    /// normally in the visitor walk.
-    fn encode_addl_info_for_item(&mut self, item: &hir::Item<'_>) {
-        match item.kind {
-            hir::ItemKind::Static(..)
-            | hir::ItemKind::Const(..)
-            | hir::ItemKind::Fn(..)
-            | hir::ItemKind::Macro(..)
-            | hir::ItemKind::Mod(..)
-            | hir::ItemKind::ForeignMod { .. }
-            | hir::ItemKind::GlobalAsm(..)
-            | hir::ItemKind::ExternCrate(..)
-            | hir::ItemKind::Use(..)
-            | hir::ItemKind::TyAlias(..)
-            | hir::ItemKind::OpaqueTy(..)
-            | hir::ItemKind::TraitAlias(..) => {
-                // no sub-item recording needed in these cases
-            }
-            hir::ItemKind::Enum(..) => {
-                let def = self.tcx.adt_def(item.def_id.to_def_id());
-                self.encode_fields(def);
-
-                for (i, variant) in def.variants().iter_enumerated() {
-                    self.encode_enum_variant_info(def, i);
-
-                    if let Some(_ctor_def_id) = variant.ctor_def_id {
-                        self.encode_enum_variant_ctor(def, i);
-                    }
-                }
-            }
-            hir::ItemKind::Struct(ref struct_def, _) => {
-                let def = self.tcx.adt_def(item.def_id.to_def_id());
-                self.encode_fields(def);
-
-                // If the struct has a constructor, encode it.
-                if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
-                    let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
-                    self.encode_struct_ctor(def, ctor_def_id.to_def_id());
-                }
-            }
-            hir::ItemKind::Union(..) => {
-                let def = self.tcx.adt_def(item.def_id.to_def_id());
-                self.encode_fields(def);
-            }
-            hir::ItemKind::Impl { .. } => {
-                for &trait_item_def_id in
-                    self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
-                {
-                    self.encode_info_for_impl_item(trait_item_def_id);
-                }
-            }
-            hir::ItemKind::Trait(..) => {
-                for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
-                {
-                    self.encode_info_for_trait_item(item_def_id);
-                }
-            }
-        }
-    }
 }
 
 /// Used to prefetch queries which will be needed later by metadata encoding.
@@ -2264,7 +2196,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) {
 
 fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) {
     let mut encoder = opaque::FileEncoder::new(path)
-        .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to create file encoder: {}", err)));
+        .unwrap_or_else(|err| tcx.sess.emit_fatal(FailCreateFileEncoder { err }));
     encoder.emit_raw_bytes(METADATA_HEADER);
 
     // Will be filled with the root position after encoding everything.
@@ -2309,10 +2241,10 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) {
     // Encode the root position.
     let header = METADATA_HEADER.len();
     file.seek(std::io::SeekFrom::Start(header as u64))
-        .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to seek the file: {}", err)));
+        .unwrap_or_else(|err| tcx.sess.emit_fatal(FailSeekFile { err }));
     let pos = root.position.get();
     file.write_all(&[(pos >> 24) as u8, (pos >> 16) as u8, (pos >> 8) as u8, (pos >> 0) as u8])
-        .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to write to the file: {}", err)));
+        .unwrap_or_else(|err| tcx.sess.emit_fatal(FailWriteFile { err }));
 
     // Return to the position where we are before writing the root position.
     file.seek(std::io::SeekFrom::Start(pos_before_seek)).unwrap();
index e6cceaf29d51f08172195392ca89b90d79a6bced..6f849a58580e679550216f06ff690d75e11a8a8f 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
+use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc_middle::mir;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::Providers;
@@ -333,7 +334,6 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
 }
 
 define_tables! {
-    kind: Table<DefIndex, LazyValue<EntryKind>>,
     attributes: Table<DefIndex, LazyArray<ast::Attribute>>,
     children: Table<DefIndex, LazyArray<DefIndex>>,
 
@@ -358,6 +358,7 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
     impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'static>>>,
     const_param_default: Table<DefIndex, LazyValue<rustc_middle::ty::Const<'static>>>,
+    object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
     optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
     mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
     promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,
@@ -391,39 +392,13 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     proc_macro_quoted_spans: Table<usize, LazyValue<Span>>,
     generator_diagnostic_data: Table<DefIndex, LazyValue<GeneratorDiagnosticData<'static>>>,
     may_have_doc_links: Table<DefIndex, ()>,
-}
-
-#[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)]
-enum EntryKind {
-    AnonConst,
-    Const,
-    Static,
-    ForeignStatic,
-    ForeignMod,
-    ForeignType,
-    GlobalAsm,
-    Type,
-    TypeParam,
-    ConstParam,
-    OpaqueTy,
-    Enum,
-    Field,
-    Variant(LazyValue<VariantData>),
-    Struct(LazyValue<VariantData>),
-    Union(LazyValue<VariantData>),
-    Fn,
-    ForeignFn,
-    Mod(LazyArray<ModChild>),
-    MacroDef(LazyValue<ast::MacArgs>, /*macro_rules*/ bool),
-    ProcMacro(MacroKind),
-    Closure,
-    Generator,
-    Trait,
-    Impl,
-    AssocFn { container: ty::AssocItemContainer, has_self: bool },
-    AssocType(ty::AssocItemContainer),
-    AssocConst(ty::AssocItemContainer),
-    TraitAlias,
+    variant_data: Table<DefIndex, LazyValue<VariantData>>,
+    assoc_container: Table<DefIndex, ty::AssocItemContainer>,
+    // Slot is full when macro is macro_rules.
+    macro_rules: Table<DefIndex, ()>,
+    macro_definition: Table<DefIndex, LazyValue<ast::MacArgs>>,
+    proc_macro: Table<DefIndex, MacroKind>,
+    module_reexports: Table<DefIndex, LazyArray<ModChild>>,
 }
 
 #[derive(TyEncodable, TyDecodable)]
@@ -457,7 +432,6 @@ pub fn provide(providers: &mut Providers) {
 
 trivially_parameterized_over_tcx! {
     VariantData,
-    EntryKind,
     RawDefId,
     TraitImpls,
     IncoherentImpls,
index 21841ae2532a7b913f1da7b901c1417ae091cc84..d5f151f0ed8e50a4116de32d27be14044bf589eb 100644 (file)
@@ -10,7 +10,6 @@
 use std::convert::TryInto;
 use std::marker::PhantomData;
 use std::num::NonZeroUsize;
-use tracing::debug;
 
 /// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
 /// Used mainly for Lazy positions and lengths.
@@ -51,7 +50,7 @@ impl FixedSizeEncoding for Option<$ty> {
                 }
                 match b[0] - 1 {
                     $(${index()} => Some($($pat)*),)*
-                    _ => panic!("Unexpected ImplPolarity code: {:?}", b[0]),
+                    _ => panic!("Unexpected {} code: {:?}", stringify!($ty), b[0]),
                 }
             }
 
@@ -141,6 +140,21 @@ impl FixedSizeEncoding for Option<$ty> {
     }
 }
 
+fixed_size_enum! {
+    ty::AssocItemContainer {
+        ( TraitContainer )
+        ( ImplContainer  )
+    }
+}
+
+fixed_size_enum! {
+    MacroKind {
+        ( Attr   )
+        ( Bang   )
+        ( Derive )
+    }
+}
+
 // We directly encode `DefPathHash` because a `LazyValue` would incur a 25% cost.
 impl FixedSizeEncoding for Option<DefPathHash> {
     type ByteArray = [u8; 16];
index 008d2c7091c1ea56ef61e1e580b3db46c2520621..cca17a4eccd3afc52243554f13277b9006f8fd44 100644 (file)
@@ -7,34 +7,35 @@ edition = "2021"
 doctest = false
 
 [dependencies]
-rustc_arena = { path = "../rustc_arena" }
 bitflags = "1.2.1"
+chalk-ir = "0.80.0"
 either = "1.5.0"
 gsgdt = "0.1.2"
-tracing = "0.1"
-rustc-rayon = { version = "0.4.0", optional = true }
-rustc-rayon-core = { version = "0.4.0", optional = true }
 polonius-engine = "0.13.0"
+rand = "0.8.4"
+rand_xoshiro = "0.6.0"
 rustc_apfloat = { path = "../rustc_apfloat" }
+rustc_arena = { path = "../rustc_arena" }
+rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
-rustc_feature = { path = "../rustc_feature" }
-rustc_hir = { path = "../rustc_hir" }
-rustc_target = { path = "../rustc_target" }
-rustc_macros = { path = "../rustc_macros" }
 rustc_data_structures = { path = "../rustc_data_structures" }
-rustc_query_system = { path = "../rustc_query_system" }
 rustc_errors = { path = "../rustc_errors" }
+rustc_feature = { path = "../rustc_feature" }
 rustc_graphviz = { path = "../rustc_graphviz" }
+rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_query_system = { path = "../rustc_query_system" }
+rustc-rayon-core = { version = "0.4.0", optional = true }
+rustc-rayon = { version = "0.4.0", optional = true }
 rustc_serialize = { path = "../rustc_serialize" }
-rustc_ast = { path = "../rustc_ast" }
-rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.80.0"
-smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 rustc_session = { path = "../rustc_session" }
+rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
 rustc_type_ir = { path = "../rustc_type_ir" }
-rand = "0.8.4"
-rand_xoshiro = "0.6.0"
+smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+thin-vec = "0.2.8"
+tracing = "0.1"
 
 [features]
 rustc_use_parallel_compiler = ["rustc-rayon", "rustc-rayon-core"]
index b94de537dc81e5525e5c5b14889c496315eee470..65d5f755f72482173aafada909ce89241ff9ebaf 100644 (file)
@@ -100,7 +100,7 @@ macro_rules! arena_types {
             [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>,
             [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
 
-            [] dep_kind: rustc_middle::dep_graph::DepKindStruct,
+            [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>,
         ]);
     )
 }
index 65fc8a2e9cf5a4413e309a96726c9ea85126aae2..7718906ac4ee7976aad733815b6d6637e66ce014 100644 (file)
@@ -74,7 +74,7 @@
 /// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
 /// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
 /// jump table instead of large matches.
-pub struct DepKindStruct {
+pub struct DepKindStruct<'tcx> {
     /// Anonymous queries cannot be replayed from one compiler invocation to the next.
     /// When their result is needed, it is recomputed. They are useful for fine-grained
     /// dependency tracking, and caching within one compiler invocation.
@@ -124,10 +124,10 @@ pub struct DepKindStruct {
     /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
     /// is actually a `DefPathHash`, and can therefore just look up the corresponding
     /// `DefId` in `tcx.def_path_hash_to_def_id`.
-    pub force_from_dep_node: Option<fn(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool>,
+    pub force_from_dep_node: Option<fn(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool>,
 
     /// Invoke a query to put the on-disk cached value in memory.
-    pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'_>, DepNode)>,
+    pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'tcx>, DepNode)>,
 }
 
 impl DepKind {
index 25c18cf50c11f3663aa19d3ce98fbede33efa959..6217bffb8f76c206b4df1840eb12dd9586c7277a 100644 (file)
@@ -291,6 +291,9 @@ pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
         Some(def_kind)
     }
 
+    /// Finds the id of the parent node to this one.
+    ///
+    /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
     pub fn find_parent_node(self, id: HirId) -> Option<HirId> {
         if id.local_id == ItemLocalId::from_u32(0) {
             Some(self.tcx.hir_owner_parent(id.owner))
@@ -486,7 +489,9 @@ pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId {
         let def_kind = self.tcx.def_kind(def_id);
         match def_kind {
             DefKind::Trait | DefKind::TraitAlias => def_id,
-            DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id),
+            DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => {
+                self.tcx.local_parent(def_id)
+            }
             _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind),
         }
     }
@@ -495,7 +500,9 @@ pub fn ty_param_name(self, def_id: LocalDefId) -> Symbol {
         let def_kind = self.tcx.def_kind(def_id);
         match def_kind {
             DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper,
-            DefKind::TyParam | DefKind::ConstParam => self.tcx.item_name(def_id.to_def_id()),
+            DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => {
+                self.tcx.item_name(def_id.to_def_id())
+            }
             _ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind),
         }
     }
index 6a6505d025663d65a32cb444e2249caf4bef93c5..be9e5865e541c515ee1e1a51574be8bca3461e07 100644 (file)
@@ -39,6 +39,7 @@
 #![feature(extern_types)]
 #![feature(new_uninit)]
 #![feature(once_cell)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(trusted_len)]
index cc9706f2d867cbe6db1bd1d222363e3455ced817..31c20fa14aaf5e819c23f6537fe6298ac2cba740 100644 (file)
@@ -18,11 +18,11 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Returns the `DefId` for a given `LangItem`.
     /// If not found, fatally aborts compilation.
     pub fn require_lang_item(self, lang_item: LangItem, span: Option<Span>) -> DefId {
-        self.lang_items().require(lang_item).unwrap_or_else(|msg| {
+        self.lang_items().require(lang_item).unwrap_or_else(|err| {
             if let Some(span) = span {
-                self.sess.span_fatal(span, &msg)
+                self.sess.span_fatal(span, err.to_string())
             } else {
-                self.sess.fatal(&msg)
+                self.sess.fatal(err.to_string())
             }
         })
     }
index 9b2f44567053225e81a7b2f6c19d71a0819b0d26..a171f5711dcffd3304c86dc958f8651aecbcebd6 100644 (file)
@@ -10,7 +10,7 @@
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
 pub enum Region {
     Static,
-    EarlyBound(/* index */ u32, /* lifetime decl */ DefId),
+    EarlyBound(/* lifetime decl */ DefId),
     LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* lifetime decl */ DefId),
     Free(DefId, /* lifetime decl */ DefId),
 }
@@ -35,7 +35,13 @@ pub fn insert(&mut self, value: T) {
     }
 }
 
-pub type ObjectLifetimeDefault = Set1<Region>;
+#[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)]
+pub enum ObjectLifetimeDefault {
+    Empty,
+    Static,
+    Ambiguous,
+    Param(DefId),
+}
 
 /// Maps the id of each lifetime reference to the lifetime decl
 /// that it corresponds to.
index 78080fcd581f6e0cdca918dd399939a61945d8ca..752cbdeae6b25df2eb76ad53c4db05c3edbfb534 100644 (file)
@@ -86,7 +86,7 @@ pub fn as_mut_preserves_cfg(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockDa
     ///
     /// You will only ever need this if you have also called [`BasicBlocks::as_mut_preserves_cfg`].
     /// All other methods that allow you to mutate the basic blocks also call this method
-    /// themselves, thereby avoiding any risk of accidentaly cache invalidation.
+    /// themselves, thereby avoiding any risk of accidentally cache invalidation.
     pub fn invalidate_cfg_cache(&mut self) {
         self.predecessor_cache.invalidate();
         self.switch_source_cache.invalidate();
index 3f618106525cf90cf3d99c93eef1983dcb13cb0e..37ec04b07f847bc009814d04c51059e1594e247b 100644 (file)
@@ -34,11 +34,11 @@ pub struct Allocation<Prov = AllocId, Extra = ()> {
     /// The actual bytes of the allocation.
     /// Note that the bytes of a pointer represent the offset of the pointer.
     bytes: Box<[u8]>,
-    /// Maps from byte addresses to extra data for each pointer.
+    /// Maps from byte addresses to extra provenance data for each pointer.
     /// Only the first byte of a pointer is inserted into the map; i.e.,
     /// every entry in this map applies to `pointer_size` consecutive bytes starting
     /// at the given offset.
-    relocations: Relocations<Prov>,
+    provenance: ProvenanceMap<Prov>,
     /// Denotes which part of this allocation is initialized.
     init_mask: InitMask,
     /// The alignment of the allocation to detect unaligned reads.
@@ -84,7 +84,7 @@ fn hash<H: hash::Hasher>(&self, state: &mut H) {
         }
 
         // Hash the other fields as usual.
-        self.relocations.hash(state);
+        self.provenance.hash(state);
         self.init_mask.hash(state);
         self.align.hash(state);
         self.mutability.hash(state);
@@ -130,6 +130,8 @@ pub enum AllocError {
     ReadPointerAsBytes,
     /// Partially overwriting a pointer.
     PartialPointerOverwrite(Size),
+    /// Partially copying a pointer.
+    PartialPointerCopy(Size),
     /// Using uninitialized data where it is not allowed.
     InvalidUninitBytes(Option<UninitBytesAccess>),
 }
@@ -152,6 +154,9 @@ pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpError<'tcx> {
             PartialPointerOverwrite(offset) => InterpError::Unsupported(
                 UnsupportedOpInfo::PartialPointerOverwrite(Pointer::new(alloc_id, offset)),
             ),
+            PartialPointerCopy(offset) => InterpError::Unsupported(
+                UnsupportedOpInfo::PartialPointerCopy(Pointer::new(alloc_id, offset)),
+            ),
             InvalidUninitBytes(info) => InterpError::UndefinedBehavior(
                 UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))),
             ),
@@ -211,7 +216,7 @@ pub fn from_bytes<'a>(
         let size = Size::from_bytes(bytes.len());
         Self {
             bytes,
-            relocations: Relocations::new(),
+            provenance: ProvenanceMap::new(),
             init_mask: InitMask::new(size, true),
             align,
             mutability,
@@ -246,7 +251,7 @@ pub fn uninit<'tcx>(size: Size, align: Align, panic_on_fail: bool) -> InterpResu
         let bytes = unsafe { bytes.assume_init() };
         Ok(Allocation {
             bytes,
-            relocations: Relocations::new(),
+            provenance: ProvenanceMap::new(),
             init_mask: InitMask::new(size, false),
             align,
             mutability: Mutability::Mut,
@@ -266,22 +271,22 @@ pub fn adjust_from_tcx<Prov, Extra, Err>(
     ) -> Result<Allocation<Prov, Extra>, Err> {
         // Compute new pointer provenance, which also adjusts the bytes.
         let mut bytes = self.bytes;
-        let mut new_relocations = Vec::with_capacity(self.relocations.0.len());
+        let mut new_provenance = Vec::with_capacity(self.provenance.0.len());
         let ptr_size = cx.data_layout().pointer_size.bytes_usize();
         let endian = cx.data_layout().endian;
-        for &(offset, alloc_id) in self.relocations.iter() {
+        for &(offset, alloc_id) in self.provenance.iter() {
             let idx = offset.bytes_usize();
             let ptr_bytes = &mut bytes[idx..idx + ptr_size];
             let bits = read_target_uint(endian, ptr_bytes).unwrap();
             let (ptr_prov, ptr_offset) =
                 adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts();
             write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap();
-            new_relocations.push((offset, ptr_prov));
+            new_provenance.push((offset, ptr_prov));
         }
         // Create allocation.
         Ok(Allocation {
             bytes,
-            relocations: Relocations::from_presorted(new_relocations),
+            provenance: ProvenanceMap::from_presorted(new_provenance),
             init_mask: self.init_mask,
             align: self.align,
             mutability: self.mutability,
@@ -300,8 +305,8 @@ pub fn size(&self) -> Size {
         Size::from_bytes(self.len())
     }
 
-    /// Looks at a slice which may describe uninitialized bytes or describe a relocation. This differs
-    /// from `get_bytes_with_uninit_and_ptr` in that it does no relocation checks (even on the
+    /// Looks at a slice which may contain uninitialized bytes or provenance. This differs
+    /// from `get_bytes_with_uninit_and_ptr` in that it does no provenance checks (even on the
     /// edges) at all.
     /// This must not be used for reads affecting the interpreter execution.
     pub fn inspect_with_uninit_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] {
@@ -313,74 +318,47 @@ pub fn init_mask(&self) -> &InitMask {
         &self.init_mask
     }
 
-    /// Returns the relocation list.
-    pub fn relocations(&self) -> &Relocations<Prov> {
-        &self.relocations
+    /// Returns the provenance map.
+    pub fn provenance(&self) -> &ProvenanceMap<Prov> {
+        &self.provenance
     }
 }
 
 /// Byte accessors.
 impl<Prov: Provenance, Extra> Allocation<Prov, Extra> {
     /// This is the entirely abstraction-violating way to just grab the raw bytes without
-    /// caring about relocations. It just deduplicates some code between `read_scalar`
-    /// and `get_bytes_internal`.
-    fn get_bytes_even_more_internal(&self, range: AllocRange) -> &[u8] {
-        &self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
-    }
-
-    /// The last argument controls whether we error out when there are uninitialized or pointer
-    /// bytes. However, we *always* error when there are relocations overlapping the edges of the
-    /// range.
-    ///
-    /// You should never call this, call `get_bytes` or `get_bytes_with_uninit_and_ptr` instead,
+    /// caring about provenance or initialization.
     ///
     /// This function also guarantees that the resulting pointer will remain stable
     /// even when new allocations are pushed to the `HashMap`. `mem_copy_repeatedly` relies
     /// on that.
-    ///
-    /// It is the caller's responsibility to check bounds and alignment beforehand.
-    fn get_bytes_internal(
-        &self,
-        cx: &impl HasDataLayout,
-        range: AllocRange,
-        check_init_and_ptr: bool,
-    ) -> AllocResult<&[u8]> {
-        if check_init_and_ptr {
-            self.check_init(range)?;
-            self.check_relocations(cx, range)?;
-        } else {
-            // We still don't want relocations on the *edges*.
-            self.check_relocation_edges(cx, range)?;
-        }
-
-        Ok(self.get_bytes_even_more_internal(range))
+    #[inline]
+    pub fn get_bytes_unchecked(&self, range: AllocRange) -> &[u8] {
+        &self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
     }
 
-    /// Checks that these bytes are initialized and not pointer bytes, and then return them
-    /// as a slice.
+    /// Checks that these bytes are initialized, and then strip provenance (if possible) and return
+    /// them.
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
     /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
     /// on `InterpCx` instead.
     #[inline]
-    pub fn get_bytes(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult<&[u8]> {
-        self.get_bytes_internal(cx, range, true)
-    }
-
-    /// It is the caller's responsibility to handle uninitialized and pointer bytes.
-    /// However, this still checks that there are no relocations on the *edges*.
-    ///
-    /// It is the caller's responsibility to check bounds and alignment beforehand.
-    #[inline]
-    pub fn get_bytes_with_uninit_and_ptr(
+    pub fn get_bytes_strip_provenance(
         &self,
         cx: &impl HasDataLayout,
         range: AllocRange,
     ) -> AllocResult<&[u8]> {
-        self.get_bytes_internal(cx, range, false)
+        self.check_init(range)?;
+        if !Prov::OFFSET_IS_ADDR {
+            if self.range_has_provenance(cx, range) {
+                return Err(AllocError::ReadPointerAsBytes);
+            }
+        }
+        Ok(self.get_bytes_unchecked(range))
     }
 
-    /// Just calling this already marks everything as defined and removes relocations,
+    /// Just calling this already marks everything as defined and removes provenance,
     /// so be sure to actually put data there!
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
@@ -392,7 +370,7 @@ pub fn get_bytes_mut(
         range: AllocRange,
     ) -> AllocResult<&mut [u8]> {
         self.mark_init(range, true);
-        self.clear_relocations(cx, range)?;
+        self.clear_provenance(cx, range)?;
 
         Ok(&mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()])
     }
@@ -404,7 +382,7 @@ pub fn get_bytes_mut_ptr(
         range: AllocRange,
     ) -> AllocResult<*mut [u8]> {
         self.mark_init(range, true);
-        self.clear_relocations(cx, range)?;
+        self.clear_provenance(cx, range)?;
 
         assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check
         let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize());
@@ -415,13 +393,6 @@ pub fn get_bytes_mut_ptr(
 
 /// Reading and writing.
 impl<Prov: Provenance, Extra> Allocation<Prov, Extra> {
-    /// Validates that this memory range is initiailized and contains no relocations.
-    pub fn check_bytes(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
-        // This implicitly does all the checking we are asking for.
-        self.get_bytes(cx, range)?;
-        Ok(())
-    }
-
     /// Reads a *non-ZST* scalar.
     ///
     /// If `read_provenance` is `true`, this will also read provenance; otherwise (if the machine
@@ -438,43 +409,53 @@ pub fn read_scalar(
         range: AllocRange,
         read_provenance: bool,
     ) -> AllocResult<Scalar<Prov>> {
-        if read_provenance {
-            assert_eq!(range.size, cx.data_layout().pointer_size);
-        }
-
         // First and foremost, if anything is uninit, bail.
         if self.is_init(range).is_err() {
             return Err(AllocError::InvalidUninitBytes(None));
         }
 
-        // If we are doing a pointer read, and there is a relocation exactly where we
-        // are reading, then we can put data and relocation back together and return that.
-        if read_provenance && let Some(&prov) = self.relocations.get(&range.start) {
-            // We already checked init and relocations, so we can use this function.
-            let bytes = self.get_bytes_even_more_internal(range);
-            let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
-            let ptr = Pointer::new(prov, Size::from_bytes(bits));
-            return Ok(Scalar::from_pointer(ptr, cx));
-        }
+        // Get the integer part of the result. We HAVE TO check provenance before returning this!
+        let bytes = self.get_bytes_unchecked(range);
+        let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
 
-        // If we are *not* reading a pointer, and we can just ignore relocations,
-        // then do exactly that.
-        if !read_provenance && Prov::OFFSET_IS_ADDR {
-            // We just strip provenance.
-            let bytes = self.get_bytes_even_more_internal(range);
-            let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
-            return Ok(Scalar::from_uint(bits, range.size));
+        if read_provenance {
+            assert_eq!(range.size, cx.data_layout().pointer_size);
+
+            // When reading data with provenance, the easy case is finding provenance exactly where we
+            // are reading, then we can put data and provenance back together and return that.
+            if let Some(&prov) = self.provenance.get(&range.start) {
+                // Now we can return the bits, with their appropriate provenance.
+                let ptr = Pointer::new(prov, Size::from_bytes(bits));
+                return Ok(Scalar::from_pointer(ptr, cx));
+            }
+
+            // If we can work on pointers byte-wise, join the byte-wise provenances.
+            if Prov::OFFSET_IS_ADDR {
+                let mut prov = self.offset_get_provenance(cx, range.start);
+                for offset in 1..range.size.bytes() {
+                    let this_prov =
+                        self.offset_get_provenance(cx, range.start + Size::from_bytes(offset));
+                    prov = Prov::join(prov, this_prov);
+                }
+                // Now use this provenance.
+                let ptr = Pointer::new(prov, Size::from_bytes(bits));
+                return Ok(Scalar::from_maybe_pointer(ptr, cx));
+            }
+        } else {
+            // We are *not* reading a pointer.
+            // If we can just ignore provenance, do exactly that.
+            if Prov::OFFSET_IS_ADDR {
+                // We just strip provenance.
+                return Ok(Scalar::from_uint(bits, range.size));
+            }
         }
 
-        // It's complicated. Better make sure there is no provenance anywhere.
-        // FIXME: If !OFFSET_IS_ADDR, this is the best we can do. But if OFFSET_IS_ADDR, then
-        // `read_pointer` is true and we ideally would distinguish the following two cases:
-        // - The entire `range` is covered by 2 relocations for the same provenance.
-        //   Then we should return a pointer with that provenance.
-        // - The range has inhomogeneous provenance. Then we should return just the
-        //   underlying bits.
-        let bytes = self.get_bytes(cx, range)?;
-        let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
+        // Fallback path for when we cannot treat provenance bytewise or ignore it.
+        assert!(!Prov::OFFSET_IS_ADDR);
+        if self.range_has_provenance(cx, range) {
+            return Err(AllocError::ReadPointerAsBytes);
+        }
+        // There is no provenance, we can just return the bits.
         Ok(Scalar::from_uint(bits, range.size))
     }
 
@@ -508,9 +489,9 @@ pub fn write_scalar(
         let dst = self.get_bytes_mut(cx, range)?;
         write_target_uint(endian, dst, bytes).unwrap();
 
-        // See if we have to also write a relocation.
+        // See if we have to also store some provenance.
         if let Some(provenance) = provenance {
-            self.relocations.0.insert(range.start, provenance);
+            self.provenance.0.insert(range.start, provenance);
         }
 
         Ok(())
@@ -519,64 +500,65 @@ pub fn write_scalar(
     /// Write "uninit" to the given memory range.
     pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
         self.mark_init(range, false);
-        self.clear_relocations(cx, range)?;
+        self.clear_provenance(cx, range)?;
         return Ok(());
     }
 }
 
-/// Relocations.
+/// Provenance.
 impl<Prov: Copy, Extra> Allocation<Prov, Extra> {
-    /// Returns all relocations overlapping with the given pointer-offset pair.
-    fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Prov)] {
+    /// Returns all provenance overlapping with the given pointer-offset pair.
+    fn range_get_provenance(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Prov)] {
         // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
         // the beginning of this range.
         let start = range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1);
-        self.relocations.range(Size::from_bytes(start)..range.end())
+        self.provenance.range(Size::from_bytes(start)..range.end())
     }
 
-    /// Returns whether this allocation has relocations overlapping with the given range.
-    ///
-    /// Note: this function exists to allow `get_relocations` to be private, in order to somewhat
-    /// limit access to relocations outside of the `Allocation` abstraction.
-    ///
-    pub fn has_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> bool {
-        !self.get_relocations(cx, range).is_empty()
+    /// Get the provenance of a single byte.
+    fn offset_get_provenance(&self, cx: &impl HasDataLayout, offset: Size) -> Option<Prov> {
+        let prov = self.range_get_provenance(cx, alloc_range(offset, Size::from_bytes(1)));
+        assert!(prov.len() <= 1);
+        prov.first().map(|(_offset, prov)| *prov)
     }
 
-    /// Checks that there are no relocations overlapping with the given range.
-    #[inline(always)]
-    fn check_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
-        if self.has_relocations(cx, range) { Err(AllocError::ReadPointerAsBytes) } else { Ok(()) }
+    /// Returns whether this allocation has progrnance overlapping with the given range.
+    ///
+    /// Note: this function exists to allow `range_get_provenance` to be private, in order to somewhat
+    /// limit access to provenance outside of the `Allocation` abstraction.
+    ///
+    pub fn range_has_provenance(&self, cx: &impl HasDataLayout, range: AllocRange) -> bool {
+        !self.range_get_provenance(cx, range).is_empty()
     }
 
-    /// Removes all relocations inside the given range.
-    /// If there are relocations overlapping with the edges, they
+    /// Removes all provenance inside the given range.
+    /// If there is provenance overlapping with the edges, it
     /// are removed as well *and* the bytes they cover are marked as
     /// uninitialized. This is a somewhat odd "spooky action at a distance",
     /// but it allows strictly more code to run than if we would just error
     /// immediately in that case.
-    fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult
+    fn clear_provenance(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult
     where
         Prov: Provenance,
     {
-        // Find the start and end of the given range and its outermost relocations.
+        // Find the start and end of the given range and its outermost provenance.
         let (first, last) = {
-            // Find all relocations overlapping the given range.
-            let relocations = self.get_relocations(cx, range);
-            if relocations.is_empty() {
+            // Find all provenance overlapping the given range.
+            let provenance = self.range_get_provenance(cx, range);
+            if provenance.is_empty() {
                 return Ok(());
             }
 
             (
-                relocations.first().unwrap().0,
-                relocations.last().unwrap().0 + cx.data_layout().pointer_size,
+                provenance.first().unwrap().0,
+                provenance.last().unwrap().0 + cx.data_layout().pointer_size,
             )
         };
         let start = range.start;
         let end = range.end();
 
-        // We need to handle clearing the relocations from parts of a pointer.
-        // FIXME: Miri should preserve partial relocations; see
+        // We need to handle clearing the provenance from parts of a pointer.
+        // FIXME: Miri should preserve partial provenance; see
         // https://github.com/rust-lang/miri/issues/2181.
         if first < start {
             if Prov::ERR_ON_PARTIAL_PTR_OVERWRITE {
@@ -599,41 +581,32 @@ fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> A
             self.init_mask.set_range(end, last, false);
         }
 
-        // Forget all the relocations.
-        // Since relocations do not overlap, we know that removing until `last` (exclusive) is fine,
-        // i.e., this will not remove any other relocations just after the ones we care about.
-        self.relocations.0.remove_range(first..last);
-
-        Ok(())
-    }
+        // Forget all the provenance.
+        // Since provenance do not overlap, we know that removing until `last` (exclusive) is fine,
+        // i.e., this will not remove any other provenance just after the ones we care about.
+        self.provenance.0.remove_range(first..last);
 
-    /// Errors if there are relocations overlapping with the edges of the
-    /// given memory range.
-    #[inline]
-    fn check_relocation_edges(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
-        self.check_relocations(cx, alloc_range(range.start, Size::ZERO))?;
-        self.check_relocations(cx, alloc_range(range.end(), Size::ZERO))?;
         Ok(())
     }
 }
 
-/// "Relocations" stores the provenance information of pointers stored in memory.
+/// Stores the provenance information of pointers stored in memory.
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
-pub struct Relocations<Prov = AllocId>(SortedMap<Size, Prov>);
+pub struct ProvenanceMap<Prov = AllocId>(SortedMap<Size, Prov>);
 
-impl<Prov> Relocations<Prov> {
+impl<Prov> ProvenanceMap<Prov> {
     pub fn new() -> Self {
-        Relocations(SortedMap::new())
+        ProvenanceMap(SortedMap::new())
     }
 
-    // The caller must guarantee that the given relocations are already sorted
+    // The caller must guarantee that the given provenance list is already sorted
     // by address and contain no duplicates.
     pub fn from_presorted(r: Vec<(Size, Prov)>) -> Self {
-        Relocations(SortedMap::from_presorted_elements(r))
+        ProvenanceMap(SortedMap::from_presorted_elements(r))
     }
 }
 
-impl<Prov> Deref for Relocations<Prov> {
+impl<Prov> Deref for ProvenanceMap<Prov> {
     type Target = SortedMap<Size, Prov>;
 
     fn deref(&self) -> &Self::Target {
@@ -641,36 +614,36 @@ fn deref(&self) -> &Self::Target {
     }
 }
 
-/// A partial, owned list of relocations to transfer into another allocation.
+/// A partial, owned list of provenance to transfer into another allocation.
 ///
 /// Offsets are already adjusted to the destination allocation.
-pub struct AllocationRelocations<Prov> {
-    dest_relocations: Vec<(Size, Prov)>,
+pub struct AllocationProvenance<Prov> {
+    dest_provenance: Vec<(Size, Prov)>,
 }
 
 impl<Prov: Copy, Extra> Allocation<Prov, Extra> {
-    pub fn prepare_relocation_copy(
+    pub fn prepare_provenance_copy(
         &self,
         cx: &impl HasDataLayout,
         src: AllocRange,
         dest: Size,
         count: u64,
-    ) -> AllocationRelocations<Prov> {
-        let relocations = self.get_relocations(cx, src);
-        if relocations.is_empty() {
-            return AllocationRelocations { dest_relocations: Vec::new() };
+    ) -> AllocationProvenance<Prov> {
+        let provenance = self.range_get_provenance(cx, src);
+        if provenance.is_empty() {
+            return AllocationProvenance { dest_provenance: Vec::new() };
         }
 
         let size = src.size;
-        let mut new_relocations = Vec::with_capacity(relocations.len() * (count as usize));
+        let mut new_provenance = Vec::with_capacity(provenance.len() * (count as usize));
 
         // If `count` is large, this is rather wasteful -- we are allocating a big array here, which
         // is mostly filled with redundant information since it's just N copies of the same `Prov`s
-        // at slightly adjusted offsets. The reason we do this is so that in `mark_relocation_range`
+        // at slightly adjusted offsets. The reason we do this is so that in `mark_provenance_range`
         // we can use `insert_presorted`. That wouldn't work with an `Iterator` that just produces
-        // the right sequence of relocations for all N copies.
+        // the right sequence of provenance for all N copies.
         for i in 0..count {
-            new_relocations.extend(relocations.iter().map(|&(offset, reloc)| {
+            new_provenance.extend(provenance.iter().map(|&(offset, reloc)| {
                 // compute offset for current repetition
                 let dest_offset = dest + size * i; // `Size` operations
                 (
@@ -681,17 +654,17 @@ pub fn prepare_relocation_copy(
             }));
         }
 
-        AllocationRelocations { dest_relocations: new_relocations }
+        AllocationProvenance { dest_provenance: new_provenance }
     }
 
-    /// Applies a relocation copy.
-    /// The affected range, as defined in the parameters to `prepare_relocation_copy` is expected
-    /// to be clear of relocations.
+    /// Applies a provenance copy.
+    /// The affected range, as defined in the parameters to `prepare_provenance_copy` is expected
+    /// to be clear of provenance.
     ///
     /// This is dangerous to use as it can violate internal `Allocation` invariants!
     /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
-    pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations<Prov>) {
-        self.relocations.0.insert_presorted(relocations.dest_relocations);
+    pub fn mark_provenance_range(&mut self, provenance: AllocationProvenance<Prov>) {
+        self.provenance.0.insert_presorted(provenance.dest_provenance);
     }
 }
 
index cecb55578d332b02224e4af05065f3a1b261465c..e4039cc7c685ad0c635f15420582b72f3c486a8e 100644 (file)
@@ -401,14 +401,18 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 pub enum UnsupportedOpInfo {
     /// Free-form case. Only for errors that are never caught!
     Unsupported(String),
-    /// Encountered a pointer where we needed raw bytes.
-    ReadPointerAsBytes,
     /// Overwriting parts of a pointer; the resulting state cannot be represented in our
     /// `Allocation` data structure. See <https://github.com/rust-lang/miri/issues/2181>.
     PartialPointerOverwrite(Pointer<AllocId>),
+    /// Attempting to `copy` parts of a pointer to somewhere else; the resulting state cannot be
+    /// represented in our `Allocation` data structure. See
+    /// <https://github.com/rust-lang/miri/issues/2181>.
+    PartialPointerCopy(Pointer<AllocId>),
     //
     // The variants below are only reachable from CTFE/const prop, miri will never emit them.
     //
+    /// Encountered a pointer where we needed raw bytes.
+    ReadPointerAsBytes,
     /// Accessing thread local statics
     ThreadLocalStatic(DefId),
     /// Accessing an unsupported extern static.
@@ -420,10 +424,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use UnsupportedOpInfo::*;
         match self {
             Unsupported(ref msg) => write!(f, "{msg}"),
-            ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"),
             PartialPointerOverwrite(ptr) => {
                 write!(f, "unable to overwrite parts of a pointer in memory at {ptr:?}")
             }
+            PartialPointerCopy(ptr) => {
+                write!(f, "unable to copy parts of a pointer from memory at {ptr:?}")
+            }
+            ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"),
             ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({did:?})"),
             ReadExternStatic(did) => write!(f, "cannot read from extern static ({did:?})"),
         }
index 93fe7e63710b15061f85791bf3071f6692a4bcb6..0fc1217d571969c6f1fd4954631d04ed8eff1def 100644 (file)
@@ -128,7 +128,7 @@ macro_rules! throw_machine_stop {
 
 pub use self::allocation::{
     alloc_range, AllocRange, Allocation, ConstAllocation, InitChunk, InitChunkIter, InitMask,
-    Relocations,
+    ProvenanceMap,
 };
 
 pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
index 384954cbbd5f7d3939fbde8828974a46de81147c..95e52e391d8f8f60f8cc6450da3d49d149f36cce 100644 (file)
@@ -107,8 +107,12 @@ impl<T: HasDataLayout> PointerArithmetic for T {}
 /// pointer), but `derive` adds some unnecessary bounds.
 pub trait Provenance: Copy + fmt::Debug {
     /// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address.
-    /// If `true, ptr-to-int casts work by simply discarding the provenance.
-    /// If `false`, ptr-to-int casts are not supported. The offset *must* be relative in that case.
+    /// - If `false`, the offset *must* be relative. This means the bytes representing a pointer are
+    ///   different from what the Abstract Machine prescribes, so the interpreter must prevent any
+    ///   operation that would inspect the underlying bytes of a pointer, such as ptr-to-int
+    ///   transmutation. A `ReadPointerAsBytes` error will be raised in such situations.
+    /// - If `true`, the interpreter will permit operations to inspect the underlying bytes of a
+    ///   pointer, and implement ptr-to-int transmutation by stripping provenance.
     const OFFSET_IS_ADDR: bool;
 
     /// We also use this trait to control whether to abort execution when a pointer is being partially overwritten
@@ -125,6 +129,9 @@ fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result
     /// Otherwise this function is best-effort (but must agree with `Machine::ptr_get_alloc`).
     /// (Identifying the offset in that allocation, however, is harder -- use `Memory::ptr_get_alloc` for that.)
     fn get_alloc_id(self) -> Option<AllocId>;
+
+    /// Defines the 'join' of provenance: what happens when doing a pointer load and different bytes have different provenance.
+    fn join(left: Option<Self>, right: Option<Self>) -> Option<Self>;
 }
 
 impl Provenance for AllocId {
@@ -152,6 +159,10 @@ fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     fn get_alloc_id(self) -> Option<AllocId> {
         Some(self)
     }
+
+    fn join(_left: Option<Self>, _right: Option<Self>) -> Option<Self> {
+        panic!("merging provenance is not supported when `OFFSET_IS_ADDR` is false")
+    }
 }
 
 /// Represents a pointer in the Miri engine.
index ba56c5267df0b1af2519dd3b4eef6918f8244238..d4fad7f1ecdd9fc656e762831ff5c937d11d7964 100644 (file)
@@ -130,9 +130,7 @@ pub enum Scalar<Prov = AllocId> {
     /// The raw bytes of a simple value.
     Int(ScalarInt),
 
-    /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
-    /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
-    /// relocation and its associated offset together as a `Pointer` here.
+    /// A pointer.
     ///
     /// We also store the size of the pointer, such that a `Scalar` always knows how big it is.
     /// The size is always the pointer size of the current target, but this is not information
@@ -509,7 +507,7 @@ pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) ->
     if let ConstValue::Slice { data, start, end } = val {
         let len = end - start;
         data.inner()
-            .get_bytes(
+            .get_bytes_strip_provenance(
                 cx,
                 AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) },
             )
index f7a1e9b2864888b2f6b5eecfcb37fe96bf87b2f4..f3676604bb0e64b34b6d6d6e38eea52be4768683 100644 (file)
@@ -128,8 +128,20 @@ fn is_mir_dump_enabled(&self) -> bool {
 
 impl MirPhase {
     /// Gets the index of the current MirPhase within the set of all `MirPhase`s.
+    ///
+    /// FIXME(JakobDegen): Return a `(usize, usize)` instead.
     pub fn phase_index(&self) -> usize {
-        *self as usize
+        const BUILT_PHASE_COUNT: usize = 1;
+        const ANALYSIS_PHASE_COUNT: usize = 2;
+        match self {
+            MirPhase::Built => 1,
+            MirPhase::Analysis(analysis_phase) => {
+                1 + BUILT_PHASE_COUNT + (*analysis_phase as usize)
+            }
+            MirPhase::Runtime(runtime_phase) => {
+                1 + BUILT_PHASE_COUNT + ANALYSIS_PHASE_COUNT + (*runtime_phase as usize)
+            }
+        }
     }
 }
 
@@ -1445,7 +1457,7 @@ pub struct PlaceRef<'tcx> {
 // Once we stop implementing `Ord` for `DefId`,
 // this impl will be unnecessary. Until then, we'll
 // leave this impl in place to prevent re-adding a
-// dependnecy on the `Ord` impl for `DefId`
+// dependency on the `Ord` impl for `DefId`
 impl<'tcx> !PartialOrd for PlaceRef<'tcx> {}
 
 impl<'tcx> Place<'tcx> {
@@ -2255,7 +2267,7 @@ pub fn from_anon_const(
         Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env)
     }
 
-    #[instrument(skip(tcx), level = "debug")]
+    #[instrument(skip(tcx), level = "debug", ret)]
     pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
         let body_id = match tcx.hir().get(hir_id) {
@@ -2293,21 +2305,18 @@ pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
         let substs =
             ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty })
                 .substs;
-        let uneval_const = tcx.mk_const(ty::ConstS {
+        debug_assert!(!substs.has_free_regions());
+        Self::Ty(tcx.mk_const(ty::ConstS {
             kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
                 def: ty::WithOptConstParam::unknown(def_id).to_global(),
                 substs,
                 promoted: None,
             }),
             ty,
-        });
-        debug!(?uneval_const);
-        debug_assert!(!uneval_const.has_free_regions());
-
-        Self::Ty(uneval_const)
+        }))
     }
 
-    #[instrument(skip(tcx), level = "debug")]
+    #[instrument(skip(tcx), level = "debug", ret)]
     fn from_opt_const_arg_anon_const(
         tcx: TyCtxt<'tcx>,
         def: ty::WithOptConstParam<LocalDefId>,
@@ -2390,24 +2399,21 @@ fn from_opt_const_arg_anon_const(
 
         match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
             Ok(val) => {
-                debug!("evaluated const value: {:?}", val);
+                debug!("evaluated const value");
                 Self::Val(val, ty)
             }
             Err(_) => {
                 debug!("error encountered during evaluation");
                 // Error was handled in `const_eval_resolve`. Here we just create a
                 // new unevaluated const and error hard later in codegen
-                let ty_const = tcx.mk_const(ty::ConstS {
+                Self::Ty(tcx.mk_const(ty::ConstS {
                     kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
                         def: def.to_global(),
                         substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
                         promoted: None,
                     }),
                     ty,
-                });
-                debug!(?ty_const);
-
-                Self::Ty(ty_const)
+                }))
             }
         }
     }
@@ -2687,8 +2693,8 @@ fn pretty_print_const_value<'tcx>(
                 match inner.kind() {
                     ty::Slice(t) => {
                         if *t == u8_type {
-                            // The `inspect` here is okay since we checked the bounds, and there are
-                            // no relocations (we have an active slice reference here). We don't use
+                            // The `inspect` here is okay since we checked the bounds, and `u8` carries
+                            // no provenance (we have an active slice reference here). We don't use
                             // this result to affect interpreter execution.
                             let byte_str = data
                                 .inner()
@@ -2698,8 +2704,8 @@ fn pretty_print_const_value<'tcx>(
                         }
                     }
                     ty::Str => {
-                        // The `inspect` here is okay since we checked the bounds, and there are no
-                        // relocations (we have an active `str` reference here). We don't use this
+                        // The `inspect` here is okay since we checked the bounds, and `str` carries
+                        // no provenance (we have an active `str` reference here). We don't use this
                         // result to affect interpreter execution.
                         let slice = data
                             .inner()
@@ -2714,7 +2720,7 @@ fn pretty_print_const_value<'tcx>(
                 let n = n.kind().try_to_bits(tcx.data_layout.pointer_size).unwrap();
                 // cast is ok because we already checked for pointer size (32 or 64 bit) above
                 let range = AllocRange { start: offset, size: Size::from_bytes(n) };
-                let byte_str = alloc.inner().get_bytes(&tcx, range).unwrap();
+                let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap();
                 fmt.write_str("*")?;
                 pretty_print_byte_str(fmt, byte_str)?;
                 return Ok(());
index da6af89b09b9b9a22cee906b971b7407b0887f4c..88c16189f1dc6da259a40c38a0c76f19381f78ec 100644 (file)
@@ -676,7 +676,7 @@ pub fn write_allocations<'tcx>(
     fn alloc_ids_from_alloc(
         alloc: ConstAllocation<'_>,
     ) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
-        alloc.inner().relocations().values().map(|id| *id)
+        alloc.inner().provenance().values().map(|id| *id)
     }
 
     fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
@@ -778,7 +778,7 @@ fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) {
 /// If the allocation is small enough to fit into a single line, no start address is given.
 /// After the hex dump, an ascii dump follows, replacing all unprintable characters (control
 /// characters or characters whose value is larger than 127) with a `.`
-/// This also prints relocations adequately.
+/// This also prints provenance adequately.
 pub fn display_allocation<'a, 'tcx, Prov, Extra>(
     tcx: TyCtxt<'tcx>,
     alloc: &'a Allocation<Prov, Extra>,
@@ -873,34 +873,34 @@ fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>(
         if i != line_start {
             write!(w, " ")?;
         }
-        if let Some(&prov) = alloc.relocations().get(&i) {
-            // Memory with a relocation must be defined
+        if let Some(&prov) = alloc.provenance().get(&i) {
+            // Memory with provenance must be defined
             assert!(alloc.init_mask().is_range_initialized(i, i + ptr_size).is_ok());
             let j = i.bytes_usize();
             let offset = alloc
                 .inspect_with_uninit_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize());
             let offset = read_target_uint(tcx.data_layout.endian, offset).unwrap();
             let offset = Size::from_bytes(offset);
-            let relocation_width = |bytes| bytes * 3;
+            let provenance_width = |bytes| bytes * 3;
             let ptr = Pointer::new(prov, offset);
             let mut target = format!("{:?}", ptr);
-            if target.len() > relocation_width(ptr_size.bytes_usize() - 1) {
+            if target.len() > provenance_width(ptr_size.bytes_usize() - 1) {
                 // This is too long, try to save some space.
                 target = format!("{:#?}", ptr);
             }
             if ((i - line_start) + ptr_size).bytes_usize() > BYTES_PER_LINE {
-                // This branch handles the situation where a relocation starts in the current line
+                // This branch handles the situation where a provenance starts in the current line
                 // but ends in the next one.
                 let remainder = Size::from_bytes(BYTES_PER_LINE) - (i - line_start);
                 let overflow = ptr_size - remainder;
-                let remainder_width = relocation_width(remainder.bytes_usize()) - 2;
-                let overflow_width = relocation_width(overflow.bytes_usize() - 1) + 1;
+                let remainder_width = provenance_width(remainder.bytes_usize()) - 2;
+                let overflow_width = provenance_width(overflow.bytes_usize() - 1) + 1;
                 ascii.push('╾');
                 for _ in 0..remainder.bytes() - 1 {
                     ascii.push('─');
                 }
                 if overflow_width > remainder_width && overflow_width >= target.len() {
-                    // The case where the relocation fits into the part in the next line
+                    // The case where the provenance fits into the part in the next line
                     write!(w, "╾{0:─^1$}", "", remainder_width)?;
                     line_start =
                         write_allocation_newline(w, line_start, &ascii, pos_width, prefix)?;
@@ -921,11 +921,11 @@ fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>(
                 i += ptr_size;
                 continue;
             } else {
-                // This branch handles a relocation that starts and ends in the current line.
-                let relocation_width = relocation_width(ptr_size.bytes_usize() - 1);
-                oversized_ptr(&mut target, relocation_width);
+                // This branch handles a provenance that starts and ends in the current line.
+                let provenance_width = provenance_width(ptr_size.bytes_usize() - 1);
+                oversized_ptr(&mut target, provenance_width);
                 ascii.push('╾');
-                write!(w, "╾{0:─^1$}╼", target, relocation_width)?;
+                write!(w, "╾{0:─^1$}╼", target, provenance_width)?;
                 for _ in 0..ptr_size.bytes() - 2 {
                     ascii.push('─');
                 }
@@ -935,7 +935,7 @@ fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>(
         } else if alloc.init_mask().is_range_initialized(i, i + Size::from_bytes(1)).is_ok() {
             let j = i.bytes_usize();
 
-            // Checked definedness (and thus range) and relocations. This access also doesn't
+            // Checked definedness (and thus range) and provenance. This access also doesn't
             // influence interpreter execution but is only for debugging.
             let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0];
             write!(w, "{:02x}", c)?;
index eb90169d0e3141acbbab8408bf7482c8d1ac3a04..d7b9d59eced51eee813171db11a11635a881378e 100644 (file)
 use rustc_span::Span;
 use rustc_target::asm::InlineAsmRegOrRegClass;
 
-/// The various "big phases" that MIR goes through.
+/// Represents the "flavors" of MIR.
 ///
-/// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the
-/// dialects forbid certain variants or values in certain phases. The sections below summarize the
-/// changes, but do not document them thoroughly. The full documentation is found in the appropriate
-/// documentation for the thing the change is affecting.
+/// All flavors of MIR use the same data structure, but there are some important differences. These
+/// differences come in two forms: Dialects and phases.
 ///
-/// Warning: ordering of variants is significant.
+/// Dialects represent a stronger distinction than phases. This is because the transitions between
+/// dialects are semantic changes, and therefore technically *lowerings* between distinct IRs. In
+/// other words, the same [`Body`](crate::mir::Body) might be well-formed for multiple dialects, but
+/// have different semantic meaning and different behavior at runtime.
+///
+/// Each dialect additionally has a number of phases. However, phase changes never involve semantic
+/// changes. If some MIR is well-formed both before and after a phase change, it is also guaranteed
+/// that it has the same semantic meaning. In this sense, phase changes can only add additional
+/// restrictions on what MIR is well-formed.
+///
+/// When adding phases, remember to update [`MirPhase::phase_index`].
 #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
 #[derive(HashStable)]
 pub enum MirPhase {
-    /// The dialect of MIR used during all phases before `DropsLowered` is the same. This is also
-    /// the MIR that analysis such as borrowck uses.
-    ///
-    /// One important thing to remember about the behavior of this section of MIR is that drop terminators
-    /// (including drop and replace) are *conditional*. The elaborate drops pass will then replace each
-    /// instance of a drop terminator with a nop, an unconditional drop, or a drop conditioned on a drop
-    /// flag. Of course, this means that it is important that the drop elaboration can accurately recognize
-    /// when things are initialized and when things are de-initialized. That means any code running on this
-    /// version of MIR must be sure to produce output that drop elaboration can reason about. See the
-    /// section on the drop terminatorss for more details.
-    Built = 0,
-    // FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query).
-    // We used to have this for pre-miri MIR based const eval.
-    Const = 1,
-    /// This phase checks the MIR for promotable elements and takes them out of the main MIR body
-    /// by creating a new MIR body per promoted element. After this phase (and thus the termination
-    /// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir`
-    /// query.
-    ConstsPromoted = 2,
-    /// After this projections may only contain deref projections as the first element.
-    Derefered = 3,
-    /// Beginning with this phase, the following variants are disallowed:
-    /// * [`TerminatorKind::DropAndReplace`]
+    /// The MIR that is generated by MIR building.
+    ///
+    /// The only things that operate on this dialect are unsafeck, the various MIR lints, and const
+    /// qualifs.
+    ///
+    /// This has no distinct phases.
+    Built,
+    /// The MIR used for most analysis.
+    ///
+    /// The only semantic change between analysis and built MIR is constant promotion. In built MIR,
+    /// sequences of statements that would generally be subject to constant promotion are
+    /// semantically constants, while in analysis MIR all constants are explicit.
+    ///
+    /// The result of const promotion is available from the `mir_promoted` and `promoted_mir` queries.
+    ///
+    /// This is the version of MIR used by borrowck and friends.
+    Analysis(AnalysisPhase),
+    /// The MIR used for CTFE, optimizations, and codegen.
+    ///
+    /// The semantic changes that occur in the lowering from analysis to runtime MIR are as follows:
+    ///
+    ///  - Drops: In analysis MIR, `Drop` terminators represent *conditional* drops; roughly speaking,
+    ///    if dataflow analysis determines that the place being dropped is uninitialized, the drop will
+    ///    not be executed. The exact semantics of this aren't written down anywhere, which means they
+    ///    are essentially "what drop elaboration does." In runtime MIR, the drops are unconditional;
+    ///    when a `Drop` terminator is reached, if the type has drop glue that drop glue is always
+    ///    executed. This may be UB if the underlying place is not initialized.
+    ///  - Packed drops: Places might in general be misaligned - in most cases this is UB, the exception
+    ///    is fields of packed structs. In analysis MIR, `Drop(P)` for a `P` that might be misaligned
+    ///    for this reason implicitly moves `P` to a temporary before dropping. Runtime MIR has no such
+    ///    rules, and dropping a misaligned place is simply UB.
+    ///  - Unwinding: in analysis MIR, unwinding from a function which may not unwind aborts. In runtime
+    ///    MIR, this is UB.
+    ///  - Retags: If `-Zmir-emit-retag` is enabled, analysis MIR has "implicit" retags in the same way
+    ///    that Rust itself has them. Where exactly these are is generally subject to change, and so we
+    ///    don't document this here. Runtime MIR has all retags explicit.
+    ///  - Generator bodies: In analysis MIR, locals may actually be behind a pointer that user code has
+    ///    access to. This occurs in generator bodies. Such locals do not behave like other locals,
+    ///    because they eg may be aliased in surprising ways. Runtime MIR has no such special locals -
+    ///    all generator bodies are lowered and so all places that look like locals really are locals.
+    ///  - Const prop lints: The lint pass which reports eg `200_u8 + 200_u8` as an error is run as a
+    ///    part of analysis to runtime MIR lowering. This means that transformations which may supress
+    ///    such errors may not run on analysis MIR.
+    Runtime(RuntimePhase),
+}
+
+/// See [`MirPhase::Analysis`].
+#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(HashStable)]
+pub enum AnalysisPhase {
+    Initial = 0,
+    /// Beginning in this phase, the following variants are disallowed:
     /// * [`TerminatorKind::FalseUnwind`]
     /// * [`TerminatorKind::FalseEdge`]
     /// * [`StatementKind::FakeRead`]
     /// * [`StatementKind::AscribeUserType`]
     /// * [`Rvalue::Ref`] with `BorrowKind::Shallow`
     ///
-    /// And the following variant is allowed:
-    /// * [`StatementKind::Retag`]
-    ///
-    /// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop`
-    /// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands
-    /// are allowed for non-`Copy` types.
-    DropsLowered = 4,
-    /// Beginning with this phase, the following variant is disallowed:
+    /// Furthermore, `Deref` projections must be the first projection within any place (if they
+    /// appear at all)
+    PostCleanup = 1,
+}
+
+/// See [`MirPhase::Runtime`].
+#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(HashStable)]
+pub enum RuntimePhase {
+    /// In addition to the semantic changes, beginning with this phase, the following variants are
+    /// disallowed:
+    /// * [`TerminatorKind::DropAndReplace`]
+    /// * [`TerminatorKind::Yield`]
+    /// * [`TerminatorKind::GeneratorDrop`]
     /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
     ///
-    /// And the following variant is allowed:
+    /// And the following variants are allowed:
+    /// * [`StatementKind::Retag`]
     /// * [`StatementKind::SetDiscriminant`]
-    Deaggregated = 5,
-    /// Before this phase, generators are in the "source code" form, featuring `yield` statements
-    /// and such. With this phase change, they are transformed into a proper state machine. Running
-    /// optimizations before this change can be potentially dangerous because the source code is to
-    /// some extent a "lie." In particular, `yield` terminators effectively make the value of all
-    /// locals visible to the caller. This means that dead store elimination before them, or code
-    /// motion across them, is not correct in general. This is also exasperated by type checking
-    /// having pre-computed a list of the types that it thinks are ok to be live across a yield
-    /// point - this is necessary to decide eg whether autotraits are implemented. Introducing new
-    /// types across a yield point will lead to ICEs becaues of this.
-    ///
-    /// Beginning with this phase, the following variants are disallowed:
-    /// * [`TerminatorKind::Yield`]
-    /// * [`TerminatorKind::GeneratorDrop`]
+    /// * [`StatementKind::Deinit`]
+    ///
+    /// Furthermore, `Copy` operands are allowed for non-`Copy` types.
+    Initial = 0,
+    /// Beginning with this phase, the following variant is disallowed:
     /// * [`ProjectionElem::Deref`] of `Box`
-    GeneratorsLowered = 6,
-    Optimized = 7,
+    PostCleanup = 1,
+    Optimized = 2,
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -297,7 +332,7 @@ pub enum StatementKind<'tcx> {
     /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer,
     /// or `Box` pointing to the same type `T`. `count` must evaluate to a `usize`. Then, `src` and
     /// `dest` are dereferenced, and `count * size_of::<T>()` bytes beginning with the first byte of
-    /// the `src` place are copied to the continguous range of bytes beginning with the first byte
+    /// the `src` place are copied to the contiguous range of bytes beginning with the first byte
     /// of `dest`.
     ///
     /// **Needs clarification**: In what order are operands computed and dereferenced? It should
@@ -343,7 +378,7 @@ pub enum FakeReadCause {
     /// Some(closure_def_id).
     /// Otherwise, the value of the optional LocalDefId will be None.
     //
-    // We can use LocaDefId here since fake read statements are removed
+    // We can use LocalDefId here since fake read statements are removed
     // before codegen in the `CleanupNonCodegenStatements` pass.
     ForMatchedPlace(Option<LocalDefId>),
 
index ecedbe8fc8eaaf0e5d74d1db0bbb82da6b4e7fd3..abaef0354ade5b319f5ca9560aa19eced27113b8 100644 (file)
     /// Used by rustdoc.
     query rendered_const(def_id: DefId) -> String {
         storage(ArenaCacheSelector<'tcx>)
-        desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) }
+        desc { |tcx| "rendering constant initializer of `{}`", tcx.def_path_str(def_id) }
         cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
     /// for each parameter if a trait object were to be passed for that parameter.
     /// For example, for `struct Foo<'a, T, U>`, this would be `['static, 'static]`.
     /// For `struct Foo<'a, T: 'a, U>`, this would instead be `['a, 'static]`.
-    query object_lifetime_defaults(_: LocalDefId) -> Option<&'tcx [ObjectLifetimeDefault]> {
-        desc { "looking up lifetime defaults for a region on an item" }
+    query object_lifetime_default(key: DefId) -> Option<ObjectLifetimeDefault> {
+        desc { "looking up lifetime defaults for generic parameter `{:?}`", key }
+        separate_provide_extern
     }
     query late_bound_vars_map(_: LocalDefId)
         -> Option<&'tcx FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>> {
index 0f2504e3d9afee0386b1240cee087a78851e92eb..59e14337f4ed86a55fc92120be7c81c5c06aa261 100644 (file)
@@ -180,7 +180,7 @@ pub enum StmtKind<'tcx> {
         /// `let <PAT> = ...`
         ///
         /// If a type annotation is included, it is added as an ascription pattern.
-        pattern: Pat<'tcx>,
+        pattern: Box<Pat<'tcx>>,
 
         /// `let pat: ty = <INIT>`
         initializer: Option<ExprId>,
@@ -301,7 +301,7 @@ pub enum ExprKind<'tcx> {
     },
     Let {
         expr: ExprId,
-        pat: Pat<'tcx>,
+        pat: Box<Pat<'tcx>>,
     },
     /// A `match` expression.
     Match {
@@ -467,7 +467,7 @@ pub struct FruInfo<'tcx> {
 /// A `match` arm.
 #[derive(Clone, Debug, HashStable)]
 pub struct Arm<'tcx> {
-    pub pattern: Pat<'tcx>,
+    pub pattern: Box<Pat<'tcx>>,
     pub guard: Option<Guard<'tcx>>,
     pub body: ExprId,
     pub lint_level: LintLevel,
@@ -479,7 +479,7 @@ pub struct Arm<'tcx> {
 #[derive(Clone, Debug, HashStable)]
 pub enum Guard<'tcx> {
     If(ExprId),
-    IfLet(Pat<'tcx>, ExprId),
+    IfLet(Box<Pat<'tcx>>, ExprId),
 }
 
 #[derive(Copy, Clone, Debug, HashStable)]
@@ -534,19 +534,19 @@ pub enum BindingMode {
 #[derive(Clone, Debug, HashStable)]
 pub struct FieldPat<'tcx> {
     pub field: Field,
-    pub pattern: Pat<'tcx>,
+    pub pattern: Box<Pat<'tcx>>,
 }
 
 #[derive(Clone, Debug, HashStable)]
 pub struct Pat<'tcx> {
     pub ty: Ty<'tcx>,
     pub span: Span,
-    pub kind: Box<PatKind<'tcx>>,
+    pub kind: PatKind<'tcx>,
 }
 
 impl<'tcx> Pat<'tcx> {
     pub fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
-        Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
+        Pat { ty, span: DUMMY_SP, kind: PatKind::Wild }
     }
 }
 
@@ -581,7 +581,7 @@ pub enum PatKind<'tcx> {
 
     AscribeUserType {
         ascription: Ascription<'tcx>,
-        subpattern: Pat<'tcx>,
+        subpattern: Box<Pat<'tcx>>,
     },
 
     /// `x`, `ref x`, `x @ P`, etc.
@@ -591,7 +591,7 @@ pub enum PatKind<'tcx> {
         mode: BindingMode,
         var: LocalVarId,
         ty: Ty<'tcx>,
-        subpattern: Option<Pat<'tcx>>,
+        subpattern: Option<Box<Pat<'tcx>>>,
         /// Is this the leftmost occurrence of the binding, i.e., is `var` the
         /// `HirId` of this pattern?
         is_primary: bool,
@@ -614,7 +614,7 @@ pub enum PatKind<'tcx> {
 
     /// `box P`, `&P`, `&mut P`, etc.
     Deref {
-        subpattern: Pat<'tcx>,
+        subpattern: Box<Pat<'tcx>>,
     },
 
     /// One of the following:
@@ -628,32 +628,32 @@ pub enum PatKind<'tcx> {
         value: mir::ConstantKind<'tcx>,
     },
 
-    Range(PatRange<'tcx>),
+    Range(Box<PatRange<'tcx>>),
 
     /// Matches against a slice, checking the length and extracting elements.
     /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
     /// e.g., `&[ref xs @ ..]`.
     Slice {
-        prefix: Vec<Pat<'tcx>>,
-        slice: Option<Pat<'tcx>>,
-        suffix: Vec<Pat<'tcx>>,
+        prefix: Box<[Box<Pat<'tcx>>]>,
+        slice: Option<Box<Pat<'tcx>>>,
+        suffix: Box<[Box<Pat<'tcx>>]>,
     },
 
     /// Fixed match against an array; irrefutable.
     Array {
-        prefix: Vec<Pat<'tcx>>,
-        slice: Option<Pat<'tcx>>,
-        suffix: Vec<Pat<'tcx>>,
+        prefix: Box<[Box<Pat<'tcx>>]>,
+        slice: Option<Box<Pat<'tcx>>>,
+        suffix: Box<[Box<Pat<'tcx>>]>,
     },
 
     /// An or-pattern, e.g. `p | q`.
     /// Invariant: `pats.len() >= 2`.
     Or {
-        pats: Vec<Pat<'tcx>>,
+        pats: Box<[Box<Pat<'tcx>>]>,
     },
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+#[derive(Clone, Debug, PartialEq, HashStable)]
 pub struct PatRange<'tcx> {
     pub lo: mir::ConstantKind<'tcx>,
     pub hi: mir::ConstantKind<'tcx>,
@@ -674,7 +674,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         };
         let mut start_or_comma = || start_or_continue(", ");
 
-        match *self.kind {
+        match self.kind {
             PatKind::Wild => write!(f, "_"),
             PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
             PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
@@ -695,7 +695,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 Ok(())
             }
             PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
-                let variant = match *self.kind {
+                let variant = match self.kind {
                     PatKind::Variant { adt_def, variant_index, .. } => {
                         Some(adt_def.variant(variant_index))
                     }
@@ -714,7 +714,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
                         let mut printed = 0;
                         for p in subpatterns {
-                            if let PatKind::Wild = *p.pattern.kind {
+                            if let PatKind::Wild = p.pattern.kind {
                                 continue;
                             }
                             let name = variant.fields[p.field.index()].name;
@@ -767,7 +767,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 write!(f, "{}", subpattern)
             }
             PatKind::Constant { value } => write!(f, "{}", value),
-            PatKind::Range(PatRange { lo, hi, end }) => {
+            PatKind::Range(box PatRange { lo, hi, end }) => {
                 write!(f, "{}", lo)?;
                 write!(f, "{}", end)?;
                 write!(f, "{}", hi)
@@ -775,24 +775,24 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             PatKind::Slice { ref prefix, ref slice, ref suffix }
             | PatKind::Array { ref prefix, ref slice, ref suffix } => {
                 write!(f, "[")?;
-                for p in prefix {
+                for p in prefix.iter() {
                     write!(f, "{}{}", start_or_comma(), p)?;
                 }
                 if let Some(ref slice) = *slice {
                     write!(f, "{}", start_or_comma())?;
-                    match *slice.kind {
+                    match slice.kind {
                         PatKind::Wild => {}
                         _ => write!(f, "{}", slice)?,
                     }
                     write!(f, "..")?;
                 }
-                for p in suffix {
+                for p in suffix.iter() {
                     write!(f, "{}{}", start_or_comma(), p)?;
                 }
                 write!(f, "]")
             }
             PatKind::Or { ref pats } => {
-                for pat in pats {
+                for pat in pats.iter() {
                     write!(f, "{}{}", start_or_continue(" | "), pat)?;
                 }
                 Ok(())
@@ -809,8 +809,8 @@ mod size_asserts {
     static_assert_size!(Block, 56);
     static_assert_size!(Expr<'_>, 64);
     static_assert_size!(ExprKind<'_>, 40);
-    static_assert_size!(Pat<'_>, 24);
-    static_assert_size!(PatKind<'_>, 112);
-    static_assert_size!(Stmt<'_>, 72);
-    static_assert_size!(StmtKind<'_>, 64);
+    static_assert_size!(Pat<'_>, 72);
+    static_assert_size!(PatKind<'_>, 56);
+    static_assert_size!(Stmt<'_>, 56);
+    static_assert_size!(StmtKind<'_>, 48);
 }
index c5c48a6360925a151a3c50ca3ef457059c6bad8e..79a0e75aa7c788b6923047908692c748a3f8b417 100644 (file)
@@ -211,7 +211,7 @@ pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'
 
 pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) {
     use PatKind::*;
-    match pat.kind.as_ref() {
+    match &pat.kind {
         AscribeUserType { subpattern, ascription: _ }
         | Deref { subpattern }
         | Binding {
@@ -232,18 +232,18 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'
         Constant { value: _ } => {}
         Range(_) => {}
         Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
-            for subpattern in prefix {
+            for subpattern in prefix.iter() {
                 visitor.visit_pat(&subpattern);
             }
             if let Some(pat) = slice {
-                visitor.visit_pat(pat);
+                visitor.visit_pat(&pat);
             }
-            for subpattern in suffix {
+            for subpattern in suffix.iter() {
                 visitor.visit_pat(&subpattern);
             }
         }
         Or { pats } => {
-            for pat in pats {
+            for pat in pats.iter() {
                 visitor.visit_pat(&pat);
             }
         }
index 2465f8e2533e80caa36077c63815cf6b45a3a6f3..0a2819feecf0bb80a4b78f9e80d1571cc33993cf 100644 (file)
@@ -115,7 +115,7 @@ pub fn is_from_trait(&self) -> bool {
         matches!(self, Node::Trait(..))
     }
 
-    /// Trys to find the associated item that implements `trait_item_def_id`
+    /// Tries to find the associated item that implements `trait_item_def_id`
     /// defined in this node.
     ///
     /// If this returns `None`, the item can potentially still be found in
index f8792edc017b2d8d3a5da6affae1e10302511dce..2eb5cffa6bc44360a25dc9cb7f578ac7addc31ff 100644 (file)
@@ -65,8 +65,6 @@ pub fn from_opt_const_arg_anon_const(
         tcx: TyCtxt<'tcx>,
         def: ty::WithOptConstParam<LocalDefId>,
     ) -> Self {
-        debug!("Const::from_anon_const(def={:?})", def);
-
         let body_id = match tcx.hir().get_by_def_id(def.did) {
             hir::Node::AnonConst(ac) => ac.body,
             _ => span_bug!(
index cb0137d2e5e09c8b8f84cf5dee284db3873b0113..3840e79cebd84e8d577b412366a049f552270719 100644 (file)
@@ -20,6 +20,12 @@ pub struct Unevaluated<'tcx, P = Option<Promoted>> {
     pub promoted: P,
 }
 
+impl rustc_errors::IntoDiagnosticArg for Unevaluated<'_> {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        format!("{:?}", self).into_diagnostic_arg()
+    }
+}
+
 impl<'tcx> Unevaluated<'tcx> {
     #[inline]
     pub fn shrink(self) -> Unevaluated<'tcx, ()> {
index 0f34aa10a1257f03f53f349faf70e45e15ecd1e8..262d59f8ff8a78963c95f2fbe60717215e465ebd 100644 (file)
@@ -874,7 +874,7 @@ pub struct UserTypeAnnotationIndex {
 
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct CanonicalUserTypeAnnotation<'tcx> {
-    pub user_ty: CanonicalUserType<'tcx>,
+    pub user_ty: Box<CanonicalUserType<'tcx>>,
     pub span: Span,
     pub inferred_ty: Ty<'tcx>,
 }
@@ -1089,7 +1089,7 @@ pub struct GlobalCtxt<'tcx> {
 
     pub queries: &'tcx dyn query::QueryEngine<'tcx>,
     pub query_caches: query::QueryCaches<'tcx>,
-    query_kinds: &'tcx [DepKindStruct],
+    query_kinds: &'tcx [DepKindStruct<'tcx>],
 
     // Internal caches for metadata decoding. No need to track deps on this.
     pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
@@ -1246,7 +1246,7 @@ pub fn create_global_ctxt(
         dep_graph: DepGraph,
         on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
         queries: &'tcx dyn query::QueryEngine<'tcx>,
-        query_kinds: &'tcx [DepKindStruct],
+        query_kinds: &'tcx [DepKindStruct<'tcx>],
         crate_name: &str,
         output_filenames: OutputFilenames,
     ) -> GlobalCtxt<'tcx> {
@@ -1296,7 +1296,7 @@ pub fn create_global_ctxt(
         }
     }
 
-    pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct {
+    pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct<'tcx> {
         &self.query_kinds[k as usize]
     }
 
@@ -1498,17 +1498,17 @@ pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'tcx {
         // Create a dependency to the crate to be sure we re-execute this when the amount of
         // definitions change.
         self.ensure().hir_crate(());
-        // Leak a read lock once we start iterating on definitions, to prevent adding new onces
+        // Leak a read lock once we start iterating on definitions, to prevent adding new ones
         // while iterating.  If some query needs to add definitions, it should be `ensure`d above.
         let definitions = self.definitions.leak();
         definitions.iter_local_def_id()
     }
 
     pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable {
-        // Create a dependency to the crate to be sure we reexcute this when the amount of
+        // Create a dependency to the crate to be sure we re-execute this when the amount of
         // definitions change.
         self.ensure().hir_crate(());
-        // Leak a read lock once we start iterating on definitions, to prevent adding new onces
+        // Leak a read lock once we start iterating on definitions, to prevent adding new ones
         // while iterating.  If some query needs to add definitions, it should be `ensure`d above.
         let definitions = self.definitions.leak();
         definitions.def_path_table()
@@ -1517,10 +1517,10 @@ pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable {
     pub fn def_path_hash_to_def_index_map(
         self,
     ) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap {
-        // Create a dependency to the crate to be sure we reexcute this when the amount of
+        // Create a dependency to the crate to be sure we re-execute this when the amount of
         // definitions change.
         self.ensure().hir_crate(());
-        // Leak a read lock once we start iterating on definitions, to prevent adding new onces
+        // Leak a read lock once we start iterating on definitions, to prevent adding new ones
         // while iterating.  If some query needs to add definitions, it should be `ensure`d above.
         let definitions = self.definitions.leak();
         definitions.def_path_hash_to_def_index_map()
@@ -1829,9 +1829,9 @@ pub mod tls {
     use crate::dep_graph::TaskDepsRef;
     use crate::ty::query;
     use rustc_data_structures::sync::{self, Lock};
-    use rustc_data_structures::thin_vec::ThinVec;
     use rustc_errors::Diagnostic;
     use std::mem;
+    use thin_vec::ThinVec;
 
     #[cfg(not(parallel_compiler))]
     use std::cell::Cell;
index ac89bec702efddd04e176750b07c452b642d881e..da564c66a70e1519ea72e29c5886d3596bfab84f 100644 (file)
@@ -276,10 +276,23 @@ pub fn sort_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
             }
             ty::Slice(ty) if ty.is_simple_ty() => format!("slice `{}`", self).into(),
             ty::Slice(_) => "slice".into(),
-            ty::RawPtr(_) => "*-ptr".into(),
+            ty::RawPtr(tymut) => {
+                let tymut_string = match tymut.mutbl {
+                    hir::Mutability::Mut => tymut.to_string(),
+                    hir::Mutability::Not => format!("const {}", tymut.ty),
+                };
+
+                if tymut_string != "_" && (tymut.ty.is_simple_text() || tymut_string.len() < "const raw pointer".len()) {
+                    format!("`*{}`", tymut_string).into()
+                } else {
+                    // Unknown type name, it's long or has type arguments
+                    "raw pointer".into()
+                }
+            },
             ty::Ref(_, ty, mutbl) => {
                 let tymut = ty::TypeAndMut { ty, mutbl };
                 let tymut_string = tymut.to_string();
+
                 if tymut_string != "_"
                     && (ty.is_simple_text() || tymut_string.len() < "mutable reference".len())
                 {
index 5e96e278b9cad5f76008b2878a8bdfbe9c89b9af..cb46a9dba579fd6d40a75e0b835cba021d2a7661 100644 (file)
@@ -353,7 +353,7 @@ fn fold_binder<T: TypeFoldable<'tcx>>(
         t
     }
 
-    #[instrument(skip(self), level = "debug")]
+    #[instrument(skip(self), level = "debug", ret)]
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match *r {
             ty::ReLateBound(debruijn, _) if debruijn < self.current_index => {
index 823e7f22af24da43f7655910de9567c5df542f5a..a1d980af921afeb05590a6ae722dc0436146dbb5 100644 (file)
@@ -1,4 +1,3 @@
-use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
 use crate::ty;
 use crate::ty::subst::{Subst, SubstsRef};
 use crate::ty::EarlyBinder;
@@ -13,7 +12,7 @@
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum GenericParamDefKind {
     Lifetime,
-    Type { has_default: bool, object_lifetime_default: ObjectLifetimeDefault, synthetic: bool },
+    Type { has_default: bool, synthetic: bool },
     Const { has_default: bool },
 }
 
@@ -267,7 +266,7 @@ pub fn own_substs_no_defaults(
         // Filter the default arguments.
         //
         // This currently uses structural equality instead
-        // of semantic equivalance. While not ideal, that's
+        // of semantic equivalence. While not ideal, that's
         // good enough for now as this should only be used
         // for diagnostics anyways.
         own_params.end -= self
index cd00b26b8def0b77d72455ecb6fe07dcd4631747..d1c0d62ac6e005aaa90562cd2e382b1409e74c7e 100644 (file)
@@ -113,7 +113,7 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
 }
 
 // `Relocations` with default type parameters is a sorted map.
-impl<'a, Prov> HashStable<StableHashingContext<'a>> for mir::interpret::Relocations<Prov>
+impl<'a, Prov> HashStable<StableHashingContext<'a>> for mir::interpret::ProvenanceMap<Prov>
 where
     Prov: HashStable<StableHashingContext<'a>>,
 {
index 980bb8e861551fc4832fe76d32c9bc6678542dfb..26b60e4f33988b4885dac0fc0d7cfb7a23fc549f 100644 (file)
@@ -756,7 +756,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'
                 // * the element type and length of the single array field, if
                 // the first field is of array type, or
                 //
-                // * the homogenous field type and the number of fields.
+                // * the homogeneous field type and the number of fields.
                 let (e_ty, e_len, is_array) = if let ty::Array(e_ty, _) = f0_ty.kind() {
                     // First ADT field is an array:
 
index 9d8a811659433f6b36b4b2043f714a228d24545d..cac8560ce1c320229dfe789a27695b039160ab26 100644 (file)
@@ -188,13 +188,11 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> {
 }
 
 impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
-    #[instrument(skip(self), level = "debug")]
     fn normalize_generic_arg_after_erasing_regions(
         &self,
         arg: ty::GenericArg<'tcx>,
     ) -> ty::GenericArg<'tcx> {
         let arg = self.param_env.and(arg);
-        debug!(?arg);
 
         self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!(
                 "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead",
index ae6e2eecbffb5f46516c54904a487f75c2d8ca9b..ca24c0d1ce386fc5801be18526395b68e3589677 100644 (file)
@@ -53,7 +53,9 @@ impl $crate::ty::ParameterizedOverTcx for $ty {
     crate::metadata::ModChild,
     crate::middle::codegen_fn_attrs::CodegenFnAttrs,
     crate::middle::exported_symbols::SymbolExportInfo,
+    crate::middle::resolve_lifetime::ObjectLifetimeDefault,
     crate::mir::ConstQualifs,
+    ty::AssocItemContainer,
     ty::Generics,
     ty::ImplPolarity,
     ty::ReprOptions,
index cc55b7e8611af2b6562a2904b5d1c42687aef7c3..329478f27b73c80ec2846f4b7e2e6a89a986b41d 100644 (file)
@@ -1275,7 +1275,7 @@ fn pretty_print_const_scalar_ptr(
                                     let range =
                                         AllocRange { start: offset, size: Size::from_bytes(len) };
                                     if let Ok(byte_str) =
-                                        alloc.inner().get_bytes(&self.tcx(), range)
+                                        alloc.inner().get_bytes_strip_provenance(&self.tcx(), range)
                                     {
                                         p!(pretty_print_byte_str(byte_str))
                                     } else {
@@ -1536,6 +1536,34 @@ fn pretty_print_const_valtree(
         }
         Ok(self)
     }
+
+    fn pretty_closure_as_impl(
+        mut self,
+        closure: ty::ClosureSubsts<'tcx>,
+    ) -> Result<Self::Const, Self::Error> {
+        let sig = closure.sig();
+        let kind = closure.kind_ty().to_opt_closure_kind().unwrap_or(ty::ClosureKind::Fn);
+
+        write!(self, "impl ")?;
+        self.wrap_binder(&sig, |sig, mut cx| {
+            define_scoped_cx!(cx);
+
+            p!(print(kind), "(");
+            for (i, arg) in sig.inputs()[0].tuple_fields().iter().enumerate() {
+                if i > 0 {
+                    p!(", ");
+                }
+                p!(print(arg));
+            }
+            p!(")");
+
+            if !sig.output().is_unit() {
+                p!(" -> ", print(sig.output()));
+            }
+
+            Ok(cx)
+        })
+    }
 }
 
 // HACK(eddyb) boxed to avoid moving around a large struct by-value.
@@ -2450,6 +2478,11 @@ pub fn print_modifiers_and_trait_path(
     }
 }
 
+#[derive(Debug, Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
+pub struct PrintClosureAsImpl<'tcx> {
+    pub closure: ty::ClosureSubsts<'tcx>,
+}
+
 forward_display_to_print! {
     ty::Region<'tcx>,
     Ty<'tcx>,
@@ -2542,6 +2575,10 @@ pub fn print_modifiers_and_trait_path(
         p!(print(self.0.trait_ref.print_only_trait_path()));
     }
 
+    PrintClosureAsImpl<'tcx> {
+        p!(pretty_closure_as_impl(self.closure))
+    }
+
     ty::ParamTy {
         p!(write("{}", self.name))
     }
index 7660a2f3af60a51c64a374fb35a374e1bdccc665..57555433f55b745b54247219bbd1846116c16463 100644 (file)
@@ -844,6 +844,12 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::Br
     }
 }
 
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &[T] {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.iter().try_for_each(|t| t.visit_with(visitor))
+    }
+}
+
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_id(|t| t.try_fold_with(folder))
index 0070575f2136ac8e6c4a36ef4ff4fdaaf04806b3..9fb91b5fe8700032585acf97aaf3b88d4a38c116 100644 (file)
@@ -325,6 +325,10 @@ pub fn sig(self) -> ty::PolyFnSig<'tcx> {
             _ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind()),
         }
     }
+
+    pub fn print_as_impl_trait(self) -> ty::print::PrintClosureAsImpl<'tcx> {
+        ty::print::PrintClosureAsImpl { closure: self }
+    }
 }
 
 /// Similar to `ClosureSubsts`; see the above documentation for more.
@@ -845,6 +849,12 @@ pub fn to_poly_trait_predicate_negative_polarity(&self) -> ty::PolyTraitPredicat
     }
 }
 
+impl rustc_errors::IntoDiagnosticArg for PolyTraitRef<'_> {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        self.to_string().into_diagnostic_arg()
+    }
+}
+
 /// An existential reference to a trait, where `Self` is erased.
 /// For example, the trait object `Trait<'a, 'b, X, Y>` is:
 /// ```ignore (illustrative)
index 541dace5cc2bb5f31964d42799e792ebdab6af2d..ac79949fca5cc40d7ed5391e8e96557ff459e36d 100644 (file)
@@ -256,7 +256,6 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
 }
 
 // Query provider for `incoherent_impls`.
-#[instrument(level = "debug", skip(tcx))]
 pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
     let mut impls = Vec::new();
 
index 591bb7831b5b6375ab98b17f28ecfb389dc26e5a..a3837512bce2652c1155ca2672e06bcb1cd07bdb 100644 (file)
@@ -627,7 +627,7 @@ pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> {
     }
 
     /// Expands the given impl trait type, stopping if the type is recursive.
-    #[instrument(skip(self), level = "debug")]
+    #[instrument(skip(self), level = "debug", ret)]
     pub fn try_expand_impl_trait_type(
         self,
         def_id: DefId,
@@ -644,7 +644,6 @@ pub fn try_expand_impl_trait_type(
         };
 
         let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap();
-        trace!(?expanded_type);
         if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
     }
 
index 5365067209af98042864cd0a8410a0a20170e722..5e042c3acfce25897621b4b4215df93554a266ed 100644 (file)
@@ -84,7 +84,7 @@ fn has_escaping_bound_vars(&self) -> bool {
         self.has_vars_bound_at_or_above(ty::INNERMOST)
     }
 
-    #[instrument(level = "trace")]
+    #[instrument(level = "trace", ret)]
     fn has_type_flags(&self, flags: TypeFlags) -> bool {
         self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags)
     }
@@ -560,7 +560,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
     type BreakTy = FoundFlags;
 
     #[inline]
-    #[instrument(skip(self), level = "trace")]
+    #[instrument(skip(self), level = "trace", ret)]
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = t.flags();
         trace!(t.flags=?t.flags());
@@ -572,7 +572,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
     }
 
     #[inline]
-    #[instrument(skip(self), level = "trace")]
+    #[instrument(skip(self), level = "trace", ret)]
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = r.type_flags();
         trace!(r.flags=?flags);
@@ -584,7 +584,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
     }
 
     #[inline]
-    #[instrument(level = "trace")]
+    #[instrument(level = "trace", ret)]
     fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = FlagComputation::for_const(c);
         trace!(r.flags=?flags);
@@ -596,7 +596,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
     }
 
     #[inline]
-    #[instrument(level = "trace")]
+    #[instrument(level = "trace", ret)]
     fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = FlagComputation::for_unevaluated_const(uv);
         trace!(r.flags=?flags);
@@ -608,7 +608,7 @@ fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::
     }
 
     #[inline]
-    #[instrument(level = "trace")]
+    #[instrument(level = "trace", ret)]
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
         debug!(
             "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
index d5213dc0e0467869d797370d41ef0d564ccd0957..c8d4a1bf2c9e7eeb4ae48231f80208b6aeb8287c 100644 (file)
@@ -117,7 +117,7 @@ fn ast_block_stmts(
                     lint_level,
                     else_block,
                 } => {
-                    let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild);
+                    let ignores_expr_result = matches!(pattern.kind, PatKind::Wild);
                     this.block_context.push(BlockFrame::Statement { ignores_expr_result });
 
                     // Enter the remainder scope, i.e., the bindings' destruction scope.
@@ -160,7 +160,7 @@ fn ast_block_stmts(
                                                 ArmHasGuard(false),
                                                 Some((None, initializer_span)),
                                             );
-                                            this.expr_into_pattern(block, pattern.clone(), init) // irrefutable pattern
+                                            this.expr_into_pattern(block, pattern, init) // irrefutable pattern
                                         }
                                     })
                                 },
index b316a6eeac1ca7e6bee507b919fd342af7edd4e1..3549b47478cbded136bc85a399c75439531a12e3 100644 (file)
@@ -42,10 +42,10 @@ pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
                 Constant { span, user_ty: None, literal }
             }
             ExprKind::NonHirLiteral { lit, ref user_ty } => {
-                let user_ty = user_ty.as_ref().map(|box user_ty| {
+                let user_ty = user_ty.as_ref().map(|user_ty| {
                     this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
                         span,
-                        user_ty: *user_ty,
+                        user_ty: user_ty.clone(),
                         inferred_ty: ty,
                     })
                 });
@@ -54,10 +54,10 @@ pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
                 Constant { span, user_ty: user_ty, literal }
             }
             ExprKind::ZstLiteral { ref user_ty } => {
-                let user_ty = user_ty.as_ref().map(|box user_ty| {
+                let user_ty = user_ty.as_ref().map(|user_ty| {
                     this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
                         span,
-                        user_ty: *user_ty,
+                        user_ty: user_ty.clone(),
                         inferred_ty: ty,
                     })
                 });
@@ -66,10 +66,10 @@ pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
                 Constant { span, user_ty: user_ty, literal }
             }
             ExprKind::NamedConst { def_id, substs, ref user_ty } => {
-                let user_ty = user_ty.as_ref().map(|box user_ty| {
+                let user_ty = user_ty.as_ref().map(|user_ty| {
                     this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
                         span,
-                        user_ty: *user_ty,
+                        user_ty: user_ty.clone(),
                         inferred_ty: ty,
                     })
                 });
index b8277f28cdc4300200b49dab6f758454996ad23a..46dbd8a136b52f1f10017e052c2bbcd68ffe0233 100644 (file)
@@ -522,11 +522,11 @@ fn expr_as_place(
                         fake_borrow_temps,
                     )
                 );
-                if let Some(box user_ty) = user_ty {
+                if let Some(user_ty) = user_ty {
                     let annotation_index =
                         this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
                             span: source_info.span,
-                            user_ty: *user_ty,
+                            user_ty: user_ty.clone(),
                             inferred_ty: expr.ty,
                         });
 
@@ -551,11 +551,11 @@ fn expr_as_place(
                 let source = &this.thir[source];
                 let temp =
                     unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability));
-                if let Some(box user_ty) = user_ty {
+                if let Some(user_ty) = user_ty {
                     let annotation_index =
                         this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
                             span: source_info.span,
-                            user_ty: *user_ty,
+                            user_ty: user_ty.clone(),
                             inferred_ty: expr.ty,
                         });
                     this.cfg.push(
index 48ec7a06724a11d0c11081d2da602d590681fe4c..74509646c17c698f6ca4dc810b2d84447123938b 100644 (file)
@@ -378,10 +378,10 @@ pub(crate) fn expr_into_dest(
                 };
 
                 let inferred_ty = expr.ty;
-                let user_ty = user_ty.as_ref().map(|box user_ty| {
+                let user_ty = user_ty.as_ref().map(|user_ty| {
                     this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
                         span: source_info.span,
-                        user_ty: *user_ty,
+                        user_ty: user_ty.clone(),
                         inferred_ty,
                     })
                 });
index 080dab0303166ea9747f5fce80ab106f5e43d134..a316c2e7d6e187bf1d25a5b7da4c33543cf89695 100644 (file)
@@ -155,7 +155,7 @@ pub(crate) fn then_else_break(
     ///
     /// * From each pre-binding block to the next pre-binding block.
     /// * From each otherwise block to the next pre-binding block.
-    #[tracing::instrument(level = "debug", skip(self, arms))]
+    #[instrument(level = "debug", skip(self, arms))]
     pub(crate) fn match_expr(
         &mut self,
         destination: Place<'tcx>,
@@ -490,10 +490,10 @@ fn bind_pattern(
     pub(super) fn expr_into_pattern(
         &mut self,
         mut block: BasicBlock,
-        irrefutable_pat: Pat<'tcx>,
+        irrefutable_pat: &Pat<'tcx>,
         initializer: &Expr<'tcx>,
     ) -> BlockAnd<()> {
-        match *irrefutable_pat.kind {
+        match irrefutable_pat.kind {
             // Optimize the case of `let x = ...` to write directly into `x`
             PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
                 let place =
@@ -518,17 +518,14 @@ pub(super) fn expr_into_pattern(
             // broken.
             PatKind::AscribeUserType {
                 subpattern:
-                    Pat {
+                    box Pat {
                         kind:
-                            box PatKind::Binding {
-                                mode: BindingMode::ByValue,
-                                var,
-                                subpattern: None,
-                                ..
+                            PatKind::Binding {
+                                mode: BindingMode::ByValue, var, subpattern: None, ..
                             },
                         ..
                     },
-                ascription: thir::Ascription { annotation, variance: _ },
+                ascription: thir::Ascription { ref annotation, variance: _ },
             } => {
                 let place =
                     self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
@@ -541,7 +538,7 @@ pub(super) fn expr_into_pattern(
 
                 let ty_source_info = self.source_info(annotation.span);
 
-                let base = self.canonical_user_type_annotations.push(annotation);
+                let base = self.canonical_user_type_annotations.push(annotation.clone());
                 self.cfg.push(
                     block,
                     Statement {
@@ -581,7 +578,7 @@ pub(super) fn expr_into_pattern(
     pub(crate) fn place_into_pattern(
         &mut self,
         block: BasicBlock,
-        irrefutable_pat: Pat<'tcx>,
+        irrefutable_pat: &Pat<'tcx>,
         initializer: PlaceBuilder<'tcx>,
         set_match_place: bool,
     ) -> BlockAnd<()> {
@@ -702,7 +699,7 @@ pub(crate) fn storage_live_binding(
         let local_id = self.var_local_id(var, for_guard);
         let source_info = self.source_info(span);
         self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
-        // Altough there is almost always scope for given variable in corner cases
+        // Although there is almost always scope for given variable in corner cases
         // like #92893 we might get variable with no scope.
         if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop{
             self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
@@ -744,7 +741,7 @@ pub(super) fn visit_primary_bindings(
             "visit_primary_bindings: pattern={:?} pattern_user_ty={:?}",
             pattern, pattern_user_ty
         );
-        match *pattern.kind {
+        match pattern.kind {
             PatKind::Binding {
                 mutability,
                 name,
@@ -767,7 +764,7 @@ pub(super) fn visit_primary_bindings(
             | PatKind::Slice { ref prefix, ref slice, ref suffix } => {
                 let from = u64::try_from(prefix.len()).unwrap();
                 let to = u64::try_from(suffix.len()).unwrap();
-                for subpattern in prefix {
+                for subpattern in prefix.iter() {
                     self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
                 }
                 for subpattern in slice {
@@ -777,7 +774,7 @@ pub(super) fn visit_primary_bindings(
                         f,
                     );
                 }
-                for subpattern in suffix {
+                for subpattern in suffix.iter() {
                     self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
                 }
             }
@@ -830,7 +827,7 @@ pub(super) fn visit_primary_bindings(
                 // may not all be in the leftmost subpattern. For example in
                 // `let (x | y) = ...`, the primary binding of `y` occurs in
                 // the right subpattern
-                for subpattern in pats {
+                for subpattern in pats.iter() {
                     self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f);
                 }
             }
@@ -982,7 +979,7 @@ enum TestKind<'tcx> {
     },
 
     /// Test whether the value falls within an inclusive or exclusive range
-    Range(PatRange<'tcx>),
+    Range(Box<PatRange<'tcx>>),
 
     /// Test that the length of the slice is equal to `len`.
     Len { len: u64, op: BinOp },
@@ -1330,7 +1327,7 @@ fn test_candidates_with_or(
 
         // All of the or-patterns have been sorted to the end, so if the first
         // pattern is an or-pattern we only have or-patterns.
-        match *first_candidate.match_pairs[0].pattern.kind {
+        match first_candidate.match_pairs[0].pattern.kind {
             PatKind::Or { .. } => (),
             _ => {
                 self.test_candidates(
@@ -1350,7 +1347,7 @@ fn test_candidates_with_or(
 
         let mut otherwise = None;
         for match_pair in match_pairs {
-            let PatKind::Or { ref pats } = &*match_pair.pattern.kind else {
+            let PatKind::Or { ref pats } = &match_pair.pattern.kind else {
                 bug!("Or-patterns should have been sorted to the end");
             };
             let or_span = match_pair.pattern.span;
@@ -1384,7 +1381,7 @@ fn test_or_pattern<'pat>(
         &mut self,
         candidate: &mut Candidate<'pat, 'tcx>,
         otherwise: &mut Option<BasicBlock>,
-        pats: &'pat [Pat<'tcx>],
+        pats: &'pat [Box<Pat<'tcx>>],
         or_span: Span,
         place: PlaceBuilder<'tcx>,
         fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
@@ -2289,7 +2286,7 @@ pub(crate) fn ast_let_else(
         let else_block_span = self.thir[else_block].span;
         let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| {
             let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span));
-            let pat = Pat { ty: init.ty, span: else_block_span, kind: Box::new(PatKind::Wild) };
+            let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild };
             let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
             this.declare_bindings(
                 visibility_scope,
index c6298904140c39ef9166191ac078d9b597ba18ed..55ed09da64fb866162cddda8d9d6809d360c6f5f 100644 (file)
@@ -67,7 +67,7 @@ pub(super) fn simplify_candidate<'pat>(
         loop {
             let match_pairs = mem::take(&mut candidate.match_pairs);
 
-            if let [MatchPair { pattern: Pat { kind: box PatKind::Or { pats }, .. }, place }] =
+            if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] =
                 &*match_pairs
             {
                 existing_bindings.extend_from_slice(&new_bindings);
@@ -113,7 +113,7 @@ pub(super) fn simplify_candidate<'pat>(
                 // late as possible.
                 candidate
                     .match_pairs
-                    .sort_by_key(|pair| matches!(*pair.pattern.kind, PatKind::Or { .. }));
+                    .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. }));
                 debug!(simplified = ?candidate, "simplify_candidate");
                 return false; // if we were not able to simplify any, done.
             }
@@ -127,10 +127,10 @@ fn create_or_subcandidates<'pat>(
         &mut self,
         candidate: &Candidate<'pat, 'tcx>,
         place: PlaceBuilder<'tcx>,
-        pats: &'pat [Pat<'tcx>],
+        pats: &'pat [Box<Pat<'tcx>>],
     ) -> Vec<Candidate<'pat, 'tcx>> {
         pats.iter()
-            .map(|pat| {
+            .map(|box pat| {
                 let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard);
                 self.simplify_candidate(&mut candidate);
                 candidate
@@ -149,7 +149,7 @@ fn simplify_match_pair<'pat>(
         candidate: &mut Candidate<'pat, 'tcx>,
     ) -> Result<(), MatchPair<'pat, 'tcx>> {
         let tcx = self.tcx;
-        match *match_pair.pattern.kind {
+        match match_pair.pattern.kind {
             PatKind::AscribeUserType {
                 ref subpattern,
                 ascription: thir::Ascription { ref annotation, variance },
@@ -208,7 +208,7 @@ fn simplify_match_pair<'pat>(
                 Err(match_pair)
             }
 
-            PatKind::Range(PatRange { lo, hi, end }) => {
+            PatKind::Range(box PatRange { lo, hi, end }) => {
                 let (range, bias) = match *lo.ty().kind() {
                     ty::Char => {
                         (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
@@ -254,7 +254,7 @@ fn simplify_match_pair<'pat>(
                         &mut candidate.match_pairs,
                         &match_pair.place,
                         prefix,
-                        slice.as_ref(),
+                        slice,
                         suffix,
                     );
                     Ok(())
@@ -294,7 +294,7 @@ fn simplify_match_pair<'pat>(
                     &mut candidate.match_pairs,
                     &match_pair.place,
                     prefix,
-                    slice.as_ref(),
+                    slice,
                     suffix,
                 );
                 Ok(())
index 598da80c574aff45ba7d4684fb4d307c86f16dd0..19c303e0bab7400ba0d8e48552ccd0233db9dcc9 100644 (file)
@@ -29,7 +29,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ///
     /// It is a bug to call this with a not-fully-simplified pattern.
     pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
-        match *match_pair.pattern.kind {
+        match match_pair.pattern.kind {
             PatKind::Variant { adt_def, substs: _, variant_index: _, subpatterns: _ } => Test {
                 span: match_pair.pattern.span,
                 kind: TestKind::Switch {
@@ -58,10 +58,10 @@ pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<
                 kind: TestKind::Eq { value, ty: match_pair.pattern.ty },
             },
 
-            PatKind::Range(range) => {
+            PatKind::Range(ref range) => {
                 assert_eq!(range.lo.ty(), match_pair.pattern.ty);
                 assert_eq!(range.hi.ty(), match_pair.pattern.ty);
-                Test { span: match_pair.pattern.span, kind: TestKind::Range(range) }
+                Test { span: match_pair.pattern.span, kind: TestKind::Range(range.clone()) }
             }
 
             PatKind::Slice { ref prefix, ref slice, ref suffix } => {
@@ -92,7 +92,7 @@ pub(super) fn add_cases_to_switch<'pat>(
             return false;
         };
 
-        match *match_pair.pattern.kind {
+        match match_pair.pattern.kind {
             PatKind::Constant { value } => {
                 options
                     .entry(value)
@@ -102,9 +102,9 @@ pub(super) fn add_cases_to_switch<'pat>(
             PatKind::Variant { .. } => {
                 panic!("you should have called add_variants_to_switch instead!");
             }
-            PatKind::Range(range) => {
+            PatKind::Range(ref range) => {
                 // Check that none of the switch values are in the range.
-                self.values_not_contained_in_range(range, options).unwrap_or(false)
+                self.values_not_contained_in_range(&*range, options).unwrap_or(false)
             }
             PatKind::Slice { .. }
             | PatKind::Array { .. }
@@ -130,7 +130,7 @@ pub(super) fn add_variants_to_switch<'pat>(
             return false;
         };
 
-        match *match_pair.pattern.kind {
+        match match_pair.pattern.kind {
             PatKind::Variant { adt_def: _, variant_index, .. } => {
                 // We have a pattern testing for variant `variant_index`
                 // set the corresponding index to true
@@ -272,7 +272,7 @@ pub(super) fn perform_test(
                 }
             }
 
-            TestKind::Range(PatRange { lo, hi, ref end }) => {
+            TestKind::Range(box PatRange { lo, hi, ref end }) => {
                 let lower_bound_success = self.cfg.start_new_block();
                 let target_blocks = make_target_blocks(self);
 
@@ -506,7 +506,7 @@ pub(super) fn sort_candidate<'pat>(
         let (match_pair_index, match_pair) =
             candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?;
 
-        match (&test.kind, &*match_pair.pattern.kind) {
+        match (&test.kind, &match_pair.pattern.kind) {
             // If we are performing a variant switch, then this
             // informs variant patterns, but nothing else.
             (
@@ -540,9 +540,9 @@ pub(super) fn sort_candidate<'pat>(
                 Some(index)
             }
 
-            (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(range)) => {
+            (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(ref range)) => {
                 let not_contained =
-                    self.values_not_contained_in_range(range, options).unwrap_or(false);
+                    self.values_not_contained_in_range(&*range, options).unwrap_or(false);
 
                 if not_contained {
                     // No switch values are contained in the pattern range,
@@ -569,7 +569,7 @@ pub(super) fn sort_candidate<'pat>(
                             match_pair_index,
                             candidate,
                             prefix,
-                            slice.as_ref(),
+                            slice,
                             suffix,
                         );
                         Some(0)
@@ -607,7 +607,7 @@ pub(super) fn sort_candidate<'pat>(
                             match_pair_index,
                             candidate,
                             prefix,
-                            slice.as_ref(),
+                            slice,
                             suffix,
                         );
                         Some(0)
@@ -631,7 +631,7 @@ pub(super) fn sort_candidate<'pat>(
                 }
             }
 
-            (&TestKind::Range(test), &PatKind::Range(pat)) => {
+            (&TestKind::Range(ref test), &PatKind::Range(ref pat)) => {
                 use std::cmp::Ordering::*;
 
                 if test == pat {
@@ -658,8 +658,8 @@ pub(super) fn sort_candidate<'pat>(
                 no_overlap
             }
 
-            (&TestKind::Range(range), &PatKind::Constant { value }) => {
-                if let Some(false) = self.const_range_contains(range, value) {
+            (&TestKind::Range(ref range), &PatKind::Constant { value }) => {
+                if let Some(false) = self.const_range_contains(&*range, value) {
                     // `value` is not contained in the testing range,
                     // so `value` can be matched only if this test fails.
                     Some(1)
@@ -678,7 +678,7 @@ pub(super) fn sort_candidate<'pat>(
                 // However, at this point we can still encounter or-patterns that were extracted
                 // from previous calls to `sort_candidate`, so we need to manually address that
                 // case to avoid panicking in `self.test()`.
-                if let PatKind::Or { .. } = &*match_pair.pattern.kind {
+                if let PatKind::Or { .. } = &match_pair.pattern.kind {
                     return None;
                 }
 
@@ -708,9 +708,9 @@ fn candidate_after_slice_test<'pat>(
         &mut self,
         match_pair_index: usize,
         candidate: &mut Candidate<'pat, 'tcx>,
-        prefix: &'pat [Pat<'tcx>],
-        opt_slice: Option<&'pat Pat<'tcx>>,
-        suffix: &'pat [Pat<'tcx>],
+        prefix: &'pat [Box<Pat<'tcx>>],
+        opt_slice: &'pat Option<Box<Pat<'tcx>>>,
+        suffix: &'pat [Box<Pat<'tcx>>],
     ) {
         let removed_place = candidate.match_pairs.remove(match_pair_index).place;
         self.prefix_slice_suffix(
@@ -754,7 +754,7 @@ fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> !
 
     fn const_range_contains(
         &self,
-        range: PatRange<'tcx>,
+        range: &PatRange<'tcx>,
         value: ConstantKind<'tcx>,
     ) -> Option<bool> {
         use std::cmp::Ordering::*;
@@ -772,7 +772,7 @@ fn const_range_contains(
 
     fn values_not_contained_in_range(
         &self,
-        range: PatRange<'tcx>,
+        range: &PatRange<'tcx>,
         options: &FxIndexMap<ConstantKind<'tcx>, u128>,
     ) -> Option<bool> {
         for &val in options.keys() {
index 9a1e98d3bb18ddc8d6b6e646a1de00610ae4ae33..06f24040f7be05d80cbd277c2f41dd947cb235d2 100644 (file)
@@ -26,9 +26,9 @@ pub(crate) fn prefix_slice_suffix<'pat>(
         &mut self,
         match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>,
         place: &PlaceBuilder<'tcx>,
-        prefix: &'pat [Pat<'tcx>],
-        opt_slice: Option<&'pat Pat<'tcx>>,
-        suffix: &'pat [Pat<'tcx>],
+        prefix: &'pat [Box<Pat<'tcx>>],
+        opt_slice: &'pat Option<Box<Pat<'tcx>>>,
+        suffix: &'pat [Box<Pat<'tcx>>],
     ) {
         let tcx = self.tcx;
         let (min_length, exact_size) = if let Ok(place_resolved) =
index 684b228e87fa983ef3b778fe587c41f354fc7c3b..763038c52d7fab8d54a003b1e94cc5fda9d47605 100644 (file)
@@ -1015,7 +1015,7 @@ fn args_and_body(
             let original_source_scope = self.source_scope;
             let span = pattern.span;
             self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
-            match *pattern.kind {
+            match pattern.kind {
                 // Don't introduce extra copies for simple bindings
                 PatKind::Binding {
                     mutability,
@@ -1052,7 +1052,10 @@ fn args_and_body(
                         Some((Some(&place), span)),
                     );
                     let place_builder = PlaceBuilder::from(local);
-                    unpack!(block = self.place_into_pattern(block, pattern, place_builder, false));
+                    unpack!(
+                        block =
+                            self.place_into_pattern(block, pattern.as_ref(), place_builder, false)
+                    );
                 }
             }
             self.source_scope = original_source_scope;
index bf5a2e7c73fabf8a36ac3e9a01bd0fc8f83cdbdb..495738ebe1c7ac9d392af26ac38f9e4bd6a309c1 100644 (file)
@@ -214,7 +214,7 @@ fn visit_block(&mut self, block: &Block) {
 
     fn visit_pat(&mut self, pat: &Pat<'tcx>) {
         if self.in_union_destructure {
-            match *pat.kind {
+            match pat.kind {
                 // binding to a variable allows getting stuff out of variable
                 PatKind::Binding { .. }
                 // match is conditional on having this value
@@ -236,7 +236,7 @@ fn visit_pat(&mut self, pat: &Pat<'tcx>) {
             }
         };
 
-        match &*pat.kind {
+        match &pat.kind {
             PatKind::Leaf { .. } => {
                 if let ty::Adt(adt_def, ..) = pat.ty.kind() {
                     if adt_def.is_union() {
index e51ca65dc16b1bb820c082c172d64dd78bef5416..11cd2a9aa4dea9b03ed61d3e6658aa0ad15084fe 100644 (file)
@@ -5,6 +5,7 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(if_let_guard)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(once_cell)]
index 54c4b9eda70dc16a8115c1a0a9ff8334ed383466..321353ca20bae01f30992f1137fe109c582afd29 100644 (file)
@@ -87,21 +87,21 @@ fn mirror_stmts(
                             {
                                 debug!("mirror_stmts: user_ty={:?}", user_ty);
                                 let annotation = CanonicalUserTypeAnnotation {
-                                    user_ty,
+                                    user_ty: Box::new(user_ty),
                                     span: ty.span,
                                     inferred_ty: self.typeck_results.node_type(ty.hir_id),
                                 };
-                                pattern = Pat {
+                                pattern = Box::new(Pat {
                                     ty: pattern.ty,
                                     span: pattern.span,
-                                    kind: Box::new(PatKind::AscribeUserType {
+                                    kind: PatKind::AscribeUserType {
                                         ascription: Ascription {
                                             annotation,
                                             variance: ty::Variance::Covariant,
                                         },
                                         subpattern: pattern,
-                                    }),
-                                };
+                                    },
+                                });
                             }
                         }
 
index 0c2b117453fe9ed5785a444d4ee0deff4186f34b..9ed1c064d2b7f3ea651eb303c9e7824dbbdba8ec 100644 (file)
@@ -268,7 +268,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                 // the overall method call for better diagnostics. args[0]
                 // is guaranteed to exist, since a method call always has a receiver.
                 let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span));
-                tracing::info!("Using method span: {:?}", expr.span);
+                info!("Using method span: {:?}", expr.span);
                 let args = self.mirror_exprs(args);
                 self.adjustment_span = old_adjustment_span;
                 ExprKind::Call {
index f7351a4caa9545250d59dcbf5c21a146724fcc27..ae53df1f9b9a4166353f93f22b96d54791dfe52f 100644 (file)
@@ -77,8 +77,8 @@ fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> {
         }
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
-    pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
+    #[instrument(level = "debug", skip(self))]
+    pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Box<Pat<'tcx>> {
         let p = match self.tcx.hir().get(p.hir_id) {
             Node::Pat(p) => p,
             node => bug!("pattern became {:?}", node),
index f2045ac19cac42920293ecc3b71d865cf5cb29a9..b58685e895809b266d76df47122f3add615fad3a 100644 (file)
@@ -19,21 +19,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     /// Converts an evaluated constant to a pattern (if possible).
     /// This means aggregate values (like structs and enums) are converted
     /// to a pattern that matches the value (as if you'd compared via structural equality).
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     pub(super) fn const_to_pat(
         &self,
         cv: mir::ConstantKind<'tcx>,
         id: hir::HirId,
         span: Span,
         mir_structural_match_violation: bool,
-    ) -> Pat<'tcx> {
-        let pat = self.tcx.infer_ctxt().enter(|infcx| {
+    ) -> Box<Pat<'tcx>> {
+        self.tcx.infer_ctxt().enter(|infcx| {
             let mut convert = ConstToPat::new(self, id, span, infcx);
             convert.to_pat(cv, mir_structural_match_violation)
-        });
-
-        debug!(?pat);
-        pat
+        })
     }
 }
 
@@ -159,7 +156,7 @@ fn to_pat(
         &mut self,
         cv: mir::ConstantKind<'tcx>,
         mir_structural_match_violation: bool,
-    ) -> Pat<'tcx> {
+    ) -> Box<Pat<'tcx>> {
         trace!(self.treat_byte_string_as_slice);
         // This method is just a wrapper handling a validity check; the heavy lifting is
         // performed by the recursive `recur` method, which is not meant to be
@@ -169,10 +166,12 @@ fn to_pat(
         // level of indirection can be eliminated
 
         let inlined_const_as_pat =
-            self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| Pat {
-                span: self.span,
-                ty: cv.ty(),
-                kind: Box::new(PatKind::Constant { value: cv }),
+            self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| {
+                Box::new(Pat {
+                    span: self.span,
+                    ty: cv.ty(),
+                    kind: PatKind::Constant { value: cv },
+                })
             });
 
         if self.include_lint_checks && !self.saw_const_match_error.get() {
@@ -274,7 +273,7 @@ fn recur(
         &self,
         cv: mir::ConstantKind<'tcx>,
         mir_structural_match_violation: bool,
-    ) -> Result<Pat<'tcx>, FallbackToConstRef> {
+    ) -> Result<Box<Pat<'tcx>>, FallbackToConstRef> {
         let id = self.id;
         let span = self.span;
         let tcx = self.tcx();
@@ -401,7 +400,7 @@ fn recur(
                     .map(|val| self.recur(*val, false))
                     .collect::<Result<_, _>>()?,
                 slice: None,
-                suffix: Vec::new(),
+                suffix: Box::new([]),
             },
             ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
                 // These are not allowed and will error elsewhere anyway.
@@ -428,8 +427,8 @@ fn recur(
                     let old = self.behind_reference.replace(true);
                     let array = tcx.deref_mir_constant(self.param_env.and(cv));
                     let val = PatKind::Deref {
-                        subpattern: Pat {
-                            kind: Box::new(PatKind::Array {
+                        subpattern: Box::new(Pat {
+                            kind: PatKind::Array {
                                 prefix: tcx
                                     .destructure_mir_constant(param_env, array)
                                     .fields
@@ -437,11 +436,11 @@ fn recur(
                                     .map(|val| self.recur(*val, false))
                                     .collect::<Result<_, _>>()?,
                                 slice: None,
-                                suffix: vec![],
-                            }),
+                                suffix: Box::new([]),
+                            },
                             span,
                             ty: *pointee_ty,
-                        },
+                        }),
                     };
                     self.behind_reference.set(old);
                     val
@@ -454,8 +453,8 @@ fn recur(
                     let old = self.behind_reference.replace(true);
                     let array = tcx.deref_mir_constant(self.param_env.and(cv));
                     let val = PatKind::Deref {
-                        subpattern: Pat {
-                            kind: Box::new(PatKind::Slice {
+                        subpattern: Box::new(Pat {
+                            kind: PatKind::Slice {
                                 prefix: tcx
                                     .destructure_mir_constant(param_env, array)
                                     .fields
@@ -463,11 +462,11 @@ fn recur(
                                     .map(|val| self.recur(*val, false))
                                     .collect::<Result<_, _>>()?,
                                 slice: None,
-                                suffix: vec![],
-                            }),
+                                suffix: Box::new([]),
+                            },
                             span,
                             ty: tcx.mk_slice(elem_ty),
-                        },
+                        }),
                     };
                     self.behind_reference.set(old);
                     val
@@ -601,6 +600,6 @@ fn recur(
             );
         }
 
-        Ok(Pat { span, ty: cv.ty(), kind: Box::new(kind) })
+        Ok(Box::new(Pat { span, ty: cv.ty(), kind }))
     }
 }
index 8d6f8efb6003f9fd7745b02e331859f14cc3ab77..5105f059f9b64797317ac251dc630389a8a1ceb8 100644 (file)
@@ -71,9 +71,9 @@
 /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
 fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
     fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
-        if let PatKind::Or { pats } = pat.kind.as_ref() {
-            for pat in pats {
-                expand(pat, vec);
+        if let PatKind::Or { pats } = &pat.kind {
+            for pat in pats.iter() {
+                expand(&pat, vec);
             }
         } else {
             vec.push(pat)
@@ -252,10 +252,14 @@ fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
         let kind = if lo == hi {
             PatKind::Constant { value: lo_const }
         } else {
-            PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included })
+            PatKind::Range(Box::new(PatRange {
+                lo: lo_const,
+                hi: hi_const,
+                end: RangeEnd::Included,
+            }))
         };
 
-        Pat { ty, span: DUMMY_SP, kind: Box::new(kind) }
+        Pat { ty, span: DUMMY_SP, kind }
     }
 
     /// Lint on likely incorrect range patterns (#63987)
@@ -1297,7 +1301,7 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
         let mkpat = |pat| DeconstructedPat::from_pat(cx, pat);
         let ctor;
         let fields;
-        match pat.kind.as_ref() {
+        match &pat.kind {
             PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern),
             PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat),
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
@@ -1342,9 +1346,9 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
                         fields = Fields::singleton(cx, pat);
                     }
                     ty::Adt(adt, _) => {
-                        ctor = match pat.kind.as_ref() {
+                        ctor = match pat.kind {
                             PatKind::Leaf { .. } => Single,
-                            PatKind::Variant { variant_index, .. } => Variant(*variant_index),
+                            PatKind::Variant { variant_index, .. } => Variant(variant_index),
                             _ => bug!(),
                         };
                         let variant = &adt.variant(ctor.variant_index_for_adt(*adt));
@@ -1402,7 +1406,7 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
                     }
                 }
             }
-            &PatKind::Range(PatRange { lo, hi, end }) => {
+            &PatKind::Range(box PatRange { lo, hi, end }) => {
                 let ty = lo.ty();
                 ctor = if let Some(int_range) = IntRange::from_range(
                     cx.tcx,
@@ -1429,7 +1433,8 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
                     FixedLen(prefix.len() + suffix.len())
                 };
                 ctor = Slice(Slice::new(array_len, kind));
-                fields = Fields::from_iter(cx, prefix.iter().chain(suffix).map(mkpat));
+                fields =
+                    Fields::from_iter(cx, prefix.iter().chain(suffix.iter()).map(|p| mkpat(&*p)));
             }
             PatKind::Or { .. } => {
                 ctor = Or;
@@ -1442,15 +1447,15 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
 
     pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> {
         let is_wildcard = |pat: &Pat<'_>| {
-            matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
+            matches!(pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
         };
-        let mut subpatterns = self.iter_fields().map(|p| p.to_pat(cx));
-        let pat = match &self.ctor {
+        let mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx)));
+        let kind = match &self.ctor {
             Single | Variant(_) => match self.ty.kind() {
                 ty::Tuple(..) => PatKind::Leaf {
                     subpatterns: subpatterns
                         .enumerate()
-                        .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
+                        .map(|(i, pattern)| FieldPat { field: Field::new(i), pattern })
                         .collect(),
                 },
                 ty::Adt(adt_def, _) if adt_def.is_box() => {
@@ -1485,7 +1490,7 @@ pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> {
                     FixedLen(_) => PatKind::Slice {
                         prefix: subpatterns.collect(),
                         slice: None,
-                        suffix: vec![],
+                        suffix: Box::new([]),
                     },
                     VarLen(prefix, _) => {
                         let mut subpatterns = subpatterns.peekable();
@@ -1504,14 +1509,18 @@ pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> {
                                 subpatterns.next();
                             }
                         }
-                        let suffix: Vec<_> = subpatterns.collect();
+                        let suffix: Box<[_]> = subpatterns.collect();
                         let wild = Pat::wildcard_from_ty(self.ty);
-                        PatKind::Slice { prefix, slice: Some(wild), suffix }
+                        PatKind::Slice {
+                            prefix: prefix.into_boxed_slice(),
+                            slice: Some(Box::new(wild)),
+                            suffix,
+                        }
                     }
                 }
             }
             &Str(value) => PatKind::Constant { value },
-            &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
+            &FloatRange(lo, hi, end) => PatKind::Range(Box::new(PatRange { lo, hi, end })),
             IntRange(range) => return range.to_pat(cx.tcx, self.ty),
             Wildcard | NonExhaustive => PatKind::Wild,
             Missing { .. } => bug!(
@@ -1523,7 +1532,7 @@ pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> {
             }
         };
 
-        Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(pat) }
+        Pat { ty: self.ty, span: DUMMY_SP, kind }
     }
 
     pub(super) fn is_or_pat(&self) -> bool {
index a13748a2d474ad1b92e74f24de438222379b376b..d2f93b679acc596a89525e118f23a06dfcc385eb 100644 (file)
@@ -49,7 +49,7 @@ pub(crate) fn pat_from_hir<'a, 'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     typeck_results: &'a ty::TypeckResults<'tcx>,
     pat: &'tcx hir::Pat<'tcx>,
-) -> Pat<'tcx> {
+) -> Box<Pat<'tcx>> {
     let mut pcx = PatCtxt::new(tcx, param_env, typeck_results);
     let result = pcx.lower_pattern(pat);
     if !pcx.errors.is_empty() {
@@ -74,7 +74,7 @@ pub(crate) fn include_lint_checks(&mut self) -> &mut Self {
         self
     }
 
-    pub(crate) fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
+    pub(crate) fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
         // When implicit dereferences have been inserted in this pattern, the unadjusted lowered
         // pattern has the type that results *after* dereferencing. For example, in this code:
         //
@@ -97,13 +97,13 @@ pub(crate) fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
         let unadjusted_pat = self.lower_pattern_unadjusted(pat);
         self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
             unadjusted_pat,
-            |pat, ref_ty| {
+            |pat: Box<_>, ref_ty| {
                 debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
-                Pat {
+                Box::new(Pat {
                     span: pat.span,
                     ty: *ref_ty,
-                    kind: Box::new(PatKind::Deref { subpattern: pat }),
-                }
+                    kind: PatKind::Deref { subpattern: pat },
+                })
             },
         )
     }
@@ -113,7 +113,7 @@ fn lower_range_expr(
         expr: &'tcx hir::Expr<'tcx>,
     ) -> (PatKind<'tcx>, Option<Ascription<'tcx>>) {
         match self.lower_lit(expr) {
-            PatKind::AscribeUserType { ascription, subpattern: Pat { kind: box kind, .. } } => {
+            PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
                 (kind, Some(ascription))
             }
             kind => (kind, None),
@@ -134,7 +134,9 @@ fn lower_pattern_range(
         match (end, cmp) {
             // `x..y` where `x < y`.
             // Non-empty because the range includes at least `x`.
-            (RangeEnd::Excluded, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }),
+            (RangeEnd::Excluded, Some(Ordering::Less)) => {
+                PatKind::Range(Box::new(PatRange { lo, hi, end }))
+            }
             // `x..y` where `x >= y`. The range is empty => error.
             (RangeEnd::Excluded, _) => {
                 struct_span_err!(
@@ -149,7 +151,9 @@ fn lower_pattern_range(
             // `x..=y` where `x == y`.
             (RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo },
             // `x..=y` where `x < y`.
-            (RangeEnd::Included, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }),
+            (RangeEnd::Included, Some(Ordering::Less)) => {
+                PatKind::Range(Box::new(PatRange { lo, hi, end }))
+            }
             // `x..=y` where `x > y` hence the range is empty => error.
             (RangeEnd::Included, _) => {
                 let mut err = struct_span_err!(
@@ -196,7 +200,7 @@ fn normalize_range_pattern_ends(
         }
     }
 
-    fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
+    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 kind = match pat.kind {
@@ -228,7 +232,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
                 // constants somewhere. Have them on the range pattern.
                 for end in &[lo, hi] {
                     if let Some((_, Some(ascription))) = end {
-                        let subpattern = Pat { span: pat.span, ty, kind: Box::new(kind) };
+                        let subpattern = Box::new(Pat { span: pat.span, ty, kind });
                         kind =
                             PatKind::AscribeUserType { ascription: ascription.clone(), subpattern };
                     }
@@ -322,7 +326,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
             hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) },
         };
 
-        Pat { span: pat.span, ty, kind: Box::new(kind) }
+        Box::new(Pat { span: pat.span, ty, kind })
     }
 
     fn lower_tuple_subpats(
@@ -340,11 +344,14 @@ fn lower_tuple_subpats(
             .collect()
     }
 
-    fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Vec<Pat<'tcx>> {
+    fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Box<Pat<'tcx>>]> {
         pats.iter().map(|p| self.lower_pattern(p)).collect()
     }
 
-    fn lower_opt_pattern(&mut self, pat: &'tcx Option<&'tcx hir::Pat<'tcx>>) -> Option<Pat<'tcx>> {
+    fn lower_opt_pattern(
+        &mut self,
+        pat: &'tcx Option<&'tcx hir::Pat<'tcx>>,
+    ) -> Option<Box<Pat<'tcx>>> {
         pat.as_ref().map(|p| self.lower_pattern(p))
     }
 
@@ -436,12 +443,12 @@ fn lower_variant_or_leaf(
         if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
             debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
             let annotation = CanonicalUserTypeAnnotation {
-                user_ty,
+                user_ty: Box::new(user_ty),
                 span,
                 inferred_ty: self.typeck_results.node_type(hir_id),
             };
             kind = PatKind::AscribeUserType {
-                subpattern: Pat { span, ty, kind: Box::new(kind) },
+                subpattern: Box::new(Pat { span, ty, kind }),
                 ascription: Ascription { annotation, variance: ty::Variance::Covariant },
             };
         }
@@ -453,11 +460,11 @@ fn lower_variant_or_leaf(
     /// it to `const_to_pat`. Any other path (like enum variants without fields)
     /// is converted to the corresponding pattern via `lower_variant_or_leaf`.
     #[instrument(skip(self), level = "debug")]
-    fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Pat<'tcx> {
+    fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box<Pat<'tcx>> {
         let ty = self.typeck_results.node_type(id);
         let res = self.typeck_results.qpath_res(qpath, id);
 
-        let pat_from_kind = |kind| Pat { span, ty, kind: Box::new(kind) };
+        let pat_from_kind = |kind| Box::new(Pat { span, ty, kind });
 
         let (def_id, is_associated_const) = match res {
             Res::Def(DefKind::Const, def_id) => (def_id, false),
@@ -505,13 +512,13 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
                 let user_provided_types = self.typeck_results().user_provided_types();
                 if let Some(&user_ty) = user_provided_types.get(id) {
                     let annotation = CanonicalUserTypeAnnotation {
-                        user_ty,
+                        user_ty: Box::new(user_ty),
                         span,
                         inferred_ty: self.typeck_results().node_type(id),
                     };
-                    Pat {
+                    Box::new(Pat {
                         span,
-                        kind: Box::new(PatKind::AscribeUserType {
+                        kind: PatKind::AscribeUserType {
                             subpattern: pattern,
                             ascription: Ascription {
                                 annotation,
@@ -519,9 +526,9 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
                                 /// `variance` field documentation for details.
                                 variance: ty::Variance::Contravariant,
                             },
-                        }),
+                        },
                         ty: const_.ty(),
-                    }
+                    })
                 } else {
                     pattern
                 }
@@ -569,7 +576,7 @@ fn lower_inline_const(
                     _ => bug!("Expected either ConstKind::Param or ConstKind::Unevaluated"),
                 }
             }
-            mir::ConstantKind::Val(_, _) => *self.const_to_pat(value, id, span, false).kind,
+            mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind,
         }
     }
 
@@ -580,7 +587,7 @@ fn lower_inline_const(
     fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
         let (lit, neg) = match expr.kind {
             hir::ExprKind::Path(ref qpath) => {
-                return *self.lower_path(qpath, expr.hir_id, expr.span).kind;
+                return self.lower_path(qpath, expr.hir_id, expr.span).kind;
             }
             hir::ExprKind::ConstBlock(ref anon_const) => {
                 return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
@@ -598,7 +605,7 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
         let lit_input =
             LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
         match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) {
-            Ok(constant) => *self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
+            Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
             Err(LitToConstError::Reported) => PatKind::Wild,
             Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
         }
@@ -646,6 +653,12 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
     }
 }
 
+impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<[T]> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        self.iter().map(|t| t.fold_with(folder)).collect()
+    }
+}
+
 impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
     fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
         self.as_ref().map(|t| t.fold_with(folder))
@@ -732,7 +745,7 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
                 PatKind::Deref { subpattern: subpattern.fold_with(folder) }
             }
             PatKind::Constant { value } => PatKind::Constant { value },
-            PatKind::Range(range) => PatKind::Range(range),
+            PatKind::Range(ref range) => PatKind::Range(range.clone()),
             PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice {
                 prefix: prefix.fold_with(folder),
                 slice: slice.fold_with(folder),
index 443626d14b9f67c636bed05f1a7483d9366ce79d..319183eb9b33fc7e0a81f15cedd6f87cd641ad88 100644 (file)
@@ -791,7 +791,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
 /// `is_under_guard` is used to inform if the pattern has a guard. If it
 /// has one it must not be inserted into the matrix. This shouldn't be
 /// relied on for soundness.
-#[instrument(level = "debug", skip(cx, matrix, hir_id))]
+#[instrument(level = "debug", skip(cx, matrix, hir_id), ret)]
 fn is_useful<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     matrix: &Matrix<'p, 'tcx>,
@@ -917,7 +917,6 @@ fn is_useful<'p, 'tcx>(
         v.head().set_reachable();
     }
 
-    debug!(?ret);
     ret
 }
 
index 5c9f4f57243b7bc5cf265bf61ee965c22fc7f39c..53f33a7a0bad2516cde21120e629806b0898fa09 100644 (file)
@@ -243,24 +243,6 @@ fn binary_ptr_op(
         throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
     }
 
-    fn access_local<'a>(
-        frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
-        local: Local,
-    ) -> InterpResult<'tcx, &'a interpret::Operand<Self::Provenance>> {
-        let l = &frame.locals[local];
-
-        if matches!(
-            l.value,
-            LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit))
-        ) {
-            // For us "uninit" means "we don't know its value, might be initiailized or not".
-            // So stop here.
-            throw_machine_stop_str!("tried to access alocal with unknown value ")
-        }
-
-        l.access()
-    }
-
     fn access_local_mut<'a>(
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
         frame: usize,
@@ -431,7 +413,13 @@ fn new(
 
     fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
         let op = match self.ecx.eval_place_to_op(place, None) {
-            Ok(op) => op,
+            Ok(op) => {
+                if matches!(*op, interpret::Operand::Immediate(Immediate::Uninit)) {
+                    // Make sure nobody accidentally uses this value.
+                    return None;
+                }
+                op
+            }
             Err(e) => {
                 trace!("get_const failed: {}", e);
                 return None;
@@ -643,6 +631,14 @@ fn const_prop(&mut self, rvalue: &Rvalue<'tcx>, place: Place<'tcx>) -> Option<()
         if rvalue.needs_subst() {
             return None;
         }
+        if !rvalue
+            .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx)
+            .is_sized(self.ecx.tcx, self.param_env)
+        {
+            // the interpreter doesn't support unsized locals (only unsized arguments),
+            // but rustc does (in a kinda broken way), so we have to skip them here
+            return None;
+        }
 
         if self.tcx.sess.mir_opt_level() >= 4 {
             self.eval_rvalue_with_identities(rvalue, place)
@@ -660,18 +656,20 @@ fn eval_rvalue_with_identities(
         self.use_ecx(|this| match rvalue {
             Rvalue::BinaryOp(op, box (left, right))
             | Rvalue::CheckedBinaryOp(op, box (left, right)) => {
-                let l = this.ecx.eval_operand(left, None);
-                let r = this.ecx.eval_operand(right, None);
+                let l = this.ecx.eval_operand(left, None).and_then(|x| this.ecx.read_immediate(&x));
+                let r =
+                    this.ecx.eval_operand(right, None).and_then(|x| this.ecx.read_immediate(&x));
 
                 let const_arg = match (l, r) {
-                    (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
-                    (Err(e), Err(_)) => return Err(e),
-                    (Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place),
+                    (Ok(x), Err(_)) | (Err(_), Ok(x)) => x, // exactly one side is known
+                    (Err(e), Err(_)) => return Err(e),      // neither side is known
+                    (Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place), // both sides are known
                 };
 
                 if !matches!(const_arg.layout.abi, abi::Abi::Scalar(..)) {
                     // We cannot handle Scalar Pair stuff.
-                    return this.ecx.eval_rvalue_into_place(rvalue, place);
+                    // No point in calling `eval_rvalue_into_place`, since only one side is known
+                    throw_machine_stop_str!("cannot optimize this")
                 }
 
                 let arg_value = const_arg.to_scalar().to_bits(const_arg.layout.size)?;
@@ -696,7 +694,7 @@ fn eval_rvalue_with_identities(
                             this.ecx.write_immediate(*const_arg, &dest)
                         }
                     }
-                    _ => this.ecx.eval_rvalue_into_place(rvalue, place),
+                    _ => throw_machine_stop_str!("cannot optimize this"),
                 }
             }
             _ => this.ecx.eval_rvalue_into_place(rvalue, place),
@@ -1073,7 +1071,11 @@ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Loca
                 if let Some(ref value) = self.eval_operand(&cond) {
                     trace!("assertion on {:?} should be {:?}", value, expected);
                     let expected = Scalar::from_bool(*expected);
-                    let value_const = self.ecx.read_scalar(&value).unwrap();
+                    let Ok(value_const) = self.ecx.read_scalar(&value) else {
+                        // FIXME should be used use_ecx rather than a local match... but we have
+                        // quite a few of these read_scalar/read_immediate that need fixing.
+                        return
+                    };
                     if expected != value_const {
                         // Poison all places this operand references so that further code
                         // doesn't use the invalid value
index 74b146833d03f27ecdfe7778ff083cca442adccd..082d6c9f07e535c38175a741687ee8b144b85ea7 100644 (file)
@@ -6,6 +6,7 @@
 use crate::const_prop::ConstPropMode;
 use crate::MirLint;
 use rustc_const_eval::const_eval::ConstEvalErr;
+use rustc_const_eval::interpret::Immediate;
 use rustc_const_eval::interpret::{
     self, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, Scalar, StackPopCleanup,
 };
@@ -229,7 +230,13 @@ fn new(
 
     fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
         let op = match self.ecx.eval_place_to_op(place, None) {
-            Ok(op) => op,
+            Ok(op) => {
+                if matches!(*op, interpret::Operand::Immediate(Immediate::Uninit)) {
+                    // Make sure nobody accidentally uses this value.
+                    return None;
+                }
+                op
+            }
             Err(e) => {
                 trace!("get_const failed: {}", e);
                 return None;
@@ -515,6 +522,14 @@ fn const_prop(
         if rvalue.needs_subst() {
             return None;
         }
+        if !rvalue
+            .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx)
+            .is_sized(self.ecx.tcx, self.param_env)
+        {
+            // the interpreter doesn't support unsized locals (only unsized arguments),
+            // but rustc does (in a kinda broken way), so we have to skip them here
+            return None;
+        }
 
         self.use_ecx(source_info, |this| this.ecx.eval_rvalue_into_place(rvalue, place))
     }
@@ -624,7 +639,11 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 if let Some(ref value) = self.eval_operand(&cond, source_info) {
                     trace!("assertion on {:?} should be {:?}", value, expected);
                     let expected = Scalar::from_bool(*expected);
-                    let value_const = self.ecx.read_scalar(&value).unwrap();
+                    let Ok(value_const) = self.ecx.read_scalar(&value) else {
+                        // FIXME should be used use_ecx rather than a local match... but we have
+                        // quite a few of these read_scalar/read_immediate that need fixing.
+                        return
+                    };
                     if expected != value_const {
                         enum DbgVal<T> {
                             Val(T),
@@ -641,9 +660,9 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                         let mut eval_to_int = |op| {
                             // This can be `None` if the lhs wasn't const propagated and we just
                             // triggered the assert on the value of the rhs.
-                            self.eval_operand(op, source_info).map_or(DbgVal::Underscore, |op| {
-                                DbgVal::Val(self.ecx.read_immediate(&op).unwrap().to_const_int())
-                            })
+                            self.eval_operand(op, source_info)
+                                .and_then(|op| self.ecx.read_immediate(&op).ok())
+                                .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int()))
                         };
                         let msg = match msg {
                             AssertKind::DivisionByZero(op) => {
index b93fe5879f4fd99a7bc388bf008cb2465b3f4c0f..fe272de20f8d085e7d0c88548f16382791209e0a 100644 (file)
@@ -6,10 +6,6 @@
 pub struct Deaggregator;
 
 impl<'tcx> MirPass<'tcx> for Deaggregator {
-    fn phase_change(&self) -> Option<MirPhase> {
-        Some(MirPhase::Deaggregated)
-    }
-
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
         for bb in basic_blocks {
index 8869f3f92af29218eaa081410920fae8a528d439..7508df92df1d5bd1537f4740d48fed7ac8c0bc50 100644 (file)
@@ -82,6 +82,5 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 impl<'tcx> MirPass<'tcx> for Derefer {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         deref_finder(tcx, body);
-        body.phase = MirPhase::Derefered;
     }
 }
index 61118ecc8ed51b0a89c8d2b64a11b57a8e9ac274..65f4956d23acd5e7722e75caf517269a838b21d7 100644 (file)
 pub struct ElaborateDrops;
 
 impl<'tcx> MirPass<'tcx> for ElaborateDrops {
-    fn phase_change(&self) -> Option<MirPhase> {
-        Some(MirPhase::DropsLowered)
-    }
-
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
 
index c260611b40712cd5c10d0bfd542f81a38e4f5981..dbff4a6bd696e01df9595a630fd99fe625efa71b 100644 (file)
@@ -1240,10 +1240,6 @@ fn create_cases<'tcx>(
 }
 
 impl<'tcx> MirPass<'tcx> for StateTransform {
-    fn phase_change(&self) -> Option<MirPhase> {
-        Some(MirPhase::GeneratorsLowered)
-    }
-
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let Some(yield_ty) = body.yield_ty() else {
             // This only applies to generators
index 56fb601d2b53528d11ddf466cf1762d0c1047470..0b674b38f32826f5a78cc2a561ea0eeed53888dd 100644 (file)
@@ -1,5 +1,6 @@
 #![allow(rustc::potential_query_instability)]
 #![feature(box_patterns)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
@@ -25,7 +26,9 @@
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::visit::Visitor as _;
-use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
+use rustc_middle::mir::{
+    traversal, AnalysisPhase, Body, ConstQualifs, MirPass, MirPhase, Promoted, RuntimePhase,
+};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
 
@@ -199,6 +202,8 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) ->
 }
 
 /// Make MIR ready for const evaluation. This is run on all MIR, not just on consts!
+/// FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query).
+/// We used to have this for pre-miri MIR based const eval.
 fn mir_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
@@ -234,7 +239,6 @@ fn mir_const<'tcx>(
             // What we need to do constant evaluation.
             &simplify::SimplifyCfg::new("initial"),
             &rustc_peek::SanityCheck, // Just a lint
-            &marker::PhaseChange(MirPhase::Const),
         ],
     );
     tcx.alloc_steal_mir(body)
@@ -340,7 +344,10 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
             pm::run_passes(
                 tcx,
                 &mut body,
-                &[&const_prop::ConstProp, &marker::PhaseChange(MirPhase::Optimized)],
+                &[
+                    &const_prop::ConstProp,
+                    &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)),
+                ],
             );
         }
     }
@@ -380,38 +387,61 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
         body.tainted_by_errors = Some(error_reported);
     }
 
-    // IMPORTANT
-    pm::run_passes(tcx, &mut body, &[&remove_false_edges::RemoveFalseEdges]);
+    run_analysis_to_runtime_passes(tcx, &mut body);
+
+    tcx.alloc_steal_mir(body)
+}
+
+fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    assert!(body.phase == MirPhase::Analysis(AnalysisPhase::Initial));
+    let did = body.source.def_id();
+
+    debug!("analysis_mir_cleanup({:?})", did);
+    run_analysis_cleanup_passes(tcx, body);
+    assert!(body.phase == MirPhase::Analysis(AnalysisPhase::PostCleanup));
 
     // Do a little drop elaboration before const-checking if `const_precise_live_drops` is enabled.
     if check_consts::post_drop_elaboration::checking_enabled(&ConstCx::new(tcx, &body)) {
         pm::run_passes(
             tcx,
-            &mut body,
+            body,
             &[
-                &simplify::SimplifyCfg::new("remove-false-edges"),
                 &remove_uninit_drops::RemoveUninitDrops,
+                &simplify::SimplifyCfg::new("remove-false-edges"),
             ],
         );
         check_consts::post_drop_elaboration::check_live_drops(tcx, &body); // FIXME: make this a MIR lint
     }
 
-    run_post_borrowck_cleanup_passes(tcx, &mut body);
-    assert!(body.phase == MirPhase::Deaggregated);
-    tcx.alloc_steal_mir(body)
+    debug!("runtime_mir_lowering({:?})", did);
+    run_runtime_lowering_passes(tcx, body);
+    assert!(body.phase == MirPhase::Runtime(RuntimePhase::Initial));
+
+    debug!("runtime_mir_cleanup({:?})", did);
+    run_runtime_cleanup_passes(tcx, body);
+    assert!(body.phase == MirPhase::Runtime(RuntimePhase::PostCleanup));
 }
 
-/// After this series of passes, no lifetime analysis based on borrowing can be done.
-fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    debug!("post_borrowck_cleanup({:?})", body.source.def_id());
+// FIXME(JakobDegen): Can we make these lists of passes consts?
 
-    let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[
-        // Remove all things only needed by analysis
+/// After this series of passes, no lifetime analysis based on borrowing can be done.
+fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    let passes: &[&dyn MirPass<'tcx>] = &[
+        &remove_false_edges::RemoveFalseEdges,
         &simplify_branches::SimplifyConstCondition::new("initial"),
         &remove_noop_landing_pads::RemoveNoopLandingPads,
         &cleanup_post_borrowck::CleanupNonCodegenStatements,
         &simplify::SimplifyCfg::new("early-opt"),
         &deref_separator::Derefer,
+        &marker::PhaseChange(MirPhase::Analysis(AnalysisPhase::PostCleanup)),
+    ];
+
+    pm::run_passes(tcx, body, passes);
+}
+
+/// Returns the sequence of passes that lowers analysis to runtime MIR.
+fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    let passes: &[&dyn MirPass<'tcx>] = &[
         // These next passes must be executed together
         &add_call_guards::CriticalCallEdges,
         &elaborate_drops::ElaborateDrops,
@@ -425,16 +455,27 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc
         // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late,
         // but before optimizations begin.
         &elaborate_box_derefs::ElaborateBoxDerefs,
+        &generator::StateTransform,
         &add_retag::AddRetag,
-        &lower_intrinsics::LowerIntrinsics,
-        &simplify::SimplifyCfg::new("elaborate-drops"),
-        // `Deaggregator` is conceptually part of MIR building, some backends rely on it happening
-        // and it can help optimizations.
+        // Deaggregator is necessary for const prop. We may want to consider implementing
+        // CTFE support for aggregates.
         &deaggregator::Deaggregator,
         &Lint(const_prop_lint::ConstProp),
+        &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Initial)),
+    ];
+    pm::run_passes_no_validate(tcx, body, passes);
+}
+
+/// Returns the sequence of passes that do the initial cleanup of runtime MIR.
+fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    let passes: &[&dyn MirPass<'tcx>] = &[
+        &elaborate_box_derefs::ElaborateBoxDerefs,
+        &lower_intrinsics::LowerIntrinsics,
+        &simplify::SimplifyCfg::new("elaborate-drops"),
+        &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::PostCleanup)),
     ];
 
-    pm::run_passes(tcx, body, post_borrowck_cleanup);
+    pm::run_passes(tcx, body, passes);
 }
 
 fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -442,9 +483,7 @@ fn o1<T>(x: T) -> WithMinOptLevel<T> {
         WithMinOptLevel(1, x)
     }
 
-    // Lowering generator control-flow and variables has to happen before we do anything else
-    // to them. We run some optimizations before that, because they may be harder to do on the state
-    // machine than on MIR with async primitives.
+    // The main optimizations that we do on MIR.
     pm::run_passes(
         tcx,
         body,
@@ -456,17 +495,6 @@ fn o1<T>(x: T) -> WithMinOptLevel<T> {
             &uninhabited_enum_branching::UninhabitedEnumBranching,
             &o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")),
             &inline::Inline,
-            &generator::StateTransform,
-        ],
-    );
-
-    assert!(body.phase == MirPhase::GeneratorsLowered);
-
-    // The main optimizations that we do on MIR.
-    pm::run_passes(
-        tcx,
-        body,
-        &[
             &remove_storage_markers::RemoveStorageMarkers,
             &remove_zsts::RemoveZsts,
             &const_goto::ConstGoto,
@@ -498,7 +526,7 @@ fn o1<T>(x: T) -> WithMinOptLevel<T> {
             &deduplicate_blocks::DeduplicateBlocks,
             // Some cleanup necessary at least for LLVM and potentially other codegen backends.
             &add_call_guards::CriticalCallEdges,
-            &marker::PhaseChange(MirPhase::Optimized),
+            &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)),
             // Dump the end result for testing and debugging purposes.
             &dump_mir::Marker("PreCodegen"),
         ],
@@ -557,7 +585,7 @@ fn promoted_mir<'tcx>(
         if let Some(error_reported) = tainted_by_errors {
             body.tainted_by_errors = Some(error_reported);
         }
-        run_post_borrowck_cleanup_passes(tcx, body);
+        run_analysis_to_runtime_passes(tcx, body);
     }
 
     debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
index e27d4ab1688e07fe98260d0e6549f428a33e2e19..67ea5cfdb3c006a038bd9fffc4ae1d2842ef1f87 100644 (file)
@@ -1,6 +1,6 @@
 use std::borrow::Cow;
 
-use rustc_middle::mir::{self, Body, MirPhase};
+use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 
@@ -72,48 +72,62 @@ fn phase_change(&self) -> Option<MirPhase> {
     }
 }
 
+/// Run the sequence of passes without validating the MIR after each pass. The MIR is still
+/// validated at the end.
+pub fn run_passes_no_validate<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &mut Body<'tcx>,
+    passes: &[&dyn MirPass<'tcx>],
+) {
+    run_passes_inner(tcx, body, passes, false);
+}
+
 pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>]) {
+    run_passes_inner(tcx, body, passes, true);
+}
+
+fn run_passes_inner<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &mut Body<'tcx>,
+    passes: &[&dyn MirPass<'tcx>],
+    validate_each: bool,
+) {
     let start_phase = body.phase;
     let mut cnt = 0;
 
-    let validate = tcx.sess.opts.unstable_opts.validate_mir;
+    let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir;
     let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
     trace!(?overridden_passes);
 
-    if validate {
-        validate_body(tcx, body, format!("start of phase transition from {:?}", start_phase));
-    }
-
     for pass in passes {
         let name = pass.name();
 
-        if let Some((_, polarity)) = overridden_passes.iter().rev().find(|(s, _)| s == &*name) {
-            trace!(
-                pass = %name,
-                "{} as requested by flag",
-                if *polarity { "Running" } else { "Not running" },
-            );
-            if !polarity {
-                continue;
-            }
-        } else {
-            if !pass.is_enabled(&tcx.sess) {
-                continue;
-            }
-        }
-        let dump_enabled = pass.is_mir_dump_enabled();
+        // Gather information about what we should be doing for this pass
+        let overriden =
+            overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| {
+                trace!(
+                    pass = %name,
+                    "{} as requested by flag",
+                    if *polarity { "Running" } else { "Not running" },
+                );
+                *polarity
+            });
+        let is_enabled = overriden.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)
+            || new_phase == Some(MirPhase::Runtime(RuntimePhase::Optimized));
 
         if dump_enabled {
             dump_mir(tcx, body, start_phase, &name, cnt, false);
         }
-
-        pass.run_pass(tcx, body);
-
+        if is_enabled {
+            pass.run_pass(tcx, body);
+        }
         if dump_enabled {
             dump_mir(tcx, body, start_phase, &name, cnt, true);
             cnt += 1;
         }
-
         if let Some(new_phase) = pass.phase_change() {
             if body.phase >= new_phase {
                 panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase);
@@ -121,15 +135,10 @@ pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn
 
             body.phase = new_phase;
         }
-
         if validate {
-            validate_body(tcx, body, format!("after pass {}", pass.name()));
+            validate_body(tcx, body, format!("after pass {}", name));
         }
     }
-
-    if validate || body.phase == MirPhase::Optimized {
-        validate_body(tcx, body, format!("end of phase transition to {:?}", body.phase));
-    }
 }
 
 pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
@@ -144,7 +153,7 @@ pub fn dump_mir<'tcx>(
     cnt: usize,
     is_after: bool,
 ) {
-    let phase_index = phase as u32;
+    let phase_index = phase.phase_index();
 
     mir::dump_mir(
         tcx,
index 3620e94bec7d750cc79fc02dddd63bd3ba94e612..2b21fbe0a617ff4496fa208fbf44e1988e41ed81 100644 (file)
@@ -17,8 +17,8 @@
 
 use crate::util::expand_aggregate;
 use crate::{
-    abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, marker, pass_manager as pm,
-    remove_noop_landing_pads, simplify,
+    abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, marker,
+    pass_manager as pm, remove_noop_landing_pads, simplify,
 };
 use rustc_middle::mir::patch::MirPatch;
 use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
@@ -92,11 +92,12 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
         &mut result,
         &[
             &add_moves_for_packed_drops::AddMovesForPackedDrops,
+            &deref_separator::Derefer,
             &remove_noop_landing_pads::RemoveNoopLandingPads,
             &simplify::SimplifyCfg::new("make_shim"),
             &add_call_guards::CriticalCallEdges,
             &abort_unwinding_calls::AbortUnwindingCalls,
-            &marker::PhaseChange(MirPhase::Const),
+            &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)),
         ],
     );
 
index 41ba4d4b64a34143376e9421da4719b145725d6c..59ca04ec868d159d32a2d62d65cfd8c67a196ace 100644 (file)
@@ -7,11 +7,13 @@ edition = "2021"
 doctest = false
 
 [dependencies]
-smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] }
 tracing = "0.1"
 rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_errors = { path = "../rustc_errors" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
+rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
index 82ef16a7f72fc526f5c9bbf3319e8cdd3fdb7ccc..4e37da0dedb154e5312ffd92e5fb23c1f749893f 100644 (file)
 use std::ops::Range;
 use std::path::PathBuf;
 
+use crate::errors::{LargeAssignmentsLint, RecursionLimit, RequiresLangItem, TypeLengthLimit};
+
 #[derive(PartialEq)]
 pub enum MonoItemCollectionMode {
     Eager,
@@ -417,7 +419,6 @@ fn collect_items_rec<'tcx>(
         // We've been here already, no need to search again.
         return;
     }
-    debug!("BEGIN collect_items_rec({})", starting_point.node);
 
     let mut neighbors = MonoItems { compute_inlining: true, tcx, items: Vec::new() };
     let recursion_depth_reset;
@@ -461,7 +462,7 @@ fn collect_items_rec<'tcx>(
             recursion_depth_reset = None;
 
             if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
-                for &id in alloc.inner().relocations().values() {
+                for &id in alloc.inner().provenance().values() {
                     collect_miri(tcx, id, &mut neighbors);
                 }
             }
@@ -543,8 +544,6 @@ fn collect_items_rec<'tcx>(
     if let Some((def_id, depth)) = recursion_depth_reset {
         recursion_depths.insert(def_id, depth);
     }
-
-    debug!("END collect_items_rec({})", starting_point.node);
 }
 
 /// Format instance name that is already known to be too long for rustc.
@@ -604,17 +603,24 @@ fn check_recursion_limit<'tcx>(
     // more than the recursion limit is assumed to be causing an
     // infinite expansion.
     if !recursion_limit.value_within_limit(adjusted_recursion_depth) {
+        let def_span = tcx.def_span(def_id);
+        let def_path_str = tcx.def_path_str(def_id);
         let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
-        let error = format!("reached the recursion limit while instantiating `{}`", shrunk);
-        let mut err = tcx.sess.struct_span_fatal(span, &error);
-        err.span_note(
-            tcx.def_span(def_id),
-            &format!("`{}` defined here", tcx.def_path_str(def_id)),
-        );
-        if let Some(path) = written_to_path {
-            err.note(&format!("the full type name has been written to '{}'", path.display()));
-        }
-        err.emit()
+        let mut path = PathBuf::new();
+        let was_written = if written_to_path.is_some() {
+            path = written_to_path.unwrap();
+            Some(())
+        } else {
+            None
+        };
+        tcx.sess.emit_fatal(RecursionLimit {
+            span,
+            shrunk,
+            def_span,
+            def_path_str,
+            was_written,
+            path,
+        });
     }
 
     recursion_depths.insert(def_id, recursion_depth + 1);
@@ -642,16 +648,15 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
     // Bail out in these cases to avoid that bad user experience.
     if !tcx.type_length_limit().value_within_limit(type_length) {
         let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance, 32, 32);
-        let msg = format!("reached the type-length limit while instantiating `{}`", shrunk);
-        let mut diag = tcx.sess.struct_span_fatal(tcx.def_span(instance.def_id()), &msg);
-        if let Some(path) = written_to_path {
-            diag.note(&format!("the full type name has been written to '{}'", path.display()));
-        }
-        diag.help(&format!(
-            "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate",
-            type_length
-        ));
-        diag.emit()
+        let span = tcx.def_span(instance.def_id());
+        let mut path = PathBuf::new();
+        let was_written = if written_to_path.is_some() {
+            path = written_to_path.unwrap();
+            Some(())
+        } else {
+            None
+        };
+        tcx.sess.emit_fatal(TypeLengthLimit { span, shrunk, was_written, path, type_length });
     }
 }
 
@@ -914,17 +919,16 @@ fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
                     // but correct span? This would make the lint at least accept crate-level lint attributes.
                     return;
                 };
-                self.tcx.struct_span_lint_hir(
+                self.tcx.emit_spanned_lint(
                     LARGE_ASSIGNMENTS,
                     lint_root,
                     source_info.span,
-                    |lint| {
-                        let mut err = lint.build(&format!("moving {} bytes", layout.size.bytes()));
-                        err.span_label(source_info.span, "value moved from here");
-                        err.note(&format!(r#"The current maximum size is {}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`"#, limit.bytes()));
-                        err.emit();
+                    LargeAssignmentsLint {
+                        span: source_info.span,
+                        size: layout.size.bytes(),
+                        limit: limit.bytes(),
                     },
-                );
+                )
             }
         }
     }
@@ -1141,23 +1145,18 @@ fn find_vtable_types_for_unsizing<'tcx>(
     }
 }
 
-#[instrument(skip(tcx), level = "debug")]
+#[instrument(skip(tcx), level = "debug", ret)]
 fn create_fn_mono_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
     source: Span,
 ) -> Spanned<MonoItem<'tcx>> {
-    debug!("create_fn_mono_item(instance={})", instance);
-
     let def_id = instance.def_id();
     if tcx.sess.opts.unstable_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id) {
         crate::util::dump_closure_profile(tcx, instance);
     }
 
-    let respanned = respan(source, MonoItem::Fn(instance.polymorphize(tcx)));
-    debug!(?respanned);
-
-    respanned
+    respan(source, MonoItem::Fn(instance.polymorphize(tcx)))
 }
 
 /// Creates a `MonoItem` for each method that is referenced by the vtable for
@@ -1302,7 +1301,7 @@ fn is_root(&self, def_id: LocalDefId) -> bool {
     #[instrument(skip(self), level = "debug")]
     fn push_if_root(&mut self, def_id: LocalDefId) {
         if self.is_root(def_id) {
-            debug!("RootCollector::push_if_root: found root def_id={:?}", def_id);
+            debug!("found root");
 
             let instance = Instance::mono(self.tcx, def_id.to_def_id());
             self.output.push(create_fn_mono_item(self.tcx, instance, DUMMY_SP));
@@ -1315,13 +1314,17 @@ fn push_if_root(&mut self, def_id: LocalDefId) {
     /// the return type of `main`. This is not needed when
     /// the user writes their own `start` manually.
     fn push_extra_entry_roots(&mut self) {
-        let Some((main_def_id, EntryFnType::Main)) = self.entry_fn else {
+        let Some((main_def_id, EntryFnType::Main { .. })) = self.entry_fn else {
             return;
         };
 
         let start_def_id = match self.tcx.lang_items().require(LangItem::Start) {
             Ok(s) => s,
-            Err(err) => self.tcx.sess.fatal(&err),
+            Err(lang_item_err) => {
+                self.tcx
+                    .sess
+                    .emit_fatal(RequiresLangItem { lang_item: lang_item_err.0.name().to_string() });
+            }
         };
         let main_ret_ty = self.tcx.fn_sig(main_def_id).output();
 
@@ -1424,7 +1427,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIte
         }
         GlobalAlloc::Memory(alloc) => {
             trace!("collecting {:?} with {:#?}", alloc_id, alloc);
-            for &inner in alloc.inner().relocations().values() {
+            for &inner in alloc.inner().provenance().values() {
                 rustc_data_structures::stack::ensure_sufficient_stack(|| {
                     collect_miri(tcx, inner, output);
                 });
@@ -1463,7 +1466,7 @@ fn collect_const_value<'tcx>(
     match value {
         ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => collect_miri(tcx, ptr.provenance, output),
         ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => {
-            for &id in alloc.inner().relocations().values() {
+            for &id in alloc.inner().provenance().values() {
                 collect_miri(tcx, id, output);
             }
         }
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
new file mode 100644 (file)
index 0000000..77b6cfa
--- /dev/null
@@ -0,0 +1,84 @@
+use std::path::PathBuf;
+
+use rustc_errors::ErrorGuaranteed;
+use rustc_macros::{LintDiagnostic, SessionDiagnostic};
+use rustc_session::SessionDiagnostic;
+use rustc_span::Span;
+
+#[derive(SessionDiagnostic)]
+#[diag(monomorphize::recursion_limit)]
+pub struct RecursionLimit {
+    #[primary_span]
+    pub span: Span,
+    pub shrunk: String,
+    #[note]
+    pub def_span: Span,
+    pub def_path_str: String,
+    #[note(monomorphize::written_to_path)]
+    pub was_written: Option<()>,
+    pub path: PathBuf,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(monomorphize::type_length_limit)]
+#[help(monomorphize::consider_type_length_limit)]
+pub struct TypeLengthLimit {
+    #[primary_span]
+    pub span: Span,
+    pub shrunk: String,
+    #[note(monomorphize::written_to_path)]
+    pub was_written: Option<()>,
+    pub path: PathBuf,
+    pub type_length: usize,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(monomorphize::requires_lang_item)]
+pub struct RequiresLangItem {
+    pub lang_item: String,
+}
+
+pub struct UnusedGenericParams {
+    pub span: Span,
+    pub param_spans: Vec<Span>,
+    pub param_names: Vec<String>,
+}
+
+impl SessionDiagnostic<'_> for UnusedGenericParams {
+    fn into_diagnostic(
+        self,
+        sess: &'_ rustc_session::parse::ParseSess,
+    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = sess.struct_err(rustc_errors::fluent::monomorphize::unused_generic_params);
+        diag.set_span(self.span);
+        for (span, name) in self.param_spans.into_iter().zip(self.param_names) {
+            // FIXME: I can figure out how to do a label with a fluent string with a fixed message,
+            // or a label with a dynamic value in a hard-coded string, but I haven't figured out
+            // how to combine the two. 😢
+            diag.span_label(span, format!("generic parameter `{}` is unused", name));
+        }
+        diag
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(monomorphize::large_assignments)]
+#[note]
+pub struct LargeAssignmentsLint {
+    #[label]
+    pub span: Span,
+    pub size: u64,
+    pub limit: u64,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(monomorphize::unknown_partition_strategy)]
+pub struct UnknownPartitionStrategy;
+
+#[derive(SessionDiagnostic)]
+#[diag(monomorphize::symbol_already_defined)]
+pub struct SymbolAlreadyDefined {
+    #[primary_span]
+    pub span: Option<Span>,
+    pub symbol: String,
+}
index ef4560b5ec48edc153a3ad9fc553491b678bdf6e..d64de44705bb2eaf7ea037a87af7516da3fac17c 100644 (file)
@@ -3,6 +3,8 @@
 #![feature(let_else)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 
 #[macro_use]
 extern crate tracing;
@@ -16,6 +18,7 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 mod collector;
+mod errors;
 mod partitioning;
 mod polymorphize;
 mod util;
index 43319dc5862e6e79372fdee53c1c995fe36861db..932edc6675f5900cb6dd04d9678d7847345f0f9b 100644 (file)
 
 use crate::collector::InliningMap;
 use crate::collector::{self, MonoItemCollectionMode};
+use crate::errors::{SymbolAlreadyDefined, UnknownPartitionStrategy};
 
 pub struct PartitioningCx<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -149,7 +150,9 @@ fn get_partitioner<'tcx>(tcx: TyCtxt<'tcx>) -> Box<dyn Partitioner<'tcx>> {
 
     match strategy {
         "default" => Box::new(default::DefaultPartitioning),
-        _ => tcx.sess.fatal("unknown partitioning strategy"),
+        _ => {
+            tcx.sess.emit_fatal(UnknownPartitionStrategy);
+        }
     }
 }
 
@@ -331,13 +334,7 @@ fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I)
                 (span1, span2) => span1.or(span2),
             };
 
-            let error_message = format!("symbol `{}` is already defined", sym1);
-
-            if let Some(span) = span {
-                tcx.sess.span_fatal(span, &error_message)
-            } else {
-                tcx.sess.fatal(&error_message)
-            }
+            tcx.sess.emit_fatal(SymbolAlreadyDefined { span, symbol: sym1.to_string() });
         }
     }
 }
index 394843e510d214dc7885908c68d5bce17a9d76a1..af4b35db3bace8bbaefb9b7808e01bd05aaf75ed 100644 (file)
@@ -22,6 +22,8 @@
 use std::convert::TryInto;
 use std::ops::ControlFlow;
 
+use crate::errors::UnusedGenericParams;
+
 /// Provide implementations of queries relating to polymorphization analysis.
 pub fn provide(providers: &mut Providers) {
     providers.unused_generic_params = unused_generic_params;
@@ -31,7 +33,6 @@ pub fn provide(providers: &mut Providers) {
 ///
 /// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all
 /// parameters are used).
-#[instrument(level = "debug", skip(tcx))]
 fn unused_generic_params<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: ty::InstanceDef<'tcx>,
@@ -206,22 +207,23 @@ fn emit_unused_generic_params_error<'tcx>(
         _ => tcx.def_span(def_id),
     };
 
-    let mut err = tcx.sess.struct_span_err(fn_span, "item has unused generic parameters");
-
+    let mut param_spans = Vec::new();
+    let mut param_names = Vec::new();
     let mut next_generics = Some(generics);
     while let Some(generics) = next_generics {
         for param in &generics.params {
             if unused_parameters.contains(param.index).unwrap_or(false) {
                 debug!(?param);
                 let def_span = tcx.def_span(param.def_id);
-                err.span_label(def_span, &format!("generic parameter `{}` is unused", param.name));
+                param_spans.push(def_span);
+                param_names.push(param.name.to_string());
             }
         }
 
         next_generics = generics.parent.map(|did| tcx.generics_of(did));
     }
 
-    err.emit();
+    tcx.sess.emit_err(UnusedGenericParams { span: fn_span, param_spans, param_names });
 }
 
 /// Visitor used to aggregate generic parameter uses.
index 847e64dc2a2f1c3469187c30c1dba8569b50e933..6a4d2df1ead158b8612f7b4ad0c14cf8f26e5c4b 100644 (file)
@@ -13,7 +13,7 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In
         .append(true)
         .open(&format!("closure_profile_{}.csv", std::process::id()))
     else {
-        eprintln!("Cound't open file for writing closure profile");
+        eprintln!("Couldn't open file for writing closure profile");
         return;
     };
 
index 848e142e59ce9b4dcc47b41a37fb4d46b073d330..63819a2f98df57b17a49a426500e48111befcfa4 100644 (file)
@@ -14,8 +14,6 @@
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{edition::Edition, BytePos, Pos, Span};
 
-use tracing::debug;
-
 mod tokentrees;
 mod unescape_error_reporting;
 mod unicode_chars;
index 273827864f1a405295e2f7f0499d605c82f290f0..77c4fadab45eacc9f61d5fd4cb4d361cedc62666 100644 (file)
@@ -20,13 +20,9 @@ pub(crate) fn emit_unescape_error(
     range: Range<usize>,
     error: EscapeError,
 ) {
-    tracing::debug!(
+    debug!(
         "emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}",
-        lit,
-        span_with_quotes,
-        mode,
-        range,
-        error
+        lit, span_with_quotes, mode, range, error
     );
     let last_char = || {
         let c = lit[range.clone()].chars().rev().next().unwrap();
index 3691d82a835a9d57158e101d24de1e05419e0b5d..3c88e1ef377e2160c42b8c4fc61149529a7bf920 100644 (file)
@@ -3,6 +3,7 @@
 #![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
 #![feature(rustc_attrs)]
index 72ab96b5ca67032aa9e4c83509e42a5b4ced6613..77a6bde1c164e43ac43c73d6a36e50929da3a671 100644 (file)
@@ -7,8 +7,6 @@
 use rustc_span::{sym, BytePos, Span};
 use std::convert::TryInto;
 
-use tracing::debug;
-
 // Public for rustfmt usage
 #[derive(Debug)]
 pub enum InnerAttrPolicy<'a> {
index b564f4ad92cff89cf28a5dcf03cadd4d33ce4c2d..f353ee6df9bc173f77a5d1e58117f9664fa145dd 100644 (file)
@@ -355,7 +355,7 @@ pub fn collect_tokens_trailing_token<R: HasAttrs + HasTokens>(
             && matches!(self.capture_state.capturing, Capturing::Yes)
             && has_cfg_or_cfg_attr(final_attrs)
         {
-            let attr_data = AttributesData { attrs: final_attrs.to_vec().into(), tokens };
+            let attr_data = AttributesData { attrs: final_attrs.iter().cloned().collect(), tokens };
 
             // Replace the entire AST node that we just parsed, including attributes,
             // with a `FlatToken::AttrTarget`. If this AST node is inside an item
index f0ea1dfe297f2fb5c99da39460a21b693bc9c980..dd806e2130e9b062f62a58603524534328ab3298 100644 (file)
@@ -29,7 +29,6 @@
 use std::mem::take;
 
 use crate::parser;
-use tracing::{debug, trace};
 
 const TURBOFISH_SUGGESTION_STR: &str =
     "use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments";
index 18aa109d7a60a640d4bb048bc9c86b1e9e2bc178..d4828a201207b25182e927e01a480a7435e9418b 100644 (file)
@@ -944,13 +944,18 @@ pub(super) fn parse_dot_or_call_expr_with(
         // Stitch the list of outer attributes onto the return value.
         // A little bit ugly, but the best way given the current code
         // structure
-        self.parse_dot_or_call_expr_with_(e0, lo).map(|expr| {
-            expr.map(|mut expr| {
-                attrs.extend(expr.attrs);
-                expr.attrs = attrs;
-                expr
+        let res = self.parse_dot_or_call_expr_with_(e0, lo);
+        if attrs.is_empty() {
+            res
+        } else {
+            res.map(|expr| {
+                expr.map(|mut expr| {
+                    attrs.extend(expr.attrs);
+                    expr.attrs = attrs;
+                    expr
+                })
             })
-        })
+        }
     }
 
     fn parse_dot_or_call_expr_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
@@ -1578,7 +1583,7 @@ fn visit_expr_post(&mut self, ex: &'ast Expr) {
                     Applicability::MachineApplicable,
                 );
 
-                // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to supress future errors about `break 'label`.
+                // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.
                 let stmt = self.mk_stmt(span, StmtKind::Expr(expr));
                 let blk = self.mk_block(vec![stmt], BlockCheckMode::Default, span);
                 self.mk_expr(span, ExprKind::Block(blk, label))
@@ -2251,7 +2256,15 @@ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<
 
     /// Parses the condition of a `if` or `while` expression.
     fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
-        self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)
+        let cond =
+            self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)?;
+
+        if let ExprKind::Let(..) = cond.kind {
+            // Remove the last feature gating of a `let` expression since it's stable.
+            self.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
+        }
+
+        Ok(cond)
     }
 
     /// Parses a `let $pat = $expr` pseudo-expression.
@@ -2280,6 +2293,7 @@ fn parse_let_expr(&mut self) -> PResult<'a, P<Expr>> {
             this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
         })?;
         let span = lo.to(expr.span);
+        self.sess.gated_spans.gate(sym::let_chains, span);
         Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span)))
     }
 
@@ -2569,15 +2583,17 @@ fn parse_arm_body_missing_braces(
     }
 
     pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
-        // Used to check the `let_chains` and `if_let_guard` features mostly by scaning
+        // Used to check the `let_chains` and `if_let_guard` features mostly by scanning
         // `&&` tokens.
-        fn check_let_expr(expr: &Expr) -> bool {
+        fn check_let_expr(expr: &Expr) -> (bool, bool) {
             match expr.kind {
                 ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, ref lhs, ref rhs) => {
-                    check_let_expr(lhs) || check_let_expr(rhs)
+                    let lhs_rslt = check_let_expr(lhs);
+                    let rhs_rslt = check_let_expr(rhs);
+                    (lhs_rslt.0 || rhs_rslt.0, false)
                 }
-                ExprKind::Let(..) => true,
-                _ => false,
+                ExprKind::Let(..) => (true, true),
+                _ => (false, true),
             }
         }
         let attrs = self.parse_outer_attributes()?;
@@ -2592,7 +2608,12 @@ fn check_let_expr(expr: &Expr) -> bool {
             let guard = if this.eat_keyword(kw::If) {
                 let if_span = this.prev_token.span;
                 let cond = this.parse_expr_res(Restrictions::ALLOW_LET, None)?;
-                if check_let_expr(&cond) {
+                let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond);
+                if has_let_expr {
+                    if does_not_have_bin_op {
+                        // Remove the last feature gating of a `let` expression since it's stable.
+                        this.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
+                    }
                     let span = if_span.to(cond.span);
                     this.sess.gated_spans.gate(sym::if_let_guard, span);
                 }
index b743162a7e4d0809a234454ccea601335bb9cc2a..5b75d1d5f221daa69dbaf0d34fc1a0462ec756ba 100644 (file)
@@ -22,7 +22,6 @@
 
 use std::convert::TryFrom;
 use std::mem;
-use tracing::debug;
 
 impl<'a> Parser<'a> {
     /// Parses a source module as a crate. This is the main entry point for the parser.
index f6516d3bd4543604155cf9bde1010d54c01b65cb..5c8f374255c7fc91635b88391161d743150ecced 100644 (file)
@@ -37,7 +37,6 @@
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::{Span, DUMMY_SP};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use tracing::debug;
 
 use std::ops::Range;
 use std::{cmp, mem, slice};
@@ -281,7 +280,7 @@ fn inlined_next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) {
                         if delim != Delimiter::Invisible {
                             return (Token::new(token::OpenDelim(delim), sp.open), Spacing::Alone);
                         }
-                        // No open delimeter to return; continue on to the next iteration.
+                        // No open delimiter to return; continue on to the next iteration.
                     }
                 };
             } else if let Some(frame) = self.stack.pop() {
index fc7fb866f110f5dd91e85fa1f0a0d79ea8a47cef..fdc1af27f82e4206e3e7d95eec13f6ffb59a4a92 100644 (file)
@@ -13,7 +13,6 @@
 use rustc_span::symbol::{kw, sym, Ident};
 
 use std::mem;
-use tracing::debug;
 
 /// Specifies how to parse a path.
 #[derive(Copy, Clone, PartialEq)]
index b63a173cc29e6cd3a5dc8806dacc825e6949bb3e..a9e502016aa8d4ac2392a8ce4fada05db3d14563 100644 (file)
@@ -167,6 +167,8 @@ pub enum Count<'a> {
     CountIsName(&'a str, InnerSpan),
     /// The count is specified by the argument at the given index.
     CountIsParam(usize),
+    /// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index.
+    CountIsStar(usize),
     /// The count is implied and cannot be explicitly specified.
     CountImplied,
 }
@@ -618,7 +620,7 @@ fn format(&mut self) -> FormatSpec<'a> {
                 // We can do this immediately as `position` is resolved later.
                 let i = self.curarg;
                 self.curarg += 1;
-                spec.precision = CountIsParam(i);
+                spec.precision = CountIsStar(i);
             } else {
                 spec.precision = self.count(start + 1);
             }
index 44ef0cd0eb5d2f0e0df69d2d117a9a875bf7e751..2f8c229c68ffe1e7ab48eb5dd818b462782ca103 100644 (file)
@@ -244,7 +244,7 @@ fn format_counts() {
                 fill: None,
                 align: AlignUnknown,
                 flags: 0,
-                precision: CountIsParam(0),
+                precision: CountIsStar(0),
                 precision_span: Some(InnerSpan { start: 3, end: 5 }),
                 width: CountImplied,
                 width_span: None,
index 5789531d2ff5ae3b1a47a975bd7521e4803917ac..100adedfb505216c1034750c605fc0b28245c601 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID};
 use rustc_hir::{MethodKind, Target};
 use rustc_middle::hir::nested_filter;
+use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::{
@@ -172,6 +173,9 @@ fn check_attributes(
                 sym::no_implicit_prelude => {
                     self.check_generic_attr(hir_id, attr, target, &[Target::Mod])
                 }
+                sym::rustc_object_lifetime_default => {
+                    self.check_object_lifetime_default(hir_id, span)
+                }
                 _ => {}
             }
 
@@ -410,6 +414,30 @@ fn check_cmse_nonsecure_entry(&self, attr: &Attribute, span: Span, target: Targe
         }
     }
 
+    /// Debugging aid for `object_lifetime_default` query.
+    fn check_object_lifetime_default(&self, hir_id: HirId, span: Span) {
+        let tcx = self.tcx;
+        if let Some(generics) = tcx.hir().get_generics(tcx.hir().local_def_id(hir_id)) {
+            let object_lifetime_default_reprs: String = generics
+                .params
+                .iter()
+                .filter_map(|p| {
+                    let param_id = tcx.hir().local_def_id(p.hir_id);
+                    let default = tcx.object_lifetime_default(param_id)?;
+                    Some(match default {
+                        ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(),
+                        ObjectLifetimeDefault::Static => "'static".to_owned(),
+                        ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
+                        ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
+                    })
+                })
+                .collect::<Vec<String>>()
+                .join(",");
+
+            tcx.sess.span_err(span, &object_lifetime_default_reprs);
+        }
+    }
+
     /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
     fn check_track_caller(
         &self,
@@ -2117,6 +2145,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
         sym::automatically_derived,
         sym::start,
         sym::rustc_main,
+        sym::unix_sigpipe,
         sym::derive,
         sym::test,
         sym::test_case,
index 7381019a620160ff782f0eb05e9e5d2593b35ba1..cd10170d3ba58756994049556beddc12bd6d18f3 100644 (file)
@@ -1,11 +1,11 @@
-use rustc_ast::{entry::EntryPointType, Attribute};
+use rustc_ast::entry::EntryPointType;
 use rustc_errors::struct_span_err;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{DefIdTree, TyCtxt};
-use rustc_session::config::{CrateType, EntryFnType};
+use rustc_session::config::{sigpipe, CrateType, EntryFnType};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol, DUMMY_SP};
@@ -71,14 +71,12 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry
     }
 }
 
-fn err_if_attr_found(ctxt: &EntryContext<'_>, attrs: &[Attribute], sym: Symbol) {
+fn err_if_attr_found(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol, details: &str) {
+    let attrs = ctxt.tcx.hir().attrs(id.hir_id());
     if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym) {
         ctxt.tcx
             .sess
-            .struct_span_err(
-                attr.span,
-                &format!("`{}` attribute can only be used on functions", sym),
-            )
+            .struct_span_err(attr.span, &format!("`{}` attribute {}", sym, details))
             .emit();
     }
 }
@@ -87,14 +85,16 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
     let at_root = ctxt.tcx.opt_local_parent(id.def_id) == Some(CRATE_DEF_ID);
 
     match entry_point_type(ctxt, id, at_root) {
-        EntryPointType::None => (),
+        EntryPointType::None => {
+            err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`");
+        }
         _ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
-            let attrs = ctxt.tcx.hir().attrs(id.hir_id());
-            err_if_attr_found(ctxt, attrs, sym::start);
-            err_if_attr_found(ctxt, attrs, sym::rustc_main);
+            err_if_attr_found(ctxt, id, sym::start, "can only be used on functions");
+            err_if_attr_found(ctxt, id, sym::rustc_main, "can only be used on functions");
         }
         EntryPointType::MainNamed => (),
         EntryPointType::OtherMain => {
+            err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on root `fn main()`");
             ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
         }
         EntryPointType::RustcMainAttr => {
@@ -116,6 +116,7 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
             }
         }
         EntryPointType::Start => {
+            err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`");
             if ctxt.start_fn.is_none() {
                 ctxt.start_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
             } else {
@@ -136,8 +137,9 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
 fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
     if let Some((def_id, _)) = visitor.start_fn {
         Some((def_id.to_def_id(), EntryFnType::Start))
-    } else if let Some((def_id, _)) = visitor.attr_main_fn {
-        Some((def_id.to_def_id(), EntryFnType::Main))
+    } else if let Some((local_def_id, _)) = visitor.attr_main_fn {
+        let def_id = local_def_id.to_def_id();
+        Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) }))
     } else {
         if let Some(main_def) = tcx.resolutions(()).main_def && let Some(def_id) = main_def.opt_fn_def_id() {
             // non-local main imports are handled below
@@ -161,13 +163,39 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
                 )
                 .emit();
             }
-            return Some((def_id, EntryFnType::Main));
+            return Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) }));
         }
         no_main_err(tcx, visitor);
         None
     }
 }
 
+fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
+    if let Some(attr) = tcx.get_attr(def_id, sym::unix_sigpipe) {
+        match (attr.value_str(), attr.meta_item_list()) {
+            (Some(sym::inherit), None) => sigpipe::INHERIT,
+            (Some(sym::sig_ign), None) => sigpipe::SIG_IGN,
+            (Some(sym::sig_dfl), None) => sigpipe::SIG_DFL,
+            (_, Some(_)) => {
+                // Keep going so that `fn emit_malformed_attribute()` can print
+                // an excellent error message
+                sigpipe::DEFAULT
+            }
+            _ => {
+                tcx.sess
+                    .struct_span_err(
+                        attr.span,
+                        "valid values for `#[unix_sigpipe = \"...\"]` are `inherit`, `sig_ign`, or `sig_dfl`",
+                    )
+                    .emit();
+                sigpipe::DEFAULT
+            }
+        }
+    } else {
+        sigpipe::DEFAULT
+    }
+}
+
 fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
     let sp = tcx.def_span(CRATE_DEF_ID);
     if *tcx.sess.parse_sess.reached_eof.borrow() {
index 399d00b403a6ba784eb5a88791f8ccbf33c25aa1..fb1d724d9d83b5a30a39cff45d5de51b6758af66 100644 (file)
@@ -49,7 +49,7 @@ fn new() -> Node {
 ///
 /// For example, `ast::Visitor` has `visit_ident`, but `Ident`s are always
 /// stored inline within other AST nodes, so we don't implement `visit_ident`
-/// here. In constrast, we do implement `visit_expr` because `ast::Expr` is
+/// here. In contrast, we do implement `visit_expr` because `ast::Expr` is
 /// always stored as `P<ast::Expr>`, and every such expression should be
 /// measured separately.
 ///
index 4af041dac0d8390789abae5de00af8024e6a3113..7b2f83958af85cd31c4bf0f3ebd87a7c5e8aa87e 100644 (file)
@@ -7,6 +7,7 @@
 #![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(iter_intersperse)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
index 70b6bfd1e582d1422eb92148c145fe4725bb4016..5aac6943eef1eb2af321c9c34f995b095bb6fc16 100644 (file)
@@ -5,6 +5,7 @@
 //! collect them instead.
 
 use rustc_ast::{Attribute, MetaItemKind};
+use rustc_attr::VERSION_PLACEHOLDER;
 use rustc_errors::struct_span_err;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
@@ -54,7 +55,6 @@ fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
                         }
                     }
                 }
-                const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
 
                 if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
                     let version = option_env!("CFG_VERSION").unwrap_or("<current>");
index 1f22ebc730aedb5ad826bf65a2caa85dede7ff98..2a6889af7c2c92aab88860e449ae341e8e07917f 100644 (file)
@@ -229,6 +229,19 @@ enum VarKind {
     Upvar(HirId, Symbol),
 }
 
+struct CollectLitsVisitor<'tcx> {
+    lit_exprs: Vec<&'tcx hir::Expr<'tcx>>,
+}
+
+impl<'tcx> Visitor<'tcx> for CollectLitsVisitor<'tcx> {
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        if let hir::ExprKind::Lit(_) = expr.kind {
+            self.lit_exprs.push(expr);
+        }
+        intravisit::walk_expr(self, expr);
+    }
+}
+
 struct IrMaps<'tcx> {
     tcx: TyCtxt<'tcx>,
     live_node_map: HirIdMap<LiveNode>,
@@ -1333,7 +1346,7 @@ fn warn_about_unreachable(
 
 impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
     fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
-        self.check_unused_vars_in_pat(&local.pat, None, |spans, hir_id, ln, var| {
+        self.check_unused_vars_in_pat(&local.pat, None, None, |spans, hir_id, ln, var| {
             if local.init.is_some() {
                 self.warn_about_dead_assign(spans, hir_id, ln, var);
             }
@@ -1348,7 +1361,7 @@ fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
     }
 
     fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
-        self.check_unused_vars_in_pat(&arm.pat, None, |_, _, _, _| {});
+        self.check_unused_vars_in_pat(&arm.pat, None, None, |_, _, _, _| {});
         intravisit::walk_arm(self, arm);
     }
 }
@@ -1387,7 +1400,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
         }
 
         hir::ExprKind::Let(let_expr) => {
-            this.check_unused_vars_in_pat(let_expr.pat, None, |_, _, _, _| {});
+            this.check_unused_vars_in_pat(let_expr.pat, None, None, |_, _, _, _| {});
         }
 
         // no correctness conditions related to liveness
@@ -1508,13 +1521,18 @@ fn warn_about_unused_upvars(&self, entry_ln: LiveNode) {
 
     fn warn_about_unused_args(&self, body: &hir::Body<'_>, entry_ln: LiveNode) {
         for p in body.params {
-            self.check_unused_vars_in_pat(&p.pat, Some(entry_ln), |spans, hir_id, ln, var| {
-                if !self.live_on_entry(ln, var) {
-                    self.report_unused_assign(hir_id, spans, var, |name| {
-                        format!("value passed to `{}` is never read", name)
-                    });
-                }
-            });
+            self.check_unused_vars_in_pat(
+                &p.pat,
+                Some(entry_ln),
+                Some(body),
+                |spans, hir_id, ln, var| {
+                    if !self.live_on_entry(ln, var) {
+                        self.report_unused_assign(hir_id, spans, var, |name| {
+                            format!("value passed to `{}` is never read", name)
+                        });
+                    }
+                },
+            );
         }
     }
 
@@ -1522,6 +1540,7 @@ fn check_unused_vars_in_pat(
         &self,
         pat: &hir::Pat<'_>,
         entry_ln: Option<LiveNode>,
+        opt_body: Option<&hir::Body<'_>>,
         on_used_on_entry: impl Fn(Vec<Span>, HirId, LiveNode, Variable),
     ) {
         // In an or-pattern, only consider the variable; any later patterns must have the same
@@ -1549,18 +1568,20 @@ fn check_unused_vars_in_pat(
                     hir_ids_and_spans.into_iter().map(|(_, _, ident_span)| ident_span).collect();
                 on_used_on_entry(spans, id, ln, var);
             } else {
-                self.report_unused(hir_ids_and_spans, ln, var, can_remove);
+                self.report_unused(hir_ids_and_spans, ln, var, can_remove, pat, opt_body);
             }
         }
     }
 
-    #[tracing::instrument(skip(self), level = "INFO")]
+    #[instrument(skip(self), level = "INFO")]
     fn report_unused(
         &self,
         hir_ids_and_spans: Vec<(HirId, Span, Span)>,
         ln: LiveNode,
         var: Variable,
         can_remove: bool,
+        pat: &hir::Pat<'_>,
+        opt_body: Option<&hir::Body<'_>>,
     ) {
         let first_hir_id = hir_ids_and_spans[0].0;
 
@@ -1664,6 +1685,9 @@ fn report_unused(
                             .collect::<Vec<_>>(),
                         |lint| {
                             let mut err = lint.build(&format!("unused variable: `{}`", name));
+                            if self.has_added_lit_match_name_span(&name, opt_body, &mut err) {
+                                err.span_label(pat.span, "unused variable");
+                            }
                             err.multipart_suggestion(
                                 "if this is intentional, prefix it with an underscore",
                                 non_shorthands,
@@ -1677,6 +1701,42 @@ fn report_unused(
         }
     }
 
+    fn has_added_lit_match_name_span(
+        &self,
+        name: &str,
+        opt_body: Option<&hir::Body<'_>>,
+        err: &mut rustc_errors::DiagnosticBuilder<'_, ()>,
+    ) -> bool {
+        let mut has_litstring = false;
+        let Some(opt_body) = opt_body else {return false;};
+        let mut visitor = CollectLitsVisitor { lit_exprs: vec![] };
+        intravisit::walk_body(&mut visitor, opt_body);
+        for lit_expr in visitor.lit_exprs {
+            let hir::ExprKind::Lit(litx) = &lit_expr.kind else { continue };
+            let rustc_ast::LitKind::Str(syb, _) = litx.node else{ continue; };
+            let name_str: &str = syb.as_str();
+            let mut name_pa = String::from("{");
+            name_pa.push_str(&name);
+            name_pa.push('}');
+            if name_str.contains(&name_pa) {
+                err.span_label(
+                    lit_expr.span,
+                    "you might have meant to use string interpolation in this string literal",
+                );
+                err.multipart_suggestion(
+                    "string interpolation only works in `format!` invocations",
+                    vec![
+                        (lit_expr.span.shrink_to_lo(), "format!(".to_string()),
+                        (lit_expr.span.shrink_to_hi(), ")".to_string()),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+                has_litstring = true;
+            }
+        }
+        has_litstring
+    }
+
     fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
         if !self.live_on_exit(ln, var) {
             self.report_unused_assign(hir_id, spans, var, |name| {
index 1e423ddb7102cb753ae0bf8aefcc1d54664afc11..63f83f8965ec52c8a56e15123549eea3369dfef0 100644 (file)
@@ -75,6 +75,14 @@ pub struct InPublicInterface<'a> {
     pub vis_span: Span,
 }
 
+#[derive(SessionDiagnostic)]
+#[diag(privacy::report_access_level)]
+pub struct ReportAccessLevel {
+    #[primary_span]
+    pub span: Span,
+    pub descr: String,
+}
+
 #[derive(LintDiagnostic)]
 #[diag(privacy::from_private_dep_in_public_interface)]
 pub struct FromPrivateDependencyInPublicInterface<'a> {
index 5d562f18a815814785602fff35961933b7b32d0a..ba69bc23118b2527921188cdf8f7a595a97bef8b 100644 (file)
@@ -8,6 +8,9 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
+#[macro_use]
+extern crate tracing;
+
 mod errors;
 
 use rustc_ast::MacroDef;
@@ -30,7 +33,7 @@
 use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
-use rustc_span::symbol::{kw, Ident};
+use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 
 use std::marker::PhantomData;
@@ -39,7 +42,8 @@
 
 use errors::{
     FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
-    InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, UnnamedItemIsPrivate,
+    InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, ReportAccessLevel,
+    UnnamedItemIsPrivate,
 };
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -904,6 +908,60 @@ fn visit_def_id(
     }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+/// Visitor, used for AccessLevels table checking
+////////////////////////////////////////////////////////////////////////////////
+pub struct TestReachabilityVisitor<'tcx, 'a> {
+    tcx: TyCtxt<'tcx>,
+    access_levels: &'a AccessLevels,
+}
+
+impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
+    fn access_level_diagnostic(&mut self, def_id: LocalDefId) {
+        if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_access_level) {
+            let access_level = format!("{:?}", self.access_levels.map.get(&def_id));
+            let span = self.tcx.def_span(def_id.to_def_id());
+            self.tcx.sess.emit_err(ReportAccessLevel { span, descr: access_level });
+        }
+    }
+}
+
+impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> {
+    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
+        self.access_level_diagnostic(item.def_id);
+
+        match item.kind {
+            hir::ItemKind::Enum(ref def, _) => {
+                for variant in def.variants.iter() {
+                    let variant_id = self.tcx.hir().local_def_id(variant.id);
+                    self.access_level_diagnostic(variant_id);
+                    for field in variant.data.fields() {
+                        let def_id = self.tcx.hir().local_def_id(field.hir_id);
+                        self.access_level_diagnostic(def_id);
+                    }
+                }
+            }
+            hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
+                for field in def.fields() {
+                    let def_id = self.tcx.hir().local_def_id(field.hir_id);
+                    self.access_level_diagnostic(def_id);
+                }
+            }
+            _ => {}
+        }
+    }
+
+    fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) {
+        self.access_level_diagnostic(item.def_id);
+    }
+    fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) {
+        self.access_level_diagnostic(item.def_id);
+    }
+    fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
+        self.access_level_diagnostic(item.def_id);
+    }
+}
+
 //////////////////////////////////////////////////////////////////////////////////////
 /// Name privacy visitor, checks privacy and reports violations.
 /// Most of name privacy checks are performed during the main resolution phase,
@@ -1784,7 +1842,7 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
     fn leaks_private_dep(&self, item_id: DefId) -> bool {
         let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate);
 
-        tracing::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
+        debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
         ret
     }
 }
@@ -2042,6 +2100,9 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels {
         }
     }
 
+    let mut check_visitor = TestReachabilityVisitor { tcx, access_levels: &visitor.access_levels };
+    tcx.hir().visit_all_item_likes_in_crate(&mut check_visitor);
+
     tcx.arena.alloc(visitor.access_levels)
 }
 
index c37ae4f32536bd3bc8a41d0f8dadac8b21b01522..e7f12caaf33e523d03598df61ada434300698815 100644 (file)
@@ -8,7 +8,6 @@ doctest = false
 
 [dependencies]
 measureme = "10.0.0"
-rustc-rayon-core = { version = "0.4.0", optional = true }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
@@ -17,10 +16,12 @@ rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_query_system = { path = "../rustc_query_system" }
+rustc-rayon-core = { version = "0.4.0", optional = true }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
+thin-vec = "0.2.8"
 tracing = "0.1"
 
 [features]
index eab627c5d4c27edde273635a053f246ccf31be51..274df5b5e5e9415679ffd389b9ab3ee5626c9e18 100644 (file)
@@ -4,22 +4,23 @@
 
 use crate::keys::Key;
 use crate::{on_disk_cache, Queries};
-use rustc_middle::dep_graph::{self, DepKind, DepNodeIndex, SerializedDepNodeIndex};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::Lock;
+use rustc_errors::{Diagnostic, Handler};
+use rustc_middle::dep_graph::{
+    self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex,
+};
 use rustc_middle::ty::tls::{self, ImplicitCtxt};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_query_system::dep_graph::HasDepContext;
+use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_query_system::query::{
-    QueryContext, QueryJobId, QueryMap, QuerySideEffects, QueryStackFrame,
+    force_query, QueryConfig, QueryContext, QueryDescription, QueryJobId, QueryMap,
+    QuerySideEffects, QueryStackFrame,
 };
-
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::Lock;
-use rustc_data_structures::thin_vec::ThinVec;
-use rustc_errors::{Diagnostic, Handler};
-
 use std::any::Any;
 use std::num::NonZeroU64;
+use thin_vec::ThinVec;
 
 #[derive(Copy, Clone)]
 pub struct QueryCtxt<'tcx> {
@@ -300,6 +301,66 @@ pub(crate) fn create_query_frame<
     QueryStackFrame::new(name, description, span, def_kind, hash)
 }
 
+fn try_load_from_on_disk_cache<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode)
+where
+    Q: QueryDescription<QueryCtxt<'tcx>>,
+    Q::Key: DepNodeParams<TyCtxt<'tcx>>,
+{
+    debug_assert!(tcx.dep_graph.is_green(&dep_node));
+
+    let key = Q::Key::recover(tcx, &dep_node).unwrap_or_else(|| {
+        panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)
+    });
+    if Q::cache_on_disk(tcx, &key) {
+        let _ = Q::execute_query(tcx, key);
+    }
+}
+
+fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool
+where
+    Q: QueryDescription<QueryCtxt<'tcx>>,
+    Q::Key: DepNodeParams<TyCtxt<'tcx>>,
+{
+    if let Some(key) = Q::Key::recover(tcx, &dep_node) {
+        #[cfg(debug_assertions)]
+        let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
+        let tcx = QueryCtxt::from_tcx(tcx);
+        force_query::<Q, _>(tcx, key, dep_node);
+        true
+    } else {
+        false
+    }
+}
+
+pub(crate) fn query_callback<'tcx, Q: QueryConfig>(
+    is_anon: bool,
+    is_eval_always: bool,
+) -> DepKindStruct<'tcx>
+where
+    Q: QueryDescription<QueryCtxt<'tcx>>,
+    Q::Key: DepNodeParams<TyCtxt<'tcx>>,
+{
+    let fingerprint_style = Q::Key::fingerprint_style();
+
+    if is_anon || !fingerprint_style.reconstructible() {
+        return DepKindStruct {
+            is_anon,
+            is_eval_always,
+            fingerprint_style,
+            force_from_dep_node: None,
+            try_load_from_on_disk_cache: None,
+        };
+    }
+
+    DepKindStruct {
+        is_anon,
+        is_eval_always,
+        fingerprint_style,
+        force_from_dep_node: Some(force_from_dep_node::<Q>),
+        try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache::<Q>),
+    }
+}
+
 // NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros
 // invoked by `rustc_query_append`.
 macro_rules! define_queries {
@@ -310,18 +371,6 @@ macro_rules! define_queries {
             input: ($(([$($modifiers)*] [$($attr)*] [$name]))*)
         }
 
-        mod make_query {
-            use super::*;
-
-            // Create an eponymous constructor for each query.
-            $(#[allow(nonstandard_style)] $(#[$attr])*
-            pub fn $name<'tcx>(tcx: QueryCtxt<'tcx>, key: <queries::$name<'tcx> as QueryConfig>::Key) -> QueryStackFrame {
-                let kind = dep_graph::DepKind::$name;
-                let name = stringify!($name);
-                $crate::plumbing::create_query_frame(tcx, queries::$name::describe, key, kind, name)
-            })*
-        }
-
         #[allow(nonstandard_style)]
         mod queries {
             use std::marker::PhantomData;
@@ -375,18 +424,19 @@ fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
                     try_load_from_disk: Self::TRY_LOAD_FROM_DISK,
                 }
             }
+
+            fn execute_query(tcx: TyCtxt<'tcx>, k: Self::Key) -> Self::Stored {
+                tcx.$name(k)
+            }
         })*
 
         #[allow(nonstandard_style)]
         mod query_callbacks {
             use super::*;
-            use rustc_middle::dep_graph::DepNode;
-            use rustc_query_system::dep_graph::DepNodeParams;
-            use rustc_query_system::query::{force_query, QueryDescription};
             use rustc_query_system::dep_graph::FingerprintStyle;
 
             // We use this for most things when incr. comp. is turned off.
-            pub fn Null() -> DepKindStruct {
+            pub fn Null<'tcx>() -> DepKindStruct<'tcx> {
                 DepKindStruct {
                     is_anon: false,
                     is_eval_always: false,
@@ -397,7 +447,7 @@ pub fn Null() -> DepKindStruct {
             }
 
             // We use this for the forever-red node.
-            pub fn Red() -> DepKindStruct {
+            pub fn Red<'tcx>() -> DepKindStruct<'tcx> {
                 DepKindStruct {
                     is_anon: false,
                     is_eval_always: false,
@@ -407,7 +457,7 @@ pub fn Red() -> DepKindStruct {
                 }
             }
 
-            pub fn TraitSelect() -> DepKindStruct {
+            pub fn TraitSelect<'tcx>() -> DepKindStruct<'tcx> {
                 DepKindStruct {
                     is_anon: true,
                     is_eval_always: false,
@@ -417,7 +467,7 @@ pub fn TraitSelect() -> DepKindStruct {
                 }
             }
 
-            pub fn CompileCodegenUnit() -> DepKindStruct {
+            pub fn CompileCodegenUnit<'tcx>() -> DepKindStruct<'tcx> {
                 DepKindStruct {
                     is_anon: false,
                     is_eval_always: false,
@@ -427,7 +477,7 @@ pub fn CompileCodegenUnit() -> DepKindStruct {
                 }
             }
 
-            pub fn CompileMonoItem() -> DepKindStruct {
+            pub fn CompileMonoItem<'tcx>() -> DepKindStruct<'tcx> {
                 DepKindStruct {
                     is_anon: false,
                     is_eval_always: false,
@@ -437,60 +487,15 @@ pub fn CompileMonoItem() -> DepKindStruct {
                 }
             }
 
-            $(pub(crate) fn $name()-> DepKindStruct {
-                let is_anon = is_anon!([$($modifiers)*]);
-                let is_eval_always = is_eval_always!([$($modifiers)*]);
-
-                let fingerprint_style =
-                    <<queries::$name<'_> as QueryConfig>::Key as DepNodeParams<TyCtxt<'_>>>::fingerprint_style();
-
-                if is_anon || !fingerprint_style.reconstructible() {
-                    return DepKindStruct {
-                        is_anon,
-                        is_eval_always,
-                        fingerprint_style,
-                        force_from_dep_node: None,
-                        try_load_from_on_disk_cache: None,
-                    }
-                }
-
-                #[inline(always)]
-                fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> Option<<queries::$name<'tcx> as QueryConfig>::Key> {
-                    <<queries::$name<'_> as QueryConfig>::Key as DepNodeParams<TyCtxt<'_>>>::recover(tcx, &dep_node)
-                }
-
-                fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool {
-                    if let Some(key) = recover(tcx, dep_node) {
-                        #[cfg(debug_assertions)]
-                        let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
-                        let tcx = QueryCtxt::from_tcx(tcx);
-                        force_query::<queries::$name<'_>, _>(tcx, key, dep_node);
-                        true
-                    } else {
-                        false
-                    }
-                }
-
-                fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: DepNode) {
-                    debug_assert!(tcx.dep_graph.is_green(&dep_node));
-
-                    let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
-                    if queries::$name::cache_on_disk(tcx, &key) {
-                        let _ = tcx.$name(key);
-                    }
-                }
-
-                DepKindStruct {
-                    is_anon,
-                    is_eval_always,
-                    fingerprint_style,
-                    force_from_dep_node: Some(force_from_dep_node),
-                    try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache),
-                }
+            $(pub(crate) fn $name<'tcx>()-> DepKindStruct<'tcx> {
+                $crate::plumbing::query_callback::<queries::$name<'tcx>>(
+                    is_anon!([$($modifiers)*]),
+                    is_eval_always!([$($modifiers)*]),
+                )
             })*
         }
 
-        pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct] {
+        pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] {
             arena.alloc_from_iter(make_dep_kind_array!(query_callbacks))
         }
     }
@@ -533,9 +538,14 @@ pub(crate) fn try_collect_active_jobs(
                 let mut jobs = QueryMap::default();
 
                 $(
+                    let make_query = |tcx, key| {
+                        let kind = dep_graph::DepKind::$name;
+                        let name = stringify!($name);
+                        $crate::plumbing::create_query_frame(tcx, queries::$name::describe, key, kind, name)
+                    };
                     self.$name.try_collect_active_jobs(
                         tcx,
-                        make_query::$name,
+                        make_query,
                         &mut jobs,
                     )?;
                 )*
@@ -557,7 +567,7 @@ fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode)
 
             $($(#[$attr])*
             #[inline(always)]
-            #[tracing::instrument(level = "trace", skip(self, tcx))]
+            #[tracing::instrument(level = "trace", skip(self, tcx), ret)]
             fn $name(
                 &'tcx self,
                 tcx: TyCtxt<'tcx>,
index b7787aeb8f7655a60b4a114adc36c5536982886b..bafc6b0a082334826d40a6c0aa9980b05b91c3e7 100644 (file)
@@ -7,9 +7,8 @@ edition = "2021"
 doctest = false
 
 [dependencies]
+parking_lot = "0.11"
 rustc_arena = { path = "../rustc_arena" }
-tracing = "0.1"
-rustc-rayon-core = { version = "0.4.0", optional = true }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
@@ -17,12 +16,14 @@ rustc_feature = { path = "../rustc_feature" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
+rustc-rayon-core = { version = "0.4.0", optional = true }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
-parking_lot = "0.11"
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+thin-vec = "0.2.8"
+tracing = "0.1"
 
 [features]
 rustc_use_parallel_compiler = ["rustc-rayon-core"]
diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs
new file mode 100644 (file)
index 0000000..5f992ec
--- /dev/null
@@ -0,0 +1,73 @@
+use rustc_errors::AddSubdiagnostic;
+use rustc_span::Span;
+
+pub struct CycleStack {
+    pub span: Span,
+    pub desc: String,
+}
+
+impl AddSubdiagnostic for CycleStack {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        diag.span_note(self.span, &format!("...which requires {}...", self.desc));
+    }
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum StackCount {
+    #[note(query_system::cycle_stack_single)]
+    Single,
+    #[note(query_system::cycle_stack_multiple)]
+    Multiple,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum Alias {
+    #[note(query_system::cycle_recursive_ty_alias)]
+    #[help(query_system::cycle_recursive_ty_alias_help1)]
+    #[help(query_system::cycle_recursive_ty_alias_help2)]
+    Ty,
+    #[note(query_system::cycle_recursive_trait_alias)]
+    Trait,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[note(query_system::cycle_usage)]
+pub struct CycleUsage {
+    #[primary_span]
+    pub span: Span,
+    pub usage: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(query_system::cycle, code = "E0391")]
+pub struct Cycle {
+    #[primary_span]
+    pub span: Span,
+    pub stack_bottom: String,
+    #[subdiagnostic]
+    pub cycle_stack: Vec<CycleStack>,
+    #[subdiagnostic]
+    pub stack_count: StackCount,
+    #[subdiagnostic]
+    pub alias: Option<Alias>,
+    #[subdiagnostic]
+    pub cycle_usage: Option<CycleUsage>,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(query_system::reentrant)]
+pub struct Reentrant;
+
+#[derive(SessionDiagnostic)]
+#[diag(query_system::increment_compilation)]
+#[help]
+#[note(query_system::increment_compilation_note1)]
+#[note(query_system::increment_compilation_note2)]
+pub struct IncrementCompilation {
+    pub run_cmd: String,
+    pub dep_node: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(query_system::query_overflow)]
+pub struct QueryOverflow;
index 68284dcaa0be8213ef2f9add4b1b416a98e2297e..7067bc5f09cfc07229179036d4042896b836611b 100644 (file)
@@ -5,6 +5,8 @@
 #![feature(min_specialization)]
 #![feature(extern_types)]
 #![allow(rustc::potential_query_instability)]
+// #![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 
 #[macro_use]
 extern crate tracing;
@@ -15,5 +17,6 @@
 
 pub mod cache;
 pub mod dep_graph;
+mod error;
 pub mod ich;
 pub mod query;
index bd0fd7ac3503a16ede69e8faa1f30a5f8140916d..ea38df836cbf1e4a0f9b98b8cad319644a4ad8b6 100644 (file)
@@ -73,4 +73,7 @@ fn query_cache<'a>(tcx: CTX) -> &'a Self::Cache
     fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVTable<CTX, Self::Key, Self::Value>;
 
     fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool;
+
+    // Don't use this method to compute query results, instead use the methods on TyCtxt
+    fn execute_query(tcx: CTX::DepContext, k: Self::Key) -> Self::Stored;
 }
index 6d2aff38172facc9f4a0157dae89a56460442abb..ddb5cd0634407c5d09e9341b2018789ef415ca6c 100644 (file)
@@ -1,12 +1,11 @@
+use crate::error::CycleStack;
 use crate::query::plumbing::CycleError;
 use crate::query::{QueryContext, QueryStackFrame};
-use rustc_hir::def::DefKind;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{
-    struct_span_err, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, Level,
-};
-use rustc_session::Session;
+use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, Level};
+use rustc_hir::def::DefKind;
+use rustc_session::{Session, SessionDiagnostic};
 use rustc_span::Span;
 
 use std::hash::Hash;
@@ -536,46 +535,44 @@ pub(crate) fn report_cycle<'a>(
     assert!(!stack.is_empty());
 
     let span = stack[0].query.default_span(stack[1 % stack.len()].span);
-    let mut err =
-        struct_span_err!(sess, span, E0391, "cycle detected when {}", stack[0].query.description);
+
+    let mut cycle_stack = Vec::new();
+
+    use crate::error::StackCount;
+    let stack_count = if stack.len() == 1 { StackCount::Single } else { StackCount::Multiple };
 
     for i in 1..stack.len() {
         let query = &stack[i].query;
         let span = query.default_span(stack[(i + 1) % stack.len()].span);
-        err.span_note(span, &format!("...which requires {}...", query.description));
-    }
-
-    if stack.len() == 1 {
-        err.note(&format!("...which immediately requires {} again", stack[0].query.description));
-    } else {
-        err.note(&format!(
-            "...which again requires {}, completing the cycle",
-            stack[0].query.description
-        ));
-    }
-
-    if stack.iter().all(|entry| {
-        entry
-            .query
-            .def_kind
-            .map_or(false, |def_kind| matches!(def_kind, DefKind::TyAlias | DefKind::TraitAlias))
-    }) {
-        if stack.iter().all(|entry| {
-            entry.query.def_kind.map_or(false, |def_kind| matches!(def_kind, DefKind::TyAlias))
-        }) {
-            err.note("type aliases cannot be recursive");
-            err.help("consider using a struct, enum, or union instead to break the cycle");
-            err.help("see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information");
-        } else {
-            err.note("trait aliases cannot be recursive");
-        }
+        cycle_stack.push(CycleStack { span, desc: query.description.to_owned() });
     }
 
+    let mut cycle_usage = None;
     if let Some((span, query)) = usage {
-        err.span_note(query.default_span(span), &format!("cycle used when {}", query.description));
+        cycle_usage = Some(crate::error::CycleUsage {
+            span: query.default_span(span),
+            usage: query.description,
+        });
     }
 
-    err
+    let alias = if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TyAlias)) {
+        Some(crate::error::Alias::Ty)
+    } else if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TraitAlias)) {
+        Some(crate::error::Alias::Trait)
+    } else {
+        None
+    };
+
+    let cycle_diag = crate::error::Cycle {
+        span,
+        cycle_stack,
+        stack_bottom: stack[0].query.description.to_owned(),
+        alias,
+        cycle_usage: cycle_usage,
+        stack_count,
+    };
+
+    cycle_diag.into_diagnostic(&sess.parse_sess)
 }
 
 pub fn print_query_stack<CTX: QueryContext>(
index a1f2b081d43465f2515b88aead23859b8e53fd73..0b07bb64b6ae0b47e212e5451a23c0e78a3ab7dc 100644 (file)
 pub use self::config::{QueryConfig, QueryDescription, QueryVTable};
 
 use crate::dep_graph::{DepContext, DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
-
 use rustc_data_structures::sync::Lock;
-use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::Diagnostic;
 use rustc_hir::def::DefKind;
 use rustc_span::Span;
+use thin_vec::ThinVec;
 
 /// Description of a frame in the query stack.
 ///
@@ -125,6 +124,6 @@ fn start_query<R>(
     ) -> R;
 
     fn depth_limit_error(&self) {
-        self.dep_context().sess().fatal("queries overflow the depth limit!");
+        self.dep_context().sess().emit_fatal(crate::error::QueryOverflow);
     }
 }
index 6ae9147ff774fe1dfffb920e425cc08eddb1a125..7bbc22e8293a566ab9e2103ef9137bb5c07b359d 100644 (file)
@@ -14,7 +14,6 @@
 #[cfg(parallel_compiler)]
 use rustc_data_structures::sharded::Sharded;
 use rustc_data_structures::sync::Lock;
-use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, FatalError};
 use rustc_session::Session;
 use rustc_span::{Span, DUMMY_SP};
@@ -24,6 +23,7 @@
 use std::hash::Hash;
 use std::mem;
 use std::ptr;
+use thin_vec::ThinVec;
 
 pub struct QueryState<K> {
     #[cfg(parallel_compiler)]
@@ -618,16 +618,12 @@ fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: D
     let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true));
 
     if old_in_panic {
-        sess.struct_err(
-            "internal compiler error: re-entrant incremental verify failure, suppressing message",
-        )
-        .emit();
+        sess.emit_err(crate::error::Reentrant);
     } else {
-        sess.struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node))
-                .help(&format!("This is a known issue with the compiler. Run {} to allow your project to compile", run_cmd))
-                .note("Please follow the instructions below to create a bug report with the provided information")
-                .note("See <https://github.com/rust-lang/rust/issues/84970> for more information")
-                .emit();
+        sess.emit_err(crate::error::IncrementCompilation {
+            run_cmd,
+            dep_node: format!("{:?}", dep_node),
+        });
         panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
     }
 
index 3fba923d9fdf425c443300fb15eed97ba6ffdfd8..0a3add2e0f5328a7e7ff90ff20630d12408484e1 100644 (file)
@@ -1,25 +1,21 @@
+use crate::imports::ImportKind;
+use crate::NameBinding;
+use crate::NameBindingKind;
+use crate::Resolver;
 use rustc_ast::ast;
 use rustc_ast::visit;
 use rustc_ast::visit::Visitor;
 use rustc_ast::Crate;
 use rustc_ast::EnumDef;
-use rustc_ast::ForeignMod;
 use rustc_ast::NodeId;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_middle::middle::privacy::AccessLevel;
-use rustc_middle::ty::Visibility;
+use rustc_middle::ty::DefIdTree;
 use rustc_span::sym;
 
-use crate::imports::ImportKind;
-use crate::BindingKey;
-use crate::NameBinding;
-use crate::NameBindingKind;
-use crate::Resolver;
-
 pub struct AccessLevelsVisitor<'r, 'a> {
     r: &'r mut Resolver<'a>,
-    prev_level: Option<AccessLevel>,
     changed: bool,
 }
 
@@ -28,31 +24,32 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
     /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
     /// need access to a TyCtxt for that.
     pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
-        let mut visitor =
-            AccessLevelsVisitor { r, changed: false, prev_level: Some(AccessLevel::Public) };
+        let mut visitor = AccessLevelsVisitor { r, changed: false };
 
         visitor.set_access_level_def_id(CRATE_DEF_ID, Some(AccessLevel::Public));
-        visitor.set_exports_access_level(CRATE_DEF_ID);
+        visitor.set_bindings_access_level(CRATE_DEF_ID);
 
         while visitor.changed {
             visitor.reset();
             visit::walk_crate(&mut visitor, krate);
         }
 
-        tracing::info!("resolve::access_levels: {:#?}", r.access_levels);
+        info!("resolve::access_levels: {:#?}", r.access_levels);
     }
 
     fn reset(&mut self) {
         self.changed = false;
-        self.prev_level = Some(AccessLevel::Public);
     }
 
-    /// Update the access level of the exports of the given module accordingly. The module access
+    /// Update the access level of the bindings in the given module accordingly. The module access
     /// level has to be Exported or Public.
     /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
-    fn set_exports_access_level(&mut self, module_id: LocalDefId) {
+    fn set_bindings_access_level(&mut self, module_id: LocalDefId) {
         assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
-
+        let module_level = self.r.access_levels.map.get(&module_id).copied();
+        if !module_level.is_some() {
+            return;
+        }
         // Set the given binding access level to `AccessLevel::Public` and
         // sets the rest of the `use` chain to `AccessLevel::Exported` until
         // we hit the actual exported item.
@@ -72,28 +69,20 @@ fn set_exports_access_level(&mut self, module_id: LocalDefId) {
                 }
             };
 
-        let module_level = self.r.access_levels.map.get(&module_id).copied();
-        assert!(module_level >= Some(AccessLevel::Exported));
-
-        if let Some(exports) = self.r.reexport_map.get(&module_id) {
-            let pub_exports = exports
-                .iter()
-                .filter(|ex| ex.vis == Visibility::Public)
-                .cloned()
-                .collect::<Vec<_>>();
-
-            let module = self.r.get_module(module_id.to_def_id()).unwrap();
-            for export in pub_exports.into_iter() {
-                if let Some(export_def_id) = export.res.opt_def_id().and_then(|id| id.as_local()) {
-                    self.set_access_level_def_id(export_def_id, Some(AccessLevel::Exported));
-                }
-
-                if let Some(ns) = export.res.ns() {
-                    let key = BindingKey { ident: export.ident, ns, disambiguator: 0 };
-                    let name_res = self.r.resolution(module, key);
-                    if let Some(binding) = name_res.borrow().binding() {
-                        set_import_binding_access_level(self, binding, module_level)
-                    }
+        let module = self.r.get_module(module_id.to_def_id()).unwrap();
+        let resolutions = self.r.resolutions(module);
+
+        for (.., name_resolution) in resolutions.borrow().iter() {
+            if let Some(binding) = name_resolution.borrow().binding() && binding.vis.is_public() && !binding.is_ambiguity() {
+                let access_level = match binding.is_import() {
+                    true => {
+                        set_import_binding_access_level(self, binding, module_level);
+                        Some(AccessLevel::Exported)
+                    },
+                    false => module_level,
+                };
+                if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
+                    self.set_access_level_def_id(def_id, access_level);
                 }
             }
         }
@@ -127,97 +116,59 @@ fn set_access_level_def_id(
 
 impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
     fn visit_item(&mut self, item: &'ast ast::Item) {
-        let inherited_item_level = match item.kind {
+        let def_id = self.r.local_def_id(item.id);
+        // Set access level of nested items.
+        // If it's a mod, also make the visitor walk all of its items
+        match item.kind {
             // Resolved in rustc_privacy when types are available
             ast::ItemKind::Impl(..) => return,
 
-            // Only exported `macro_rules!` items are public, but they always are
-            ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
-                let is_macro_export =
-                    item.attrs.iter().any(|attr| attr.has_name(sym::macro_export));
-                if is_macro_export { Some(AccessLevel::Public) } else { None }
-            }
-
-            // Foreign modules inherit level from parents.
-            ast::ItemKind::ForeignMod(..) => self.prev_level,
-
-            // Other `pub` items inherit levels from parents.
-            ast::ItemKind::ExternCrate(..)
-            | ast::ItemKind::Use(..)
-            | ast::ItemKind::Static(..)
-            | ast::ItemKind::Const(..)
-            | ast::ItemKind::Fn(..)
-            | ast::ItemKind::Mod(..)
-            | ast::ItemKind::GlobalAsm(..)
-            | ast::ItemKind::TyAlias(..)
-            | ast::ItemKind::Enum(..)
-            | ast::ItemKind::Struct(..)
-            | ast::ItemKind::Union(..)
-            | ast::ItemKind::Trait(..)
-            | ast::ItemKind::TraitAlias(..)
-            | ast::ItemKind::MacroDef(..) => {
-                if item.vis.kind.is_pub() {
-                    self.prev_level
-                } else {
-                    None
-                }
-            }
-
             // Should be unreachable at this stage
             ast::ItemKind::MacCall(..) => panic!(
                 "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
             ),
-        };
 
-        let access_level = self.set_access_level(item.id, inherited_item_level);
+            // Foreign modules inherit level from parents.
+            ast::ItemKind::ForeignMod(..) => {
+                let parent_level =
+                    self.r.access_levels.map.get(&self.r.local_parent(def_id)).copied();
+                self.set_access_level(item.id, parent_level);
+            }
 
-        // Set access level of nested items.
-        // If it's a mod, also make the visitor walk all of its items
-        match item.kind {
-            ast::ItemKind::Mod(..) => {
-                if access_level.is_some() {
-                    self.set_exports_access_level(self.r.local_def_id(item.id));
+            // Only exported `macro_rules!` items are public, but they always are
+            ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
+                if item.attrs.iter().any(|attr| attr.has_name(sym::macro_export)) {
+                    self.set_access_level(item.id, Some(AccessLevel::Public));
                 }
+            }
 
-                let orig_level = std::mem::replace(&mut self.prev_level, access_level);
+            ast::ItemKind::Mod(..) => {
+                self.set_bindings_access_level(def_id);
                 visit::walk_item(self, item);
-                self.prev_level = orig_level;
             }
 
-            ast::ItemKind::ForeignMod(ForeignMod { ref items, .. }) => {
-                for nested in items {
-                    if nested.vis.kind.is_pub() {
-                        self.set_access_level(nested.id, access_level);
-                    }
-                }
-            }
             ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
+                self.set_bindings_access_level(def_id);
                 for variant in variants {
-                    let variant_level = self.set_access_level(variant.id, access_level);
-                    if let Some(ctor_id) = variant.data.ctor_id() {
-                        self.set_access_level(ctor_id, access_level);
-                    }
-
+                    let variant_def_id = self.r.local_def_id(variant.id);
+                    let variant_level = self.r.access_levels.map.get(&variant_def_id).copied();
                     for field in variant.data.fields() {
                         self.set_access_level(field.id, variant_level);
                     }
                 }
             }
-            ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
-                if let Some(ctor_id) = def.ctor_id() {
-                    self.set_access_level(ctor_id, access_level);
-                }
 
+            ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
+                let inherited_level = self.r.access_levels.map.get(&def_id).copied();
                 for field in def.fields() {
                     if field.vis.kind.is_pub() {
-                        self.set_access_level(field.id, access_level);
+                        self.set_access_level(field.id, inherited_level);
                     }
                 }
             }
-            ast::ItemKind::Trait(ref trait_kind) => {
-                for nested in trait_kind.items.iter() {
-                    self.set_access_level(nested.id, access_level);
-                }
+
+            ast::ItemKind::Trait(..) => {
+                self.set_bindings_access_level(def_id);
             }
 
             ast::ItemKind::ExternCrate(..)
@@ -229,9 +180,6 @@ fn visit_item(&mut self, item: &'ast ast::Item) {
             | ast::ItemKind::TraitAlias(..)
             | ast::ItemKind::MacroDef(..)
             | ast::ItemKind::Fn(..) => return,
-
-            // Unreachable kinds
-            ast::ItemKind::Impl(..) | ast::ItemKind::MacCall(..) => unreachable!(),
         }
     }
 }
index 8f3b6009bd6ef8a5f31fa6387c5badaceb443faf..51e8c24b9c25a51066088753bf4ec5b00a261798 100644 (file)
@@ -36,7 +36,6 @@
 
 use std::cell::Cell;
 use std::ptr;
-use tracing::debug;
 
 type Res = def::Res<NodeId>;
 
@@ -1030,7 +1029,7 @@ fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) {
                 self.insert_field_names(def_id, field_names);
             }
             Res::Def(DefKind::AssocFn, def_id) => {
-                if cstore.fn_has_self_parameter_untracked(def_id) {
+                if cstore.fn_has_self_parameter_untracked(def_id, self.r.session) {
                     self.r.has_self.insert(def_id);
                 }
             }
index 66641fb2cb248dc15446f722b0bb88f6f530a536..5955d8df16ee1edfa34f6edf2af8fca6c3cfc69c 100644 (file)
@@ -8,7 +8,6 @@
 use rustc_span::hygiene::LocalExpnId;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
-use tracing::debug;
 
 pub(crate) fn collect_definitions(
     resolver: &mut Resolver<'_>,
index 25013036d87493017476c616b04671b1d81548b2..4fd6fe4e36c69093babe14a7b3b2e8c214fa83d4 100644 (file)
@@ -25,7 +25,6 @@
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Span};
-use tracing::debug;
 
 use crate::imports::{Import, ImportKind, ImportResolver};
 use crate::late::{PatternSource, Rib};
@@ -1172,16 +1171,6 @@ fn early_lookup_typo_candidate(
                 Scope::Module(module, _) => {
                     this.add_module_candidates(module, &mut suggestions, filter_fn);
                 }
-                Scope::RegisteredAttrs => {
-                    let res = Res::NonMacroAttr(NonMacroAttrKind::Registered);
-                    if filter_fn(res) {
-                        suggestions.extend(
-                            this.registered_attrs
-                                .iter()
-                                .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)),
-                        );
-                    }
-                }
                 Scope::MacroUsePrelude => {
                     suggestions.extend(this.macro_use_prelude.iter().filter_map(
                         |(name, binding)| {
index 23c0ca108d38582e838522f8d5d1009ea86ba699..b84a610833ddf6a8faa398d6e070d0ef93b25136 100644 (file)
@@ -127,7 +127,6 @@ pub(crate) fn visit_scopes<T>(
                 }
                 Scope::CrateRoot => true,
                 Scope::Module(..) => true,
-                Scope::RegisteredAttrs => use_prelude,
                 Scope::MacroUsePrelude => use_prelude || rust_2015,
                 Scope::BuiltinAttrs => true,
                 Scope::ExternPrelude => use_prelude || is_absolute_path,
@@ -187,12 +186,11 @@ pub(crate) fn visit_scopes<T>(
                             match ns {
                                 TypeNS => Scope::ExternPrelude,
                                 ValueNS => Scope::StdLibPrelude,
-                                MacroNS => Scope::RegisteredAttrs,
+                                MacroNS => Scope::MacroUsePrelude,
                             }
                         }
                     }
                 }
-                Scope::RegisteredAttrs => Scope::MacroUsePrelude,
                 Scope::MacroUsePrelude => Scope::StdLibPrelude,
                 Scope::BuiltinAttrs => break, // nowhere else to search
                 Scope::ExternPrelude if is_absolute_path => break,
@@ -275,7 +273,7 @@ fn hygienic_lexical_parent(
     ///
     /// Invariant: This must only be called during main resolution, not during
     /// import resolution.
-    #[tracing::instrument(level = "debug", skip(self, ribs))]
+    #[instrument(level = "debug", skip(self, ribs))]
     pub(crate) fn resolve_ident_in_lexical_scope(
         &mut self,
         mut ident: Ident,
@@ -369,7 +367,7 @@ pub(crate) fn resolve_ident_in_lexical_scope(
     /// expansion and import resolution (perhaps they can be merged in the future).
     /// The function is used for resolving initial segments of macro paths (e.g., `foo` in
     /// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition.
-    #[tracing::instrument(level = "debug", skip(self, scope_set))]
+    #[instrument(level = "debug", skip(self, scope_set))]
     pub(crate) fn early_resolve_ident_in_lexical_scope(
         &mut self,
         orig_ident: Ident,
@@ -556,14 +554,6 @@ struct Flags: u8 {
                             Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
                         }
                     }
-                    Scope::RegisteredAttrs => match this.registered_attrs.get(&ident).cloned() {
-                        Some(ident) => ok(
-                            Res::NonMacroAttr(NonMacroAttrKind::Registered),
-                            ident.span,
-                            this.arenas,
-                        ),
-                        None => Err(Determinacy::Determined),
-                    },
                     Scope::MacroUsePrelude => {
                         match this.macro_use_prelude.get(&ident.name).cloned() {
                             Some(binding) => Ok((binding, Flags::MISC_FROM_PRELUDE)),
@@ -718,7 +708,7 @@ struct Flags: u8 {
         Err(Determinacy::determined(determinacy == Determinacy::Determined || force))
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn maybe_resolve_ident_in_module(
         &mut self,
         module: ModuleOrUniformRoot<'a>,
@@ -730,7 +720,7 @@ pub(crate) fn maybe_resolve_ident_in_module(
             .map_err(|(determinacy, _)| determinacy)
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn resolve_ident_in_module(
         &mut self,
         module: ModuleOrUniformRoot<'a>,
@@ -744,7 +734,7 @@ pub(crate) fn resolve_ident_in_module(
             .map_err(|(determinacy, _)| determinacy)
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn resolve_ident_in_module_ext(
         &mut self,
         module: ModuleOrUniformRoot<'a>,
@@ -782,7 +772,7 @@ fn resolve_ident_in_module_ext(
         )
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn resolve_ident_in_module_unadjusted(
         &mut self,
         module: ModuleOrUniformRoot<'a>,
@@ -806,7 +796,7 @@ fn resolve_ident_in_module_unadjusted(
 
     /// Attempts to resolve `ident` in namespaces `ns` of `module`.
     /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete.
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn resolve_ident_in_module_unadjusted_ext(
         &mut self,
         module: ModuleOrUniformRoot<'a>,
@@ -1069,7 +1059,7 @@ fn resolve_ident_in_module_unadjusted_ext(
     }
 
     /// Validate a local resolution (from ribs).
-    #[tracing::instrument(level = "debug", skip(self, all_ribs))]
+    #[instrument(level = "debug", skip(self, all_ribs))]
     fn validate_res_from_ribs(
         &mut self,
         rib_index: usize,
@@ -1304,7 +1294,7 @@ fn validate_res_from_ribs(
         res
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn maybe_resolve_path(
         &mut self,
         path: &[Segment],
@@ -1314,7 +1304,7 @@ pub(crate) fn maybe_resolve_path(
         self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None)
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn resolve_path(
         &mut self,
         path: &[Segment],
index c2491c6ebdec08892d03f255f2f991b4484b902a..27745cee52df7f3243630d103984205ecbb9db78 100644 (file)
@@ -23,8 +23,6 @@
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::Span;
 
-use tracing::*;
-
 use std::cell::Cell;
 use std::{mem, ptr};
 
@@ -1135,24 +1133,15 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>) {
         if let Some(def_id) = module.opt_def_id() {
             let mut reexports = Vec::new();
 
-            module.for_each_child(self.r, |_, ident, _, binding| {
-                // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules`
-                // into the crate root to actual `NameBindingKind::Import`.
-                if binding.is_import()
-                    || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true))
-                {
-                    let res = binding.res().expect_non_local();
-                    // Ambiguous imports are treated as errors at this point and are
-                    // not exposed to other crates (see #36837 for more details).
-                    if res != def::Res::Err && !binding.is_ambiguity() {
-                        reexports.push(ModChild {
-                            ident,
-                            res,
-                            vis: binding.vis,
-                            span: binding.span,
-                            macro_rules: false,
-                        });
-                    }
+            module.for_each_child(self.r, |this, ident, _, binding| {
+                if let Some(res) = this.is_reexport(binding) {
+                    reexports.push(ModChild {
+                        ident,
+                        res,
+                        vis: binding.vis,
+                        span: binding.span,
+                        macro_rules: false,
+                    });
                 }
             });
 
index 693ec86616ee431e3ff70e2bbeeef37228ba70f2..dbe4d691f04cdf1a465dc3d1598498294f27b784 100644 (file)
@@ -32,7 +32,6 @@
 use rustc_span::source_map::{respan, Spanned};
 use std::collections::{hash_map::Entry, BTreeSet};
 use std::mem::{replace, take};
-use tracing::debug;
 
 mod diagnostics;
 pub(crate) mod lifetimes;
@@ -1390,7 +1389,7 @@ fn visit_generic_params(&mut self, params: &'ast [GenericParam], add_self_upper:
         })
     }
 
-    #[tracing::instrument(level = "debug", skip(self, work))]
+    #[instrument(level = "debug", skip(self, work))]
     fn with_lifetime_rib<T>(
         &mut self,
         kind: LifetimeRibKind,
@@ -1404,7 +1403,7 @@ fn with_lifetime_rib<T>(
         ret
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::LifetimeCtxt) {
         let ident = lifetime.ident;
 
@@ -1508,7 +1507,7 @@ fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::Lifeti
         self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named);
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
         debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
 
@@ -1573,7 +1572,7 @@ fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
         self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) {
         let id = self.r.next_node_id();
         let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) };
@@ -1586,7 +1585,7 @@ fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) {
         self.resolve_anonymous_lifetime(&lt, true);
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, binder: NodeId) -> LifetimeRes {
         debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
         debug!(?ident.span);
@@ -1604,7 +1603,7 @@ fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, binder: NodeId) ->
         res
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn resolve_elided_lifetimes_in_path(
         &mut self,
         path_id: NodeId,
@@ -1804,7 +1803,7 @@ fn resolve_elided_lifetimes_in_path(
         }
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn record_lifetime_res(
         &mut self,
         id: NodeId,
@@ -1827,7 +1826,7 @@ fn record_lifetime_res(
         }
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) {
         if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
             panic!(
@@ -1838,7 +1837,7 @@ fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) {
     }
 
     /// Perform resolution of a function signature, accounting for lifetime elision.
-    #[tracing::instrument(level = "debug", skip(self, inputs))]
+    #[instrument(level = "debug", skip(self, inputs))]
     fn resolve_fn_signature(
         &mut self,
         fn_id: NodeId,
@@ -3268,11 +3267,9 @@ fn smart_resolve_path_fragment(
         source: PathSource<'ast>,
         finalize: Finalize,
     ) -> PartialRes {
-        tracing::debug!(
+        debug!(
             "smart_resolve_path_fragment(qself={:?}, path={:?}, finalize={:?})",
-            qself,
-            path,
-            finalize,
+            qself, path, finalize,
         );
         let ns = source.namespace();
 
index d41edea6a256f423fe03f88ee9ad6d160090fe5c..99d13acbae1b9aa5fd9afecc36f18949557bbc8b 100644 (file)
@@ -33,8 +33,6 @@
 use std::iter;
 use std::ops::Deref;
 
-use tracing::debug;
-
 type Res = def::Res<ast::NodeId>;
 
 /// A field or associated item from self type suggested in case of resolution failure.
@@ -1792,7 +1790,7 @@ fn suggest_using_enum_variant(
                 }
             };
 
-            let mut suggestable_variants = variants
+            let suggestable_variants = variants
                 .iter()
                 .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind))
                 .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
@@ -1802,8 +1800,9 @@ fn suggest_using_enum_variant(
                     CtorKind::Fictive => format!("({} {{}})", variant),
                 })
                 .collect::<Vec<_>>();
+            let no_suggestable_variant = suggestable_variants.is_empty();
 
-            if !suggestable_variants.is_empty() {
+            if !no_suggestable_variant {
                 let msg = if suggestable_variants.len() == 1 {
                     "you might have meant to use the following enum variant"
                 } else {
@@ -1813,7 +1812,7 @@ fn suggest_using_enum_variant(
                 err.span_suggestions(
                     span,
                     msg,
-                    suggestable_variants.drain(..),
+                    suggestable_variants.into_iter(),
                     Applicability::MaybeIncorrect,
                 );
             }
@@ -1830,15 +1829,15 @@ fn suggest_using_enum_variant(
                 .collect::<Vec<_>>();
 
             if !suggestable_variants_with_placeholders.is_empty() {
-                let msg = match (
-                    suggestable_variants.is_empty(),
-                    suggestable_variants_with_placeholders.len(),
-                ) {
-                    (true, 1) => "the following enum variant is available",
-                    (true, _) => "the following enum variants are available",
-                    (false, 1) => "alternatively, the following enum variant is available",
-                    (false, _) => "alternatively, the following enum variants are also available",
-                };
+                let msg =
+                    match (no_suggestable_variant, suggestable_variants_with_placeholders.len()) {
+                        (true, 1) => "the following enum variant is available",
+                        (true, _) => "the following enum variants are available",
+                        (false, 1) => "alternatively, the following enum variant is available",
+                        (false, _) => {
+                            "alternatively, the following enum variants are also available"
+                        }
+                    };
 
                 err.span_suggestions(
                     span,
index 94460e33d8b01a62b8be14afca238e9da2680555..c16eab222f625d8495bcf99e62d8fed42aef951e 100644 (file)
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefIdMap, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
 use rustc_middle::bug;
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::*;
-use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
-use std::borrow::Cow;
 use std::fmt;
-use std::mem::take;
 
 trait RegionExt {
-    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
+    fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
 
     fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
 
@@ -36,19 +34,13 @@ trait RegionExt {
     fn shifted(self, amount: u32) -> Region;
 
     fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region;
-
-    fn subst<'a, L>(self, params: L, map: &NamedRegionMap) -> Option<Region>
-    where
-        L: Iterator<Item = &'a hir::Lifetime>;
 }
 
 impl RegionExt for Region {
-    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region) {
-        let i = *index;
-        *index += 1;
+    fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
         let def_id = hir_map.local_def_id(param.hir_id);
-        debug!("Region::early: index={} def_id={:?}", i, def_id);
-        (def_id, Region::EarlyBound(i, def_id.to_def_id()))
+        debug!("Region::early: def_id={:?}", def_id);
+        (def_id, Region::EarlyBound(def_id.to_def_id()))
     }
 
     fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
@@ -65,9 +57,7 @@ fn id(&self) -> Option<DefId> {
         match *self {
             Region::Static => None,
 
-            Region::EarlyBound(_, id) | Region::LateBound(_, _, id) | Region::Free(_, id) => {
-                Some(id)
-            }
+            Region::EarlyBound(id) | Region::LateBound(_, _, id) | Region::Free(_, id) => Some(id),
         }
     }
 
@@ -88,17 +78,6 @@ fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region {
             _ => self,
         }
     }
-
-    fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option<Region>
-    where
-        L: Iterator<Item = &'a hir::Lifetime>,
-    {
-        if let Region::EarlyBound(index, _) = self {
-            params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned())
-        } else {
-            Some(self)
-        }
-    }
 }
 
 /// Maps the id of each lifetime reference to the lifetime decl
@@ -131,9 +110,6 @@ pub(crate) struct LifetimeContext<'a, 'tcx> {
     /// be false if the `Item` we are resolving lifetimes for is not a trait or
     /// we eventually need lifetimes resolve for trait items.
     trait_definition_only: bool,
-
-    /// Cache for cross-crate per-definition object lifetime defaults.
-    xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
 }
 
 #[derive(Debug)]
@@ -147,25 +123,6 @@ enum Scope<'a> {
         /// for diagnostics.
         lifetimes: FxIndexMap<LocalDefId, Region>,
 
-        /// if we extend this scope with another scope, what is the next index
-        /// we should use for an early-bound region?
-        next_early_index: u32,
-
-        /// Whether or not this binder would serve as the parent
-        /// binder for opaque types introduced within. For example:
-        ///
-        /// ```text
-        ///     fn foo<'a>() -> impl for<'b> Trait<Item = impl Trait2<'a>>
-        /// ```
-        ///
-        /// Here, the opaque types we create for the `impl Trait`
-        /// and `impl Trait2` references will both have the `foo` item
-        /// as their parent. When we get to `impl Trait2`, we find
-        /// that it is nested within the `for<>` binder -- this flag
-        /// allows us to skip that when looking for the parent binder
-        /// of the resulting opaque type.
-        opaque_type_parent: bool,
-
         scope_type: BinderScopeType,
 
         /// The late bound vars for a given item are stored by `HirId` to be
@@ -245,19 +202,9 @@ enum BinderScopeType {
 impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.0 {
-            Scope::Binder {
-                lifetimes,
-                next_early_index,
-                opaque_type_parent,
-                scope_type,
-                hir_id,
-                where_bound_origin,
-                s: _,
-            } => f
+            Scope::Binder { lifetimes, scope_type, hir_id, where_bound_origin, s: _ } => f
                 .debug_struct("Binder")
                 .field("lifetimes", lifetimes)
-                .field("next_early_index", next_early_index)
-                .field("opaque_type_parent", opaque_type_parent)
                 .field("scope_type", scope_type)
                 .field("hir_id", hir_id)
                 .field("where_bound_origin", where_bound_origin)
@@ -294,10 +241,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
 
         named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id),
         is_late_bound_map,
-        object_lifetime_defaults: |tcx, id| match tcx.hir().find_by_def_id(id) {
-            Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item),
-            _ => None,
-        },
+        object_lifetime_default,
         late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
 
         ..*providers
@@ -334,7 +278,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
 /// lifetimes into a single binder.) This requires us to resolve the
 /// *trait definition* of `Sub`; basically just enough lifetime information
 /// to look at the supertraits.
-#[tracing::instrument(level = "debug", skip(tcx))]
+#[instrument(level = "debug", skip(tcx))]
 fn resolve_lifetimes_trait_definition(
     tcx: TyCtxt<'_>,
     local_def_id: LocalDefId,
@@ -345,7 +289,7 @@ fn resolve_lifetimes_trait_definition(
 /// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
 /// You should not read the result of this query directly, but rather use
 /// `named_region_map`, `is_late_bound_map`, etc.
-#[tracing::instrument(level = "debug", skip(tcx))]
+#[instrument(level = "debug", skip(tcx))]
 fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
     convert_named_region_map(do_resolve(tcx, local_def_id, false))
 }
@@ -363,7 +307,6 @@ fn do_resolve(
         map: &mut named_region_map,
         scope: ROOT_SCOPE,
         trait_definition_only,
-        xcrate_object_lifetime_defaults: Default::default(),
     };
     visitor.visit_item(item);
 
@@ -432,13 +375,6 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
     item
 }
 
-/// In traits, there is an implicit `Self` type parameter which comes before the generics.
-/// We have to account for this when computing the index of the other generic parameters.
-/// This function returns whether there is such an implicit parameter defined on the given item.
-fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool {
-    matches!(*node, hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..))
-}
-
 fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind {
     match region {
         Region::LateBound(_, _, def_id) => {
@@ -558,7 +494,6 @@ fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
                 }
             }
 
-            let next_early_index = self.next_early_index();
             let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
                 bound_generic_params
                     .iter()
@@ -576,8 +511,6 @@ fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
                 hir_id: e.hir_id,
                 lifetimes,
                 s: self.scope,
-                next_early_index,
-                opaque_type_parent: false,
                 scope_type: BinderScopeType::Normal,
                 where_bound_origin: None,
             };
@@ -603,7 +536,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         }
         match item.kind {
             hir::ItemKind::Fn(_, ref generics, _) => {
-                self.visit_early_late(None, item.hir_id(), generics, |this| {
+                self.visit_early_late(item.hir_id(), generics, |this| {
                     intravisit::walk_item(this, item);
                 });
             }
@@ -670,31 +603,20 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             | hir::ItemKind::TraitAlias(ref generics, ..)
             | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
                 // These kinds of items have only early-bound lifetime parameters.
-                let mut index = if sub_items_have_self_param(&item.kind) {
-                    1 // Self comes before lifetimes
-                } else {
-                    0
-                };
-                let mut non_lifetime_count = 0;
                 let lifetimes = generics
                     .params
                     .iter()
                     .filter_map(|param| match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(self.tcx.hir(), &mut index, param))
-                        }
-                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                            non_lifetime_count += 1;
-                            None
+                            Some(Region::early(self.tcx.hir(), param))
                         }
+                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
                     })
                     .collect();
                 self.map.late_bound_vars.insert(item.hir_id(), vec![]);
                 let scope = Scope::Binder {
                     hir_id: item.hir_id(),
                     lifetimes,
-                    next_early_index: index + non_lifetime_count,
-                    opaque_type_parent: true,
                     scope_type: BinderScopeType::Normal,
                     s: ROOT_SCOPE,
                     where_bound_origin: None,
@@ -712,7 +634,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
         match item.kind {
             hir::ForeignItemKind::Fn(_, _, ref generics) => {
-                self.visit_early_late(None, item.hir_id(), generics, |this| {
+                self.visit_early_late(item.hir_id(), generics, |this| {
                     intravisit::walk_foreign_item(this, item);
                 })
             }
@@ -725,11 +647,10 @@ fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
         }
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
         match ty.kind {
             hir::TyKind::BareFn(ref c) => {
-                let next_early_index = self.next_early_index();
                 let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
                     .generic_params
                     .iter()
@@ -746,8 +667,6 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     hir_id: ty.hir_id,
                     lifetimes,
                     s: self.scope,
-                    next_early_index,
-                    opaque_type_parent: false,
                     scope_type: BinderScopeType::Normal,
                     where_bound_origin: None,
                 };
@@ -886,32 +805,23 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
 
                 // We want to start our early-bound indices at the end of the parent scope,
                 // not including any parent `impl Trait`s.
-                let mut index = self.next_early_index_for_opaque_type();
-                debug!(?index);
-
                 let mut lifetimes = FxIndexMap::default();
-                let mut non_lifetime_count = 0;
                 debug!(?generics.params);
                 for param in generics.params {
                     match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, &param);
+                            let (def_id, reg) = Region::early(self.tcx.hir(), &param);
                             lifetimes.insert(def_id, reg);
                         }
-                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                            non_lifetime_count += 1;
-                        }
+                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
                     }
                 }
-                let next_early_index = index + non_lifetime_count;
                 self.map.late_bound_vars.insert(ty.hir_id, vec![]);
 
                 let scope = Scope::Binder {
                     hir_id: ty.hir_id,
                     lifetimes,
-                    next_early_index,
                     s: self.scope,
-                    opaque_type_parent: false,
                     scope_type: BinderScopeType::Normal,
                     where_bound_origin: None,
                 };
@@ -933,39 +843,27 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         use self::hir::TraitItemKind::*;
         match trait_item.kind {
             Fn(_, _) => {
-                let tcx = self.tcx;
-                self.visit_early_late(
-                    Some(tcx.hir().get_parent_item(trait_item.hir_id())),
-                    trait_item.hir_id(),
-                    &trait_item.generics,
-                    |this| intravisit::walk_trait_item(this, trait_item),
-                );
+                self.visit_early_late(trait_item.hir_id(), &trait_item.generics, |this| {
+                    intravisit::walk_trait_item(this, trait_item)
+                });
             }
             Type(bounds, ref ty) => {
                 let generics = &trait_item.generics;
-                let mut index = self.next_early_index();
-                debug!("visit_ty: index = {}", index);
-                let mut non_lifetime_count = 0;
                 let lifetimes = generics
                     .params
                     .iter()
                     .filter_map(|param| match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(self.tcx.hir(), &mut index, param))
-                        }
-                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                            non_lifetime_count += 1;
-                            None
+                            Some(Region::early(self.tcx.hir(), param))
                         }
+                        GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
                     })
                     .collect();
                 self.map.late_bound_vars.insert(trait_item.hir_id(), vec![]);
                 let scope = Scope::Binder {
                     hir_id: trait_item.hir_id(),
                     lifetimes,
-                    next_early_index: index + non_lifetime_count,
                     s: self.scope,
-                    opaque_type_parent: true,
                     scope_type: BinderScopeType::Normal,
                     where_bound_origin: None,
                 };
@@ -993,40 +891,26 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         use self::hir::ImplItemKind::*;
         match impl_item.kind {
-            Fn(..) => {
-                let tcx = self.tcx;
-                self.visit_early_late(
-                    Some(tcx.hir().get_parent_item(impl_item.hir_id())),
-                    impl_item.hir_id(),
-                    &impl_item.generics,
-                    |this| intravisit::walk_impl_item(this, impl_item),
-                );
-            }
+            Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| {
+                intravisit::walk_impl_item(this, impl_item)
+            }),
             TyAlias(ref ty) => {
                 let generics = &impl_item.generics;
-                let mut index = self.next_early_index();
-                let mut non_lifetime_count = 0;
-                debug!("visit_ty: index = {}", index);
                 let lifetimes: FxIndexMap<LocalDefId, Region> = generics
                     .params
                     .iter()
                     .filter_map(|param| match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(self.tcx.hir(), &mut index, param))
-                        }
-                        GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => {
-                            non_lifetime_count += 1;
-                            None
+                            Some(Region::early(self.tcx.hir(), param))
                         }
+                        GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None,
                     })
                     .collect();
                 self.map.late_bound_vars.insert(ty.hir_id, vec![]);
                 let scope = Scope::Binder {
                     hir_id: ty.hir_id,
                     lifetimes,
-                    next_early_index: index + non_lifetime_count,
                     s: self.scope,
-                    opaque_type_parent: true,
                     scope_type: BinderScopeType::Normal,
                     where_bound_origin: None,
                 };
@@ -1046,7 +930,7 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         }
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
         match lifetime_ref.name {
             hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static),
@@ -1129,7 +1013,6 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                                 })
                                 .unzip();
                         this.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone());
-                        let next_early_index = this.next_early_index();
                         // Even if there are no lifetimes defined here, we still wrap it in a binder
                         // scope. If there happens to be a nested poly trait ref (an error), that
                         // will be `Concatenating` anyways, so we don't have to worry about the depth
@@ -1138,8 +1021,6 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                             hir_id: bounded_ty.hir_id,
                             lifetimes,
                             s: this.scope,
-                            next_early_index,
-                            opaque_type_parent: false,
                             scope_type: BinderScopeType::Normal,
                             where_bound_origin: Some(origin),
                         };
@@ -1210,8 +1091,6 @@ fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) {
                     hir_id: *hir_id,
                     lifetimes: FxIndexMap::default(),
                     s: self.scope,
-                    next_early_index: self.next_early_index(),
-                    opaque_type_parent: false,
                     scope_type,
                     where_bound_origin: None,
                 };
@@ -1230,7 +1109,6 @@ fn visit_poly_trait_ref(
     ) {
         debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
 
-        let next_early_index = self.next_early_index();
         let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
 
         let initial_bound_vars = binders.len() as u32;
@@ -1260,8 +1138,6 @@ fn visit_poly_trait_ref(
             hir_id: trait_ref.trait_ref.hir_ref_id,
             lifetimes,
             s: self.scope,
-            next_early_index,
-            opaque_type_parent: false,
             scope_type,
             where_bound_origin: None,
         };
@@ -1272,127 +1148,46 @@ fn visit_poly_trait_ref(
     }
 }
 
-fn compute_object_lifetime_defaults<'tcx>(
+fn object_lifetime_default<'tcx>(
     tcx: TyCtxt<'tcx>,
-    item: &hir::Item<'_>,
-) -> Option<&'tcx [ObjectLifetimeDefault]> {
-    match item.kind {
-        hir::ItemKind::Struct(_, ref generics)
-        | hir::ItemKind::Union(_, ref generics)
-        | hir::ItemKind::Enum(_, ref generics)
-        | hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-            ref generics,
-            origin: hir::OpaqueTyOrigin::TyAlias,
-            ..
-        })
-        | hir::ItemKind::TyAlias(_, ref generics)
-        | hir::ItemKind::Trait(_, _, ref generics, ..) => {
-            let result = object_lifetime_defaults_for_item(tcx, generics);
-
-            // Debugging aid.
-            let attrs = tcx.hir().attrs(item.hir_id());
-            if tcx.sess.contains_name(attrs, sym::rustc_object_lifetime_default) {
-                let object_lifetime_default_reprs: String = result
-                    .iter()
-                    .map(|set| match *set {
-                        Set1::Empty => "BaseDefault".into(),
-                        Set1::One(Region::Static) => "'static".into(),
-                        Set1::One(Region::EarlyBound(mut i, _)) => generics
-                            .params
-                            .iter()
-                            .find_map(|param| match param.kind {
-                                GenericParamKind::Lifetime { .. } => {
-                                    if i == 0 {
-                                        return Some(param.name.ident().to_string().into());
-                                    }
-                                    i -= 1;
-                                    None
-                                }
-                                _ => None,
-                            })
-                            .unwrap(),
-                        Set1::One(_) => bug!(),
-                        Set1::Many => "Ambiguous".into(),
-                    })
-                    .collect::<Vec<Cow<'static, str>>>()
-                    .join(",");
-                tcx.sess.span_err(item.span, &object_lifetime_default_reprs);
-            }
-
-            Some(result)
-        }
-        _ => None,
-    }
-}
-
-/// Scan the bounds and where-clauses on parameters to extract bounds
-/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
-/// for each type parameter.
-fn object_lifetime_defaults_for_item<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    generics: &hir::Generics<'_>,
-) -> &'tcx [ObjectLifetimeDefault] {
-    fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::GenericBound<'_>]) {
-        for bound in bounds {
-            if let hir::GenericBound::Outlives(ref lifetime) = *bound {
-                set.insert(lifetime.name.normalize_to_macros_2_0());
-            }
-        }
-    }
-
-    let process_param = |param: &hir::GenericParam<'_>| match param.kind {
+    param_def_id: DefId,
+) -> Option<ObjectLifetimeDefault> {
+    let param_def_id = param_def_id.expect_local();
+    let parent_def_id = tcx.local_parent(param_def_id);
+    let generics = tcx.hir().get_generics(parent_def_id)?;
+    let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id);
+    let param = generics.params.iter().find(|p| p.hir_id == param_hir_id)?;
+
+    // Scan the bounds and where-clauses on parameters to extract bounds
+    // of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
+    // for each type parameter.
+    match param.kind {
         GenericParamKind::Lifetime { .. } => None,
         GenericParamKind::Type { .. } => {
             let mut set = Set1::Empty;
 
-            let param_def_id = tcx.hir().local_def_id(param.hir_id);
-            for predicate in generics.predicates {
-                // Look for `type: ...` where clauses.
-                let hir::WherePredicate::BoundPredicate(ref data) = *predicate else { continue };
-
+            // Look for `type: ...` where clauses.
+            for bound in generics.bounds_for_param(param_def_id) {
                 // Ignore `for<'a> type: ...` as they can change what
                 // lifetimes mean (although we could "just" handle it).
-                if !data.bound_generic_params.is_empty() {
+                if !bound.bound_generic_params.is_empty() {
                     continue;
                 }
 
-                let res = match data.bounded_ty.kind {
-                    hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res,
-                    _ => continue,
-                };
-
-                if res == Res::Def(DefKind::TyParam, param_def_id.to_def_id()) {
-                    add_bounds(&mut set, &data.bounds);
+                for bound in bound.bounds {
+                    if let hir::GenericBound::Outlives(ref lifetime) = *bound {
+                        set.insert(lifetime.name.normalize_to_macros_2_0());
+                    }
                 }
             }
 
             Some(match set {
-                Set1::Empty => Set1::Empty,
-                Set1::One(name) => {
-                    if name == hir::LifetimeName::Static {
-                        Set1::One(Region::Static)
-                    } else {
-                        generics
-                            .params
-                            .iter()
-                            .filter_map(|param| match param.kind {
-                                GenericParamKind::Lifetime { .. } => {
-                                    let param_def_id = tcx.hir().local_def_id(param.hir_id);
-                                    Some((
-                                        param_def_id,
-                                        hir::LifetimeName::Param(param_def_id, param.name),
-                                    ))
-                                }
-                                _ => None,
-                            })
-                            .enumerate()
-                            .find(|&(_, (_, lt_name))| lt_name == name)
-                            .map_or(Set1::Many, |(i, (def_id, _))| {
-                                Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id()))
-                            })
-                    }
+                Set1::Empty => ObjectLifetimeDefault::Empty,
+                Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
+                Set1::One(hir::LifetimeName::Param(param_def_id, _)) => {
+                    ObjectLifetimeDefault::Param(param_def_id.to_def_id())
                 }
-                Set1::Many => Set1::Many,
+                _ => ObjectLifetimeDefault::Ambiguous,
             })
         }
         GenericParamKind::Const { .. } => {
@@ -1400,11 +1195,9 @@ fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::GenericBound<'_>
             //
             // We still store a dummy value here to allow generic parameters
             // in an arbitrary order.
-            Some(Set1::Empty)
+            Some(ObjectLifetimeDefault::Empty)
         }
-    };
-
-    tcx.arena.alloc_from_iter(generics.params.iter().filter_map(process_param))
+    }
 }
 
 impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
@@ -1413,20 +1206,17 @@ fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
         F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
     {
         let LifetimeContext { tcx, map, .. } = self;
-        let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
         let mut this = LifetimeContext {
             tcx: *tcx,
             map,
             scope: &wrap_scope,
             trait_definition_only: self.trait_definition_only,
-            xcrate_object_lifetime_defaults,
         };
-        let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
+        let span = debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
         {
             let _enter = span.enter();
             f(&mut this);
         }
-        self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
     }
 
     /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
@@ -1449,30 +1239,12 @@ fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
     /// ordering is not important there.
     fn visit_early_late<F>(
         &mut self,
-        parent_id: Option<LocalDefId>,
         hir_id: hir::HirId,
         generics: &'tcx hir::Generics<'tcx>,
         walk: F,
     ) where
         F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
     {
-        // Find the start of nested early scopes, e.g., in methods.
-        let mut next_early_index = 0;
-        if let Some(parent_id) = parent_id {
-            let parent = self.tcx.hir().expect_item(parent_id);
-            if sub_items_have_self_param(&parent.kind) {
-                next_early_index += 1; // Self comes before lifetimes
-            }
-            match parent.kind {
-                hir::ItemKind::Trait(_, _, ref generics, ..)
-                | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
-                    next_early_index += generics.params.len() as u32;
-                }
-                _ => {}
-            }
-        }
-
-        let mut non_lifetime_count = 0;
         let mut named_late_bound_vars = 0;
         let lifetimes: FxIndexMap<LocalDefId, Region> = generics
             .params
@@ -1484,16 +1256,12 @@ fn visit_early_late<F>(
                         named_late_bound_vars += 1;
                         Some(Region::late(late_bound_idx, self.tcx.hir(), param))
                     } else {
-                        Some(Region::early(self.tcx.hir(), &mut next_early_index, param))
+                        Some(Region::early(self.tcx.hir(), param))
                     }
                 }
-                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                    non_lifetime_count += 1;
-                    None
-                }
+                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
             })
             .collect();
-        let next_early_index = next_early_index + non_lifetime_count;
 
         let binders: Vec<_> = generics
             .params
@@ -1512,52 +1280,14 @@ fn visit_early_late<F>(
         let scope = Scope::Binder {
             hir_id,
             lifetimes,
-            next_early_index,
             s: self.scope,
-            opaque_type_parent: true,
             scope_type: BinderScopeType::Normal,
             where_bound_origin: None,
         };
         self.with(scope, walk);
     }
 
-    fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 {
-        let mut scope = self.scope;
-        loop {
-            match *scope {
-                Scope::Root => return 0,
-
-                Scope::Binder { next_early_index, opaque_type_parent, .. }
-                    if (!only_opaque_type_parent || opaque_type_parent) =>
-                {
-                    return next_early_index;
-                }
-
-                Scope::Binder { s, .. }
-                | Scope::Body { s, .. }
-                | Scope::Elision { s, .. }
-                | Scope::ObjectLifetimeDefault { s, .. }
-                | Scope::Supertrait { s, .. }
-                | Scope::TraitRefBoundary { s, .. } => scope = s,
-            }
-        }
-    }
-
-    /// Returns the next index one would use for an early-bound-region
-    /// if extending the current scope.
-    fn next_early_index(&self) -> u32 {
-        self.next_early_index_helper(true)
-    }
-
-    /// Returns the next index one would use for an `impl Trait` that
-    /// is being converted into an opaque type alias `impl Trait`. This will be the
-    /// next early index from the enclosing item, for the most
-    /// part. See the `opaque_type_parent` field for more info.
-    fn next_early_index_for_opaque_type(&self) -> u32 {
-        self.next_early_index_helper(false)
-    }
-
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn resolve_lifetime_ref(
         &mut self,
         region_def_id: LocalDefId,
@@ -1638,7 +1368,7 @@ fn resolve_lifetime_ref(
             return;
         }
 
-        // We may fail to resolve higher-ranked lifetimes that are mentionned by APIT.
+        // We may fail to resolve higher-ranked lifetimes that are mentioned by APIT.
         // AST-based resolution does not care for impl-trait desugaring, which are the
         // responibility of lowering.  This may create a mismatch between the resolution
         // AST found (`region_def_id`) which points to HRTB, and what HIR allows.
@@ -1679,17 +1409,13 @@ fn resolve_lifetime_ref(
         );
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn visit_segment_args(
         &mut self,
         res: Res,
         depth: usize,
         generic_args: &'tcx hir::GenericArgs<'tcx>,
     ) {
-        debug!(
-            "visit_segment_args(res={:?}, depth={:?}, generic_args={:?})",
-            res, depth, generic_args,
-        );
-
         if generic_args.parenthesized {
             self.visit_fn_like_elision(
                 generic_args.inputs(),
@@ -1707,13 +1433,9 @@ fn visit_segment_args(
 
         // Figure out if this is a type/trait segment,
         // which requires object lifetime defaults.
-        let parent_def_id = |this: &mut Self, def_id: DefId| {
-            let def_key = this.tcx.def_key(def_id);
-            DefId { krate: def_id.krate, index: def_key.parent.expect("missing parent") }
-        };
         let type_def_id = match res {
-            Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(parent_def_id(self, def_id)),
-            Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(parent_def_id(self, def_id)),
+            Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(self.tcx.parent(def_id)),
+            Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(self.tcx.parent(def_id)),
             Res::Def(
                 DefKind::Struct
                 | DefKind::Union
@@ -1725,7 +1447,7 @@ fn visit_segment_args(
             _ => None,
         };
 
-        debug!("visit_segment_args: type_def_id={:?}", type_def_id);
+        debug!(?type_def_id);
 
         // Compute a vector of defaults, one for each type parameter,
         // per the rules given in RFCs 599 and 1156. Example:
@@ -1763,55 +1485,39 @@ fn visit_segment_args(
             };
 
             let map = &self.map;
-            let set_to_region = |set: &ObjectLifetimeDefault| match *set {
-                Set1::Empty => {
+            let generics = self.tcx.generics_of(def_id);
+
+            // `type_def_id` points to an item, so there is nothing to inherit generics from.
+            debug_assert_eq!(generics.parent_count, 0);
+
+            let set_to_region = |set: ObjectLifetimeDefault| match set {
+                ObjectLifetimeDefault::Empty => {
                     if in_body {
                         None
                     } else {
                         Some(Region::Static)
                     }
                 }
-                Set1::One(r) => {
-                    let lifetimes = generic_args.args.iter().filter_map(|arg| match arg {
-                        GenericArg::Lifetime(lt) => Some(lt),
+                ObjectLifetimeDefault::Static => Some(Region::Static),
+                ObjectLifetimeDefault::Param(param_def_id) => {
+                    // This index can be used with `generic_args` since `parent_count == 0`.
+                    let index = generics.param_def_id_to_index[&param_def_id] as usize;
+                    generic_args.args.get(index).and_then(|arg| match arg {
+                        GenericArg::Lifetime(lt) => map.defs.get(&lt.hir_id).copied(),
                         _ => None,
-                    });
-                    r.subst(lifetimes, map)
+                    })
                 }
-                Set1::Many => None,
+                ObjectLifetimeDefault::Ambiguous => None,
             };
-            if let Some(def_id) = def_id.as_local() {
-                let id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-                self.tcx
-                    .object_lifetime_defaults(id.owner)
-                    .unwrap()
-                    .iter()
-                    .map(set_to_region)
-                    .collect()
-            } else {
-                let tcx = self.tcx;
-                self.xcrate_object_lifetime_defaults
-                    .entry(def_id)
-                    .or_insert_with(|| {
-                        tcx.generics_of(def_id)
-                            .params
-                            .iter()
-                            .filter_map(|param| match param.kind {
-                                GenericParamDefKind::Type { object_lifetime_default, .. } => {
-                                    Some(object_lifetime_default)
-                                }
-                                GenericParamDefKind::Const { .. } => Some(Set1::Empty),
-                                GenericParamDefKind::Lifetime => None,
-                            })
-                            .collect()
-                    })
-                    .iter()
-                    .map(set_to_region)
-                    .collect()
-            }
+            generics
+                .params
+                .iter()
+                .filter_map(|param| self.tcx.object_lifetime_default(param.def_id))
+                .map(set_to_region)
+                .collect()
         });
 
-        debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults);
+        debug!(?object_lifetime_defaults);
 
         let mut i = 0;
         for arg in generic_args.args {
@@ -1953,7 +1659,7 @@ fn supertrait_hrtb_lifetimes(
         }
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_fn_like_elision(
         &mut self,
         inputs: &'tcx [hir::Ty<'tcx>],
@@ -2001,7 +1707,7 @@ fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime)
         self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
         debug!(
             node = ?self.tcx.hir().node_to_string(lifetime_ref.hir_id),
index eb727debc91bb558cc3ff4bea34771fe13dcb4f5..a15a0c298a9522940402fda5716bbe39fdeb0933 100644 (file)
@@ -11,6 +11,7 @@
 #![feature(drain_filter)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
@@ -57,7 +58,6 @@
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
 use std::{cmp, fmt, ptr};
-use tracing::debug;
 
 use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
 use imports::{Import, ImportKind, ImportResolver, NameResolution};
@@ -107,7 +107,6 @@ enum Scope<'a> {
     // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
     // lint if it should be reported.
     Module(Module<'a>, Option<NodeId>),
-    RegisteredAttrs,
     MacroUsePrelude,
     BuiltinAttrs,
     ExternPrelude,
@@ -975,7 +974,6 @@ pub struct Resolver<'a> {
     /// A small map keeping true kinds of built-in macros that appear to be fn-like on
     /// the surface (`macro` items in libcore), but are actually attributes or derives.
     builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>,
-    registered_attrs: FxHashSet<Ident>,
     registered_tools: RegisteredTools,
     macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>,
     macro_map: FxHashMap<DefId, MacroData>,
@@ -1252,8 +1250,7 @@ pub fn new(
             }
         }
 
-        let (registered_attrs, registered_tools) =
-            macros::registered_attrs_and_tools(session, &krate.attrs);
+        let registered_tools = macros::registered_tools(session, &krate.attrs);
 
         let features = session.features_untracked();
 
@@ -1318,7 +1315,6 @@ pub fn new(
             macro_names: FxHashSet::default(),
             builtin_macros: Default::default(),
             builtin_macro_kinds: Default::default(),
-            registered_attrs,
             registered_tools,
             macro_use_prelude: FxHashMap::default(),
             macro_map: FxHashMap::default(),
@@ -1994,7 +1990,7 @@ pub fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> {
                         _ => panic!("invalid arg index"),
                     }
                 }
-                // Cache the lookup to avoid parsing attributes for an iterm multiple times.
+                // Cache the lookup to avoid parsing attributes for an item multiple times.
                 self.legacy_const_generic_args.insert(def_id, Some(ret.clone()));
                 return Some(ret);
             }
@@ -2024,6 +2020,24 @@ fn resolve_main(&mut self) {
         }
         self.main_def = Some(MainDefinition { res, is_import, span });
     }
+
+    // Items that go to reexport table encoded to metadata and visible through it to other crates.
+    fn is_reexport(&self, binding: &NameBinding<'a>) -> Option<def::Res<!>> {
+        // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules`
+        // into the crate root to actual `NameBindingKind::Import`.
+        if binding.is_import()
+            || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true))
+        {
+            let res = binding.res().expect_non_local();
+            // Ambiguous imports are treated as errors at this point and are
+            // not exposed to other crates (see #36837 for more details).
+            if res != def::Res::Err && !binding.is_ambiguity() {
+                return Some(res);
+            }
+        }
+
+        return None;
+    }
 }
 
 fn names_to_string(names: &[Symbol]) -> String {
index 070fb9c721b401b1287fde73e37972e04e38ea97..dafa10e9e0026ff4ad4c32fc8f511a1bf73b8f2e 100644 (file)
@@ -112,47 +112,32 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
     }
 }
 
-/// The code common between processing `#![register_tool]` and `#![register_attr]`.
-fn registered_idents(
-    sess: &Session,
-    attrs: &[ast::Attribute],
-    attr_name: Symbol,
-    descr: &str,
-) -> FxHashSet<Ident> {
-    let mut registered = FxHashSet::default();
-    for attr in sess.filter_by_name(attrs, attr_name) {
+pub(crate) fn registered_tools(sess: &Session, attrs: &[ast::Attribute]) -> FxHashSet<Ident> {
+    let mut registered_tools = FxHashSet::default();
+    for attr in sess.filter_by_name(attrs, sym::register_tool) {
         for nested_meta in attr.meta_item_list().unwrap_or_default() {
             match nested_meta.ident() {
                 Some(ident) => {
-                    if let Some(old_ident) = registered.replace(ident) {
-                        let msg = format!("{} `{}` was already registered", descr, ident);
+                    if let Some(old_ident) = registered_tools.replace(ident) {
+                        let msg = format!("{} `{}` was already registered", "tool", ident);
                         sess.struct_span_err(ident.span, &msg)
                             .span_label(old_ident.span, "already registered here")
                             .emit();
                     }
                 }
                 None => {
-                    let msg = format!("`{}` only accepts identifiers", attr_name);
+                    let msg = format!("`{}` only accepts identifiers", sym::register_tool);
                     let span = nested_meta.span();
                     sess.struct_span_err(span, &msg).span_label(span, "not an identifier").emit();
                 }
             }
         }
     }
-    registered
-}
-
-pub(crate) fn registered_attrs_and_tools(
-    sess: &Session,
-    attrs: &[ast::Attribute],
-) -> (FxHashSet<Ident>, FxHashSet<Ident>) {
-    let registered_attrs = registered_idents(sess, attrs, sym::register_attr, "attribute");
-    let mut registered_tools = registered_idents(sess, attrs, sym::register_tool, "tool");
     // We implicitly add `rustfmt` and `clippy` to known tools,
     // but it's not an error to register them explicitly.
     let predefined_tools = [sym::clippy, sym::rustfmt];
     registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span));
-    (registered_attrs, registered_tools)
+    registered_tools
 }
 
 // Some feature gates for inner attributes are reported as lints for backward compatibility.
@@ -456,7 +441,7 @@ fn cfg_accessible(
                 }
                 PathResult::Indeterminate => indeterminate = true,
                 // We can only be sure that a path doesn't exist after having tested all the
-                // posibilities, only at that time we can return false.
+                // possibilities, only at that time we can return false.
                 PathResult::Failed { .. } => {}
                 PathResult::Module(_) => panic!("unexpected path resolution"),
             }
index e2e0e1f5b300ad345ef4bf9837bab4eb49c8b29a..ac6c3663b63762d134e8bb21a6567724a08dd022 100644 (file)
@@ -44,8 +44,6 @@
     RefKind, Relation, RelationKind, SpanData,
 };
 
-use tracing::{debug, error};
-
 #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5213
 macro_rules! down_cast_data {
     ($id:ident, $kind:ident, $sp:expr) => {
index 619e083d89ad398b1991ecbf49e808e37409321a..16af53385104646aab85c1876aaf6e4f07b3c1ee 100644 (file)
@@ -7,6 +7,9 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
+#[macro_use]
+extern crate tracing;
+
 mod dump_visitor;
 mod dumper;
 #[macro_use]
@@ -49,8 +52,6 @@
     RefKind, Relation, RelationKind, SpanData,
 };
 
-use tracing::{debug, error, info};
-
 pub struct SaveContext<'tcx> {
     tcx: TyCtxt<'tcx>,
     maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
index dbc5c15195c86128511be6425f123523f69398e1..3b0b3144f2cd7d924fb0e4c3019b4c6654b8f0e0 100644 (file)
@@ -6,6 +6,7 @@ edition = "2021"
 [dependencies]
 indexmap = "1.9.1"
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+thin-vec = "0.2.8"
 
 [dev-dependencies]
 rustc_macros = { path = "../rustc_macros" }
index 5e53f0b104dfc6f398bb7f5670758a3f7cd3adc4..8f8c504117cc1c795f0326c561690c65557eb049 100644 (file)
@@ -1,13 +1,12 @@
 //! Implementations of serialization for structures found in liballoc
 
-use std::hash::{BuildHasher, Hash};
-
 use crate::{Decodable, Decoder, Encodable, Encoder};
+use smallvec::{Array, SmallVec};
 use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, LinkedList, VecDeque};
+use std::hash::{BuildHasher, Hash};
 use std::rc::Rc;
 use std::sync::Arc;
-
-use smallvec::{Array, SmallVec};
+use thin_vec::ThinVec;
 
 impl<S: Encoder, A: Array<Item: Encodable<S>>> Encodable<S> for SmallVec<A> {
     fn encode(&self, s: &mut S) {
@@ -23,6 +22,19 @@ fn decode(d: &mut D) -> SmallVec<A> {
     }
 }
 
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for ThinVec<T> {
+    fn encode(&self, s: &mut S) {
+        self.as_slice().encode(s);
+    }
+}
+
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for ThinVec<T> {
+    fn decode(d: &mut D) -> ThinVec<T> {
+        let len = d.read_usize();
+        (0..len).map(|_| Decodable::decode(d)).collect()
+    }
+}
+
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for LinkedList<T> {
     fn encode(&self, s: &mut S) {
         s.emit_usize(self.len());
index dd64e8ab71e7be2af29740c031aeb49b9208927d..2336d99363fd3d8ed639b61d96d9891dcb293439 100644 (file)
@@ -2,10 +2,14 @@
 //! compilation. This is used for incremental compilation tests and debug
 //! output.
 
+use crate::errors::{CguNotRecorded, IncorrectCguReuseType};
+use crate::Session;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
 use rustc_span::{Span, Symbol};
+use std::borrow::Cow;
+use std::fmt::{self};
 use std::sync::{Arc, Mutex};
-use tracing::debug;
 
 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
 pub enum CguReuse {
@@ -14,6 +18,22 @@ pub enum CguReuse {
     PostLto,
 }
 
+impl fmt::Display for CguReuse {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            CguReuse::No => write!(f, "No"),
+            CguReuse::PreLto => write!(f, "PreLto "),
+            CguReuse::PostLto => write!(f, "PostLto "),
+        }
+    }
+}
+
+impl IntoDiagnosticArg for CguReuse {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum ComparisonKind {
     Exact,
@@ -84,7 +104,7 @@ pub fn set_expectation(
         }
     }
 
-    pub fn check_expected_reuse(&self, diag: &rustc_errors::Handler) {
+    pub fn check_expected_reuse(&self, sess: &Session) {
         if let Some(ref data) = self.data {
             let data = data.lock().unwrap();
 
@@ -98,19 +118,17 @@ pub fn check_expected_reuse(&self, diag: &rustc_errors::Handler) {
                     };
 
                     if error {
-                        let at_least = if at_least { "at least " } else { "" };
-                        let msg = format!(
-                            "CGU-reuse for `{cgu_user_name}` is `{actual_reuse:?}` but \
-                                           should be {at_least}`{expected_reuse:?}`"
-                        );
-                        diag.span_err(error_span.0, &msg);
+                        let at_least = if at_least { 1 } else { 0 };
+                        IncorrectCguReuseType {
+                            span: error_span.0,
+                            cgu_user_name: &cgu_user_name,
+                            actual_reuse,
+                            expected_reuse,
+                            at_least,
+                        };
                     }
                 } else {
-                    let msg = format!(
-                        "CGU-reuse for `{cgu_user_name}` (mangled: `{cgu_name}`) was \
-                                       not recorded"
-                    );
-                    diag.span_fatal(error_span.0, &msg)
+                    sess.emit_fatal(CguNotRecorded { cgu_user_name, cgu_name });
                 }
             }
         }
index 162fc9aa0a6ea622e3202fb47a2fe2f967777ebe..7fa4294e5cf7f5384419eff0d96a63e3cc4bc5e5 100644 (file)
@@ -12,8 +12,8 @@
 
 use rustc_data_structures::stable_hasher::ToStableHashKey;
 use rustc_target::abi::{Align, TargetDataLayout};
-use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
-use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS};
+use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
+use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
 
 use crate::parse::{CrateCheckConfig, CrateConfig};
 use rustc_feature::UnstableFeatures;
@@ -36,6 +36,8 @@
 use std::path::{Path, PathBuf};
 use std::str::{self, FromStr};
 
+pub mod sigpipe;
+
 /// The different settings that the `-C strip` flag can have.
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum Strip {
@@ -798,7 +800,15 @@ pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags
 // The type of entry function, so users can have their own entry functions
 #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
 pub enum EntryFnType {
-    Main,
+    Main {
+        /// Specifies what to do with `SIGPIPE` before calling `fn main()`.
+        ///
+        /// What values that are valid and what they mean must be in sync
+        /// across rustc and libstd, but we don't want it public in libstd,
+        /// so we take a bit of an unusual approach with simple constants
+        /// and an `include!()`.
+        sigpipe: u8,
+    },
     Start,
 }
 
@@ -2379,16 +2389,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         }
     }
 
-    if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
-        && !nightly_options::is_unstable_enabled(matches)
-    {
-        early_error(
-            error_format,
-            "`l4-bender` linker flavor is unstable, `-Z unstable-options` \
-             flag must also be passed to explicitly use it",
-        );
-    }
-
     let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
 
     let cg = cg;
@@ -2530,7 +2530,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio
             ),
         ),
     };
-    tracing::debug!("got unpretty option: {first:?}");
+    debug!("got unpretty option: {first:?}");
     Some(first)
 }
 
diff --git a/compiler/rustc_session/src/config/sigpipe.rs b/compiler/rustc_session/src/config/sigpipe.rs
new file mode 100644 (file)
index 0000000..a5c9411
--- /dev/null
@@ -0,0 +1,22 @@
+//! NOTE: Keep these constants in sync with `library/std/src/sys/unix/mod.rs`!
+
+/// Do not touch `SIGPIPE`. Use whatever the parent process uses.
+#[allow(dead_code)]
+pub const INHERIT: u8 = 1;
+
+/// Change `SIGPIPE` to `SIG_IGN` so that failed writes results in `EPIPE`
+/// that are eventually converted to `ErrorKind::BrokenPipe`.
+#[allow(dead_code)]
+pub const SIG_IGN: u8 = 2;
+
+/// Change `SIGPIPE` to `SIG_DFL` so that the process is killed when trying
+/// to write to a closed pipe. This is usually the desired behavior for CLI
+/// apps that produce textual output that you want to pipe to other programs
+/// such as `head -n 1`.
+#[allow(dead_code)]
+pub const SIG_DFL: u8 = 3;
+
+/// `SIG_IGN` has been the Rust default since 2014. See
+/// <https://github.com/rust-lang/rust/issues/62569>.
+#[allow(dead_code)]
+pub const DEFAULT: u8 = SIG_IGN;
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
new file mode 100644 (file)
index 0000000..7252f17
--- /dev/null
@@ -0,0 +1,45 @@
+use std::num::NonZeroU32;
+
+use crate as rustc_session;
+use crate::cgu_reuse_tracker::CguReuse;
+use rustc_errors::MultiSpan;
+use rustc_macros::SessionDiagnostic;
+use rustc_span::{Span, Symbol};
+
+#[derive(SessionDiagnostic)]
+#[diag(session::incorrect_cgu_reuse_type)]
+pub struct IncorrectCguReuseType<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub cgu_user_name: &'a str,
+    pub actual_reuse: CguReuse,
+    pub expected_reuse: CguReuse,
+    pub at_least: u8,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::cgu_not_recorded)]
+pub struct CguNotRecorded<'a> {
+    pub cgu_user_name: &'a str,
+    pub cgu_name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::feature_gate_error, code = "E0658")]
+pub struct FeatureGateError<'a> {
+    #[primary_span]
+    pub span: MultiSpan,
+    pub explain: &'a str,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[note(session::feature_diagnostic_for_issue)]
+pub struct FeatureDiagnosticForIssue {
+    pub n: NonZeroU32,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[help(session::feature_diagnostic_help)]
+pub struct FeatureDiagnosticHelp {
+    pub feature: Symbol,
+}
index c973e3140cef97b596545cdfb3d536fa6bd6eef1..e8edb38f5038ea1f4c55d949a5dc3558050efbbe 100644 (file)
@@ -7,7 +7,6 @@
 
 use crate::search_paths::{PathKind, SearchPath};
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
-use tracing::debug;
 
 #[derive(Copy, Clone)]
 pub enum FileMatch {
index 0617bd5fae786696dce2598ebe181fbaf0d5fd5e..02d5d33c8d5ba24727b27fec54a3a42bbd511fe4 100644 (file)
@@ -1,4 +1,5 @@
 #![feature(if_let_guard)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(never_type)]
 
 #[macro_use]
 extern crate rustc_macros;
+pub mod errors;
+
+#[macro_use]
+extern crate tracing;
 
 pub mod cgu_reuse_tracker;
 pub mod utils;
index 46bba02537dc7b830f20d03450c307b964c0c301..9f07394b61ab8fc0808ee5397d4bfd7e20b5deec 100644 (file)
@@ -5,7 +5,7 @@
 use crate::search_paths::SearchPath;
 use crate::utils::NativeLib;
 use rustc_errors::LanguageIdentifier;
-use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet};
+use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
 use rustc_target::spec::{
     RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
 };
@@ -382,7 +382,7 @@ mod desc {
         "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
     pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
     pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
-    pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
+    pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
     pub const parse_optimization_fuel: &str = "crate=integer";
     pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
     pub const parse_instrument_coverage: &str =
@@ -763,8 +763,8 @@ pub(crate) fn parse_cfprotection(slot: &mut CFProtection, v: Option<&str>) -> bo
         true
     }
 
-    pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
-        match v.and_then(LinkerFlavor::from_str) {
+    pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavorCli>, v: Option<&str>) -> bool {
+        match v.and_then(LinkerFlavorCli::from_str) {
             Some(lf) => *slot = Some(lf),
             _ => return false,
         }
@@ -1139,7 +1139,7 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         on C toolchain installed in the system"),
     linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
         "system linker to link outputs with"),
-    linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
+    linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED],
         "linker flavor"),
     linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
         parse_linker_plugin_lto, [TRACKED],
index 17866dc6bddcbf2cbb89adf7d1a4df188efa4abe..ebec754dcffb841b063ed5ea0b4415bee8822345 100644 (file)
@@ -2,6 +2,7 @@
 //! It also serves as an input to the parser itself.
 
 use crate::config::CheckCfg;
+use crate::errors::{FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError};
 use crate::lint::{
     builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId,
 };
@@ -11,7 +12,7 @@
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
 use rustc_errors::{
-    error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
+    fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
     DiagnosticMessage, EmissionGuarantee, ErrorGuaranteed, MultiSpan, StashKey,
 };
 use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
@@ -112,7 +113,7 @@ pub fn feature_err_issue<'a>(
             .map(|err| err.cancel());
     }
 
-    let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658));
+    let mut err = sess.create_err(FeatureGateError { span, explain });
     add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
     err
 }
@@ -130,6 +131,8 @@ pub fn feature_warn<'a>(sess: &'a ParseSess, feature: Symbol, span: Span, explai
 ///
 /// This variant allows you to control whether it is a library or language feature.
 /// Almost always, you want to use this for a language feature. If so, prefer `feature_warn`.
+#[allow(rustc::diagnostic_outside_of_impl)]
+#[allow(rustc::untranslatable_diagnostic)]
 pub fn feature_warn_issue<'a>(
     sess: &'a ParseSess,
     feature: Symbol,
@@ -172,14 +175,12 @@ pub fn add_feature_diagnostics_for_issue<'a>(
     issue: GateIssue,
 ) {
     if let Some(n) = find_feature_issue(feature, issue) {
-        err.note(&format!(
-            "see issue #{n} <https://github.com/rust-lang/rust/issues/{n}> for more information"
-        ));
+        err.subdiagnostic(FeatureDiagnosticForIssue { n });
     }
 
     // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
     if sess.unstable_features.is_nightly_build() {
-        err.help(&format!("add `#![feature({feature})]` to the crate attributes to enable"));
+        err.subdiagnostic(FeatureDiagnosticHelp { feature });
     }
 }
 
@@ -372,6 +373,8 @@ pub fn emit_fatal<'a>(&'a self, fatal: impl SessionDiagnostic<'a, !>) -> ! {
     }
 
     #[rustc_lint_diagnostics]
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    #[allow(rustc::untranslatable_diagnostic)]
     pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -380,16 +383,22 @@ pub fn struct_err(
     }
 
     #[rustc_lint_diagnostics]
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    #[allow(rustc::untranslatable_diagnostic)]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.span_diagnostic.struct_warn(msg)
     }
 
     #[rustc_lint_diagnostics]
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    #[allow(rustc::untranslatable_diagnostic)]
     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
         self.span_diagnostic.struct_fatal(msg)
     }
 
     #[rustc_lint_diagnostics]
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    #[allow(rustc::untranslatable_diagnostic)]
     pub fn struct_diagnostic<G: EmissionGuarantee>(
         &self,
         msg: impl Into<DiagnosticMessage>,
index ec5e5170d359494fbeae05002849ef132dd91c1d..a49af23be2316d7ad1a839bd27d115522d3a765e 100644 (file)
@@ -110,6 +110,12 @@ fn mul(self, rhs: usize) -> Self::Output {
     }
 }
 
+impl rustc_errors::IntoDiagnosticArg for Limit {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        self.to_string().into_diagnostic_arg()
+    }
+}
+
 #[derive(Clone, Copy, Debug, HashStable_Generic)]
 pub struct Limits {
     /// The maximum recursion limit for potentially infinitely recursive
index e169d3c7cfb7c2553d583f7686c30a9e73383798..e8ddb4ed17a3e6da5af4e922736fa11dbe4c029f 100644 (file)
@@ -41,7 +41,6 @@
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::fmt;
 use std::hash::Hash;
-use tracing::*;
 
 /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
index 860af7fe93a077959f1377c70d642af5e8709a9e..34e2e92bdfce1efa6fc203f15245ac5d76104a04 100644 (file)
@@ -76,8 +76,6 @@
 use sha1::Sha1;
 use sha2::Sha256;
 
-use tracing::debug;
-
 #[cfg(test)]
 mod tests;
 
index a32cabab4c407281a0190e9dba473a863086b8bf..4d94c92d3f2b182ce8521d059210527bf784d62d 100644 (file)
@@ -23,7 +23,6 @@
 
 use std::fs;
 use std::io;
-use tracing::debug;
 
 #[cfg(test)]
 mod tests;
@@ -1060,13 +1059,13 @@ pub fn map_prefix(&self, path: PathBuf) -> (PathBuf, bool) {
 
         return remap_path_prefix(&self.mapping, path);
 
-        #[instrument(level = "debug", skip(mapping))]
+        #[instrument(level = "debug", skip(mapping), ret)]
         fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf, bool) {
             // NOTE: We are iterating over the mapping entries from last to first
             //       because entries specified later on the command line should
             //       take precedence.
             for &(ref from, ref to) in mapping.iter().rev() {
-                debug!("Trying to apply {:?} => {:?}", from, to);
+                debug!("Trying to apply {from:?} => {to:?}");
 
                 if let Ok(rest) = path.strip_prefix(from) {
                     let remapped = if rest.as_os_str().is_empty() {
@@ -1080,15 +1079,15 @@ fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf,
                     } else {
                         to.join(rest)
                     };
-                    debug!("Match - remapped {:?} => {:?}", path, remapped);
+                    debug!("Match - remapped");
 
                     return (remapped, true);
                 } else {
-                    debug!("No match - prefix {:?} does not match {:?}", from, path);
+                    debug!("No match - prefix {from:?} does not match");
                 }
             }
 
-            debug!("Path {:?} was not remapped", path);
+            debug!("not remapped");
             (path, false)
         }
     }
index 1b47d11f6f87d37380165556c5eaef555b2135eb..64b919587e80d96b438744570b0b5e36febe6690 100644 (file)
         BTreeSet,
         BinaryHeap,
         Borrow,
+        BorrowMut,
         Break,
         C,
         CStr,
         LinkedList,
         LintPass,
         Mutex,
+        MutexGuard,
         N,
         NonZeroI128,
         NonZeroI16,
         Rust,
         RustcDecodable,
         RustcEncodable,
+        RwLockReadGuard,
+        RwLockWriteGuard,
         Send,
         SeqCst,
         SessionDiagnostic,
         infer_outlives_requirements,
         infer_static_outlives_requirements,
         inherent_associated_types,
+        inherit,
         inlateout,
         inline,
         inline_const,
         rust_eh_unregister_frames,
         rust_oom,
         rustc,
+        rustc_access_level,
         rustc_allocator,
         rustc_allocator_nounwind,
         rustc_allocator_zeroed,
         should_panic,
         shr,
         shr_assign,
+        sig_dfl,
+        sig_ign,
         simd,
         simd_add,
         simd_and,
         unit,
         universal_impl_trait,
         unix,
+        unix_sigpipe,
         unlikely,
         unmarked_api,
         unpin,
index b104a40c231150fb3802ac03c127ace56da0f27b..3db05225722e71aad54fad9c2e6d53d288992353 100644 (file)
@@ -18,3 +18,5 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_target = { path = "../rustc_target" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_session = { path = "../rustc_session" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs
new file mode 100644 (file)
index 0000000..2429973
--- /dev/null
@@ -0,0 +1,36 @@
+//! Errors emitted by symbol_mangling.
+
+use rustc_macros::SessionDiagnostic;
+use rustc_span::Span;
+
+#[derive(SessionDiagnostic)]
+#[diag(symbol_mangling::invalid_symbol_name)]
+pub struct InvalidSymbolName {
+    #[primary_span]
+    pub span: Span,
+    pub mangled_formatted: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(symbol_mangling::invalid_trait_item)]
+pub struct InvalidTraitItem {
+    #[primary_span]
+    pub span: Span,
+    pub demangling_formatted: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(symbol_mangling::alt_invalid_trait_item)]
+pub struct AltInvalidTraitItem {
+    #[primary_span]
+    pub span: Span,
+    pub alt_demangling_formatted: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(symbol_mangling::invalid_def_path)]
+pub struct InvalidDefPath {
+    #[primary_span]
+    pub span: Span,
+    pub def_path: String,
+}
index 9241fd82c745fde4a857c5598faaba111c2edd34..46c5fe78ffbf65697085e5bcd7874ed70e50595a 100644 (file)
@@ -6,8 +6,6 @@
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitable};
 use rustc_middle::util::common::record_time;
 
-use tracing::debug;
-
 use std::fmt::{self, Write};
 use std::mem::{self, discriminant};
 
index 5fc992023caa04121a440bf26b5414bb9e25288e..62f44a48032efd93301b704bf538bdea53813c8f 100644 (file)
 #![feature(never_type)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 
 #[macro_use]
 extern crate rustc_middle;
 
+#[macro_use]
+extern crate tracing;
+
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::{self, Instance, TyCtxt};
 use rustc_session::config::SymbolManglingVersion;
 
-use tracing::debug;
-
 mod legacy;
 mod v0;
 
+pub mod errors;
 pub mod test;
 pub mod typeid;
 
index 7249ce04c155ecac4c357fbd7af61220c096e75a..b1c4cab11eb8e184772f74b8535e329072254381 100644 (file)
@@ -4,6 +4,7 @@
 //! def-path. This is used for unit testing the code that generates
 //! paths etc in all kinds of annoying scenarios.
 
+use crate::errors::{AltInvalidTraitItem, InvalidDefPath, InvalidSymbolName, InvalidTraitItem};
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{subst::InternalSubsts, Instance, TyCtxt};
@@ -59,16 +60,27 @@ fn process_attrs(&mut self, def_id: LocalDefId) {
                 tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def_id)),
             );
             let mangled = tcx.symbol_name(instance);
-            tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled));
+            tcx.sess.emit_err(InvalidSymbolName {
+                span: attr.span,
+                mangled_formatted: format!("{mangled}"),
+            });
             if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
-                tcx.sess.span_err(attr.span, &format!("demangling({})", demangling));
-                tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
+                tcx.sess.emit_err(InvalidTraitItem {
+                    span: attr.span,
+                    demangling_formatted: format!("{demangling}"),
+                });
+                tcx.sess.emit_err(AltInvalidTraitItem {
+                    span: attr.span,
+                    alt_demangling_formatted: format!("{:#}", demangling),
+                });
             }
         }
 
         for attr in tcx.get_attrs(def_id.to_def_id(), DEF_PATH) {
-            let path = with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id()));
-            tcx.sess.span_err(attr.span, &format!("def-path({})", path));
+            tcx.sess.emit_err(InvalidDefPath {
+                span: attr.span,
+                def_path: with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id())),
+            });
         }
     }
 }
index 1b7161fbb85c5365aa42aae59836b80b2edba6b7..b301ce68a1ce10ba20b877f904059a91c85299dd 100644 (file)
@@ -18,7 +18,6 @@ pub fn target() -> Target {
             panic_strategy: PanicStrategy::Abort,
             position_independent_executables: true,
             dynamic_linking: true,
-            executables: true,
             relro_level: RelroLevel::Off,
             ..Default::default()
         },
index 2bf83a8782a1273a56eeeb04c4b52548bea9260f..9f3e0bd5ef0e3ac8b74484d418e249f44740abca 100644 (file)
@@ -4,7 +4,6 @@ pub fn opts() -> TargetOptions {
     let mut base = super::linux_base::opts();
     base.os = "android".into();
     base.default_dwarf_version = 2;
-    base.position_independent_executables = true;
     base.has_thread_local = false;
     // This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867
     // for context. (At that time, there was no `-C force-unwind-tables`, so the only solution
index 9bbee88a894cad82a8ab012a26242ba1dfc47b23..2c72bf88a41e8b03b881d8d97e822a7658b2c00e 100644 (file)
@@ -1,40 +1,37 @@
 use std::{borrow::Cow, env};
 
-use crate::spec::{cvs, DebuginfoKind, FramePointer, SplitDebuginfo, TargetOptions};
+use crate::spec::{cvs, DebuginfoKind, FramePointer, SplitDebuginfo, StaticCow, TargetOptions};
 use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor};
 
 fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs {
-    let mut args = LinkArgs::new();
-
-    let platform_name = match abi {
-        "sim" => format!("{}-simulator", os),
-        "macabi" => "mac-catalyst".to_string(),
-        _ => os.to_string(),
+    let platform_name: StaticCow<str> = match abi {
+        "sim" => format!("{}-simulator", os).into(),
+        "macabi" => "mac-catalyst".into(),
+        _ => os.into(),
     };
 
-    let platform_version = match os.as_ref() {
+    let platform_version: StaticCow<str> = match os.as_ref() {
         "ios" => ios_lld_platform_version(),
         "tvos" => tvos_lld_platform_version(),
         "watchos" => watchos_lld_platform_version(),
         "macos" => macos_lld_platform_version(arch),
         _ => unreachable!(),
-    };
-
-    if abi != "macabi" {
-        args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), arch.into()]);
     }
+    .into();
 
-    args.insert(
+    let mut args = TargetOptions::link_args(
         LinkerFlavor::Lld(LldFlavor::Ld64),
-        vec![
-            "-arch".into(),
-            arch.into(),
-            "-platform_version".into(),
-            platform_name.into(),
-            platform_version.clone().into(),
-            platform_version.into(),
-        ],
+        &["-arch", arch, "-platform_version"],
     );
+    // Manually add owned args unsupported by link arg building helpers.
+    args.entry(LinkerFlavor::Lld(LldFlavor::Ld64)).or_default().extend([
+        platform_name,
+        platform_version.clone(),
+        platform_version,
+    ]);
+    if abi != "macabi" {
+        super::add_link_args(&mut args, LinkerFlavor::Gcc, &["-arch", arch]);
+    }
 
     args
 }
@@ -127,7 +124,7 @@ pub fn macos_llvm_target(arch: &str) -> String {
     format!("{}-apple-macosx{}.{}.0", arch, major, minor)
 }
 
-pub fn macos_link_env_remove() -> Vec<Cow<'static, str>> {
+pub fn macos_link_env_remove() -> Vec<StaticCow<str>> {
     let mut env_remove = Vec::with_capacity(2);
     // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which
     // may occur when we're linking a custom build script while targeting iOS for example.
index b4cf2c5ee229496f71f65ba2eebb2af13b208913..f492c3451a4182dcb18dbf991980f5089cd27a39 100644 (file)
@@ -2,6 +2,6 @@
 
 pub fn target() -> Target {
     let mut target = wasm32_unknown_emscripten::target();
-    target.add_post_link_args(LinkerFlavor::Em, &["-sWASM=0", "--memory-init-file", "0"]);
+    target.add_post_link_args(LinkerFlavor::EmCc, &["-sWASM=0", "--memory-init-file", "0"]);
     target
 }
index 1d441e558ddcc257b9c88b16844b24aaf3ec5e97..8cca33cc43b358e1a55cf56f23ce8c2bf5c31f51 100644 (file)
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, RelocModel, Target, TargetOptions};
 
 /// A base target for AVR devices using the GNU toolchain.
 ///
@@ -21,6 +21,7 @@ pub fn target(target_cpu: &'static str, mmcu: &'static str) -> Target {
             late_link_args: TargetOptions::link_args(LinkerFlavor::Gcc, &["-lgcc"]),
             max_atomic_width: Some(0),
             atomic_cas: false,
+            relocation_model: RelocModel::Static,
             ..TargetOptions::default()
         },
     }
index 3c4da6f883d9dab420e3520d582ff68ff12a1ede..baf36587147a690d4ecbeba0066468e4f5af6c2f 100644 (file)
@@ -5,7 +5,7 @@ pub fn opts(endian: Endian) -> TargetOptions {
     TargetOptions {
         allow_asm: true,
         endian,
-        linker_flavor: LinkerFlavor::BpfLinker,
+        linker_flavor: LinkerFlavor::Bpf,
         atomic_cas: false,
         dynamic_linking: true,
         no_builtins: true,
index cc2c78c69fe15f321728e662743d8e00984ef50d..2a24e4459c553c65ceb35feb37d8afb5fc8ba597 100644 (file)
@@ -10,7 +10,6 @@ pub fn target() -> Target {
     base.crt_static_default = false;
     base.has_rpath = true;
     base.linker_is_gnu = false;
-    base.dynamic_linking = true;
 
     base.c_enum_min_bits = 8;
 
index a08756861e5b265167baa9ad8cbc3c1b8d8baba4..b7bc1072bf3280c0b496ce057c09dabef754f47f 100644 (file)
@@ -1,14 +1,15 @@
-use crate::spec::{cvs, LinkerFlavor, PanicStrategy, TargetOptions};
+use crate::spec::{cvs, LinkerFlavor, PanicStrategy, RelocModel, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
         os: "l4re".into(),
         env: "uclibc".into(),
-        linker_flavor: LinkerFlavor::L4Bender,
+        linker_flavor: LinkerFlavor::Ld,
         panic_strategy: PanicStrategy::Abort,
         linker: Some("l4-bender".into()),
         linker_is_gnu: false,
         families: cvs!["unix"],
+        relocation_model: RelocModel::Static,
         ..Default::default()
     }
 }
index 8d00129b1b1dc5c23357a30e7012cdbf889a04ba..47eb5fc6a1dcbc6d5beac04d65a6fae9d2709b49 100644 (file)
 
 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
 pub enum LinkerFlavor {
-    Em,
     Gcc,
-    L4Bender,
     Ld,
+    Lld(LldFlavor),
     Msvc,
+    EmCc,
+    Bpf,
+    Ptx,
+}
+
+#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
+pub enum LinkerFlavorCli {
+    Gcc,
+    Ld,
     Lld(LldFlavor),
-    PtxLinker,
+    Msvc,
+    Em,
     BpfLinker,
+    PtxLinker,
 }
 
 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
@@ -137,19 +147,40 @@ fn to_json(&self) -> Json {
     }
 }
 
-impl ToJson for LinkerFlavor {
-    fn to_json(&self) -> Json {
-        self.desc().to_json()
+impl LinkerFlavor {
+    pub fn from_cli(cli: LinkerFlavorCli) -> LinkerFlavor {
+        match cli {
+            LinkerFlavorCli::Gcc => LinkerFlavor::Gcc,
+            LinkerFlavorCli::Ld => LinkerFlavor::Ld,
+            LinkerFlavorCli::Lld(lld_flavor) => LinkerFlavor::Lld(lld_flavor),
+            LinkerFlavorCli::Msvc => LinkerFlavor::Msvc,
+            LinkerFlavorCli::Em => LinkerFlavor::EmCc,
+            LinkerFlavorCli::BpfLinker => LinkerFlavor::Bpf,
+            LinkerFlavorCli::PtxLinker => LinkerFlavor::Ptx,
+        }
+    }
+
+    fn to_cli(self) -> LinkerFlavorCli {
+        match self {
+            LinkerFlavor::Gcc => LinkerFlavorCli::Gcc,
+            LinkerFlavor::Ld => LinkerFlavorCli::Ld,
+            LinkerFlavor::Lld(lld_flavor) => LinkerFlavorCli::Lld(lld_flavor),
+            LinkerFlavor::Msvc => LinkerFlavorCli::Msvc,
+            LinkerFlavor::EmCc => LinkerFlavorCli::Em,
+            LinkerFlavor::Bpf => LinkerFlavorCli::BpfLinker,
+            LinkerFlavor::Ptx => LinkerFlavorCli::PtxLinker,
+        }
     }
 }
-macro_rules! flavor_mappings {
-    ($((($($flavor:tt)*), $string:expr),)*) => (
-        impl LinkerFlavor {
+
+macro_rules! linker_flavor_cli_impls {
+    ($(($($flavor:tt)*) $string:literal)*) => (
+        impl LinkerFlavorCli {
             pub const fn one_of() -> &'static str {
                 concat!("one of: ", $($string, " ",)*)
             }
 
-            pub fn from_str(s: &str) -> Option<Self> {
+            pub fn from_str(s: &str) -> Option<LinkerFlavorCli> {
                 Some(match s {
                     $($string => $($flavor)*,)*
                     _ => return None,
@@ -165,18 +196,23 @@ pub fn desc(&self) -> &str {
     )
 }
 
-flavor_mappings! {
-    ((LinkerFlavor::Em), "em"),
-    ((LinkerFlavor::Gcc), "gcc"),
-    ((LinkerFlavor::L4Bender), "l4-bender"),
-    ((LinkerFlavor::Ld), "ld"),
-    ((LinkerFlavor::Msvc), "msvc"),
-    ((LinkerFlavor::PtxLinker), "ptx-linker"),
-    ((LinkerFlavor::BpfLinker), "bpf-linker"),
-    ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"),
-    ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"),
-    ((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"),
-    ((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"),
+linker_flavor_cli_impls! {
+    (LinkerFlavorCli::Gcc) "gcc"
+    (LinkerFlavorCli::Ld) "ld"
+    (LinkerFlavorCli::Lld(LldFlavor::Ld)) "ld.lld"
+    (LinkerFlavorCli::Lld(LldFlavor::Ld64)) "ld64.lld"
+    (LinkerFlavorCli::Lld(LldFlavor::Link)) "lld-link"
+    (LinkerFlavorCli::Lld(LldFlavor::Wasm)) "wasm-ld"
+    (LinkerFlavorCli::Msvc) "msvc"
+    (LinkerFlavorCli::Em) "em"
+    (LinkerFlavorCli::BpfLinker) "bpf-linker"
+    (LinkerFlavorCli::PtxLinker) "ptx-linker"
+}
+
+impl ToJson for LinkerFlavorCli {
+    fn to_json(&self) -> Json {
+        self.desc().to_json()
+    }
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)]
@@ -467,6 +503,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<StaticCow<str>>>;
+pub type LinkArgsCli = BTreeMap<LinkerFlavorCli, Vec<StaticCow<str>>>;
 
 /// Which kind of debuginfo does the target use?
 ///
@@ -837,15 +874,15 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 macro_rules! supported_targets {
-    ( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
+    ( $(($triple:literal, $module:ident ),)+ ) => {
         $(mod $module;)+
 
         /// List of supported targets
-        pub const TARGETS: &[&str] = &[$($($triple),+),+];
+        pub const TARGETS: &[&str] = &[$($triple),+];
 
         fn load_builtin(target: &str) -> Option<Target> {
             let mut t = match target {
-                $( $($triple)|+ => $module::target(), )+
+                $( $triple => $module::target(), )+
                 _ => return None,
             };
             t.is_builtin = true;
@@ -861,7 +898,7 @@ mod tests {
             $(
                 #[test] // `#[test]`
                 fn $module() {
-                    tests_impl::test_target(super::$module::target());
+                    tests_impl::test_target(super::$module::target(), $triple);
                 }
             )+
         }
@@ -944,9 +981,11 @@ fn $module() {
 
     ("aarch64-unknown-openbsd", aarch64_unknown_openbsd),
     ("i686-unknown-openbsd", i686_unknown_openbsd),
+    ("powerpc-unknown-openbsd", powerpc_unknown_openbsd),
+    ("powerpc64-unknown-openbsd", powerpc64_unknown_openbsd),
+    ("riscv64gc-unknown-openbsd", riscv64gc_unknown_openbsd),
     ("sparc64-unknown-openbsd", sparc64_unknown_openbsd),
     ("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
-    ("powerpc-unknown-openbsd", powerpc_unknown_openbsd),
 
     ("aarch64-unknown-netbsd", aarch64_unknown_netbsd),
     ("armv6-unknown-netbsd-eabihf", armv6_unknown_netbsd_eabihf),
@@ -1208,19 +1247,21 @@ pub struct TargetOptions {
     pub abi: StaticCow<str>,
     /// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown".
     pub vendor: StaticCow<str>,
-    /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
-    /// on the command line. Defaults to `LinkerFlavor::Gcc`.
-    pub linker_flavor: LinkerFlavor,
 
     /// Linker to invoke
     pub linker: Option<StaticCow<str>>,
-
+    /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
+    /// on the command line. Defaults to `LinkerFlavor::Gcc`.
+    pub linker_flavor: LinkerFlavor,
+    linker_flavor_json: LinkerFlavorCli,
     /// LLD flavor used if `lld` (or `rust-lld`) is specified as a linker
     /// without clarifying its flavor in any way.
+    /// FIXME: Merge this into `LinkerFlavor`.
     pub lld_flavor: LldFlavor,
+    /// Whether the linker support GNU-like arguments such as -O. Defaults to true.
+    /// FIXME: Merge this into `LinkerFlavor`.
+    pub linker_is_gnu: bool,
 
-    /// Linker arguments that are passed *before* any user-defined libraries.
-    pub pre_link_args: LinkArgs,
     /// Objects to link before and after all other object code.
     pub pre_link_objects: CrtObjects,
     pub post_link_objects: CrtObjects,
@@ -1229,24 +1270,31 @@ pub struct TargetOptions {
     pub post_link_objects_self_contained: CrtObjects,
     pub link_self_contained: LinkSelfContainedDefault,
 
+    /// Linker arguments that are passed *before* any user-defined libraries.
+    pub pre_link_args: LinkArgs,
+    pre_link_args_json: LinkArgsCli,
     /// Linker arguments that are unconditionally passed after any
     /// user-defined but before post-link objects. Standard platform
     /// libraries that should be always be linked to, usually go here.
     pub late_link_args: LinkArgs,
+    late_link_args_json: LinkArgsCli,
     /// Linker arguments used in addition to `late_link_args` if at least one
     /// Rust dependency is dynamically linked.
     pub late_link_args_dynamic: LinkArgs,
+    late_link_args_dynamic_json: LinkArgsCli,
     /// Linker arguments used in addition to `late_link_args` if all Rust
     /// dependencies are statically linked.
     pub late_link_args_static: LinkArgs,
+    late_link_args_static_json: LinkArgsCli,
     /// Linker arguments that are unconditionally passed *after* any
     /// user-defined libraries.
     pub post_link_args: LinkArgs,
+    post_link_args_json: LinkArgsCli,
+
     /// Optional link script applied to `dylib` and `executable` crate types.
     /// This is a string containing the script, not a path. Can only be applied
     /// to linkers where `linker_is_gnu` is true.
     pub link_script: Option<StaticCow<str>>,
-
     /// Environment variables to be set for the linker invocation.
     pub link_env: StaticCow<[(StaticCow<str>, StaticCow<str>)]>,
     /// Environment variables to be removed for the linker invocation.
@@ -1331,8 +1379,6 @@ pub struct TargetOptions {
     /// Default supported version of DWARF on this platform.
     /// Useful because some platforms (osx, bsd) only want up to DWARF2.
     pub default_dwarf_version: u32,
-    /// Whether the linker support GNU-like arguments such as -O. Defaults to true.
-    pub linker_is_gnu: bool,
     /// The MinGW toolchain has a known issue that prevents it from correctly
     /// handling COFF object files with more than 2<sup>15</sup> sections. Since each weak
     /// symbol needs its own COMDAT section, weak linkage implies a large
@@ -1526,15 +1572,11 @@ fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'stati
     match flavor {
         LinkerFlavor::Ld => insert(LinkerFlavor::Lld(LldFlavor::Ld)),
         LinkerFlavor::Msvc => insert(LinkerFlavor::Lld(LldFlavor::Link)),
-        LinkerFlavor::Lld(LldFlavor::Wasm) => {}
+        LinkerFlavor::Lld(LldFlavor::Ld64) | LinkerFlavor::Lld(LldFlavor::Wasm) => {}
         LinkerFlavor::Lld(lld_flavor) => {
             panic!("add_link_args: use non-LLD flavor for {:?}", lld_flavor)
         }
-        LinkerFlavor::Gcc
-        | LinkerFlavor::Em
-        | LinkerFlavor::L4Bender
-        | LinkerFlavor::BpfLinker
-        | LinkerFlavor::PtxLinker => {}
+        LinkerFlavor::Gcc | LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Ptx => {}
     }
 }
 
@@ -1552,6 +1594,36 @@ fn add_pre_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) {
     fn add_post_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) {
         add_link_args(&mut self.post_link_args, flavor, args);
     }
+
+    fn update_from_cli(&mut self) {
+        self.linker_flavor = LinkerFlavor::from_cli(self.linker_flavor_json);
+        for (args, args_json) in [
+            (&mut self.pre_link_args, &self.pre_link_args_json),
+            (&mut self.late_link_args, &self.late_link_args_json),
+            (&mut self.late_link_args_dynamic, &self.late_link_args_dynamic_json),
+            (&mut self.late_link_args_static, &self.late_link_args_static_json),
+            (&mut self.post_link_args, &self.post_link_args_json),
+        ] {
+            *args = args_json
+                .iter()
+                .map(|(flavor, args)| (LinkerFlavor::from_cli(*flavor), args.clone()))
+                .collect();
+        }
+    }
+
+    fn update_to_cli(&mut self) {
+        self.linker_flavor_json = self.linker_flavor.to_cli();
+        for (args, args_json) in [
+            (&self.pre_link_args, &mut self.pre_link_args_json),
+            (&self.late_link_args, &mut self.late_link_args_json),
+            (&self.late_link_args_dynamic, &mut self.late_link_args_dynamic_json),
+            (&self.late_link_args_static, &mut self.late_link_args_static_json),
+            (&self.post_link_args, &mut self.post_link_args_json),
+        ] {
+            *args_json =
+                args.iter().map(|(flavor, args)| (flavor.to_cli(), args.clone())).collect();
+        }
+    }
 }
 
 impl Default for TargetOptions {
@@ -1566,11 +1638,11 @@ fn default() -> TargetOptions {
             env: "".into(),
             abi: "".into(),
             vendor: "unknown".into(),
-            linker_flavor: LinkerFlavor::Gcc,
             linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.into()),
+            linker_flavor: LinkerFlavor::Gcc,
+            linker_flavor_json: LinkerFlavorCli::Gcc,
             lld_flavor: LldFlavor::Ld,
-            pre_link_args: LinkArgs::new(),
-            post_link_args: LinkArgs::new(),
+            linker_is_gnu: true,
             link_script: None,
             asm_args: cvs![],
             cpu: "generic".into(),
@@ -1597,7 +1669,6 @@ fn default() -> TargetOptions {
             is_like_msvc: false,
             is_like_wasm: false,
             default_dwarf_version: 4,
-            linker_is_gnu: true,
             allows_weak_linkage: true,
             has_rpath: false,
             no_default_libraries: true,
@@ -1610,9 +1681,16 @@ fn default() -> TargetOptions {
             pre_link_objects_self_contained: Default::default(),
             post_link_objects_self_contained: Default::default(),
             link_self_contained: LinkSelfContainedDefault::False,
+            pre_link_args: LinkArgs::new(),
+            pre_link_args_json: LinkArgsCli::new(),
             late_link_args: LinkArgs::new(),
+            late_link_args_json: LinkArgsCli::new(),
             late_link_args_dynamic: LinkArgs::new(),
+            late_link_args_dynamic_json: LinkArgsCli::new(),
             late_link_args_static: LinkArgs::new(),
+            late_link_args_static_json: LinkArgsCli::new(),
+            post_link_args: LinkArgs::new(),
+            post_link_args_json: LinkArgsCli::new(),
             link_env: cvs![],
             link_env_remove: cvs![],
             archive_format: "gnu".into(),
@@ -2017,13 +2095,13 @@ macro_rules! key {
                     Some(Ok(()))
                 })).unwrap_or(Ok(()))
             } );
-            ($key_name:ident, LinkerFlavor) => ( {
-                let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
-                    match LinkerFlavor::from_str(s) {
+            ($key_name:ident = $json_name:expr, LinkerFlavor) => ( {
+                let name = $json_name;
+                obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
+                    match LinkerFlavorCli::from_str(s) {
                         Some(linker_flavor) => base.$key_name = linker_flavor,
                         _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
-                                                      Use {}", s, LinkerFlavor::one_of()))),
+                                                      Use {}", s, LinkerFlavorCli::one_of()))),
                     }
                     Some(Ok(()))
                 })).unwrap_or(Ok(()))
@@ -2104,14 +2182,14 @@ macro_rules! key {
                     base.$key_name = args;
                 }
             } );
-            ($key_name:ident, link_args) => ( {
-                let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(val) = obj.remove(&name) {
+            ($key_name:ident = $json_name:expr, link_args) => ( {
+                let name = $json_name;
+                if let Some(val) = obj.remove(name) {
                     let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
                         JSON object with fields per linker-flavor.", name))?;
-                    let mut args = LinkArgs::new();
+                    let mut args = LinkArgsCli::new();
                     for (k, v) in obj {
-                        let flavor = LinkerFlavor::from_str(&k).ok_or_else(|| {
+                        let flavor = LinkerFlavorCli::from_str(&k).ok_or_else(|| {
                             format!("{}: '{}' is not a valid value for linker-flavor. \
                                      Use 'em', 'gcc', 'ld' or 'msvc'", name, k)
                         })?;
@@ -2197,19 +2275,20 @@ macro_rules! key {
         key!(env);
         key!(abi);
         key!(vendor);
-        key!(linker_flavor, LinkerFlavor)?;
         key!(linker, optional);
+        key!(linker_flavor_json = "linker-flavor", LinkerFlavor)?;
         key!(lld_flavor, LldFlavor)?;
+        key!(linker_is_gnu, bool);
         key!(pre_link_objects = "pre-link-objects", link_objects);
         key!(post_link_objects = "post-link-objects", link_objects);
         key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects);
         key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects);
         key!(link_self_contained = "crt-objects-fallback", link_self_contained)?;
-        key!(pre_link_args, link_args);
-        key!(late_link_args, link_args);
-        key!(late_link_args_dynamic, link_args);
-        key!(late_link_args_static, link_args);
-        key!(post_link_args, link_args);
+        key!(pre_link_args_json = "pre-link-args", link_args);
+        key!(late_link_args_json = "late-link-args", link_args);
+        key!(late_link_args_dynamic_json = "late-link-args-dynamic", link_args);
+        key!(late_link_args_static_json = "late-link-args-static", link_args);
+        key!(post_link_args_json = "post-link-args", link_args);
         key!(link_script, optional);
         key!(link_env, env);
         key!(link_env_remove, list);
@@ -2237,7 +2316,6 @@ macro_rules! key {
         key!(is_like_msvc, bool);
         key!(is_like_wasm, bool);
         key!(default_dwarf_version, u32);
-        key!(linker_is_gnu, bool);
         key!(allows_weak_linkage, bool);
         key!(has_rpath, bool);
         key!(no_default_libraries, bool);
@@ -2294,6 +2372,8 @@ macro_rules! key {
             // This can cause unfortunate ICEs later down the line.
             return Err("may not set is_builtin for targets not built-in".into());
         }
+        base.update_from_cli();
+
         // Each field should have been read using `Json::remove` so any keys remaining are unused.
         let remaining_keys = obj.keys();
         Ok((
@@ -2309,7 +2389,7 @@ pub fn expect_builtin(target_triple: &TargetTriple) -> Target {
                 load_builtin(target_triple).expect("built-in target")
             }
             TargetTriple::TargetJson { .. } => {
-                panic!("built-in targets doens't support target-paths")
+                panic!("built-in targets doesn't support target-paths")
             }
         }
     }
@@ -2385,42 +2465,44 @@ impl ToJson for Target {
     fn to_json(&self) -> Json {
         let mut d = serde_json::Map::new();
         let default: TargetOptions = Default::default();
+        let mut target = self.clone();
+        target.update_to_cli();
 
         macro_rules! target_val {
             ($attr:ident) => {{
                 let name = (stringify!($attr)).replace("_", "-");
-                d.insert(name, self.$attr.to_json());
+                d.insert(name, target.$attr.to_json());
             }};
         }
 
         macro_rules! target_option_val {
             ($attr:ident) => {{
                 let name = (stringify!($attr)).replace("_", "-");
-                if default.$attr != self.$attr {
-                    d.insert(name, self.$attr.to_json());
+                if default.$attr != target.$attr {
+                    d.insert(name, target.$attr.to_json());
                 }
             }};
-            ($attr:ident, $key_name:expr) => {{
-                let name = $key_name;
-                if default.$attr != self.$attr {
-                    d.insert(name.into(), self.$attr.to_json());
+            ($attr:ident, $json_name:expr) => {{
+                let name = $json_name;
+                if default.$attr != target.$attr {
+                    d.insert(name.into(), target.$attr.to_json());
                 }
             }};
-            (link_args - $attr:ident) => {{
-                let name = (stringify!($attr)).replace("_", "-");
-                if default.$attr != self.$attr {
-                    let obj = self
+            (link_args - $attr:ident, $json_name:expr) => {{
+                let name = $json_name;
+                if default.$attr != target.$attr {
+                    let obj = target
                         .$attr
                         .iter()
                         .map(|(k, v)| (k.desc().to_string(), v.clone()))
                         .collect::<BTreeMap<_, _>>();
-                    d.insert(name, obj.to_json());
+                    d.insert(name.to_string(), obj.to_json());
                 }
             }};
             (env - $attr:ident) => {{
                 let name = (stringify!($attr)).replace("_", "-");
-                if default.$attr != self.$attr {
-                    let obj = self
+                if default.$attr != target.$attr {
+                    let obj = target
                         .$attr
                         .iter()
                         .map(|&(ref k, ref v)| format!("{k}={v}"))
@@ -2442,19 +2524,20 @@ macro_rules! target_option_val {
         target_option_val!(env);
         target_option_val!(abi);
         target_option_val!(vendor);
-        target_option_val!(linker_flavor);
         target_option_val!(linker);
+        target_option_val!(linker_flavor_json, "linker-flavor");
         target_option_val!(lld_flavor);
+        target_option_val!(linker_is_gnu);
         target_option_val!(pre_link_objects);
         target_option_val!(post_link_objects);
         target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback");
         target_option_val!(post_link_objects_self_contained, "post-link-objects-fallback");
         target_option_val!(link_self_contained, "crt-objects-fallback");
-        target_option_val!(link_args - pre_link_args);
-        target_option_val!(link_args - late_link_args);
-        target_option_val!(link_args - late_link_args_dynamic);
-        target_option_val!(link_args - late_link_args_static);
-        target_option_val!(link_args - post_link_args);
+        target_option_val!(link_args - pre_link_args_json, "pre-link-args");
+        target_option_val!(link_args - late_link_args_json, "late-link-args");
+        target_option_val!(link_args - late_link_args_dynamic_json, "late-link-args-dynamic");
+        target_option_val!(link_args - late_link_args_static_json, "late-link-args-static");
+        target_option_val!(link_args - post_link_args_json, "post-link-args");
         target_option_val!(link_script);
         target_option_val!(env - link_env);
         target_option_val!(link_env_remove);
@@ -2483,7 +2566,6 @@ macro_rules! target_option_val {
         target_option_val!(is_like_msvc);
         target_option_val!(is_like_wasm);
         target_option_val!(default_dwarf_version);
-        target_option_val!(linker_is_gnu);
         target_option_val!(allows_weak_linkage);
         target_option_val!(has_rpath);
         target_option_val!(no_default_libraries);
index ec9609a2b26a185af568828ad2ba408df2160773..b3cd38a6ec3de7ad1847d054222f202e594a7cd9 100644 (file)
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions};
+use crate::spec::{DebuginfoKind, LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions};
 use std::borrow::Cow;
 
 pub fn opts() -> TargetOptions {
@@ -20,6 +20,7 @@ pub fn opts() -> TargetOptions {
         // where `*.pdb` files show up next to the final artifact.
         split_debuginfo: SplitDebuginfo::Packed,
         supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Packed]),
+        debuginfo_kind: DebuginfoKind::Pdb,
 
         ..Default::default()
     }
index 1c5b68001b957b00cc0b927c014022f3b1c25c95..6ab3a8b7eb5a06f688bc5505f1f0ddb9e6301bb8 100644 (file)
@@ -10,7 +10,7 @@ pub fn target() -> Target {
         options: TargetOptions {
             os: "cuda".into(),
             vendor: "nvidia".into(),
-            linker_flavor: LinkerFlavor::PtxLinker,
+            linker_flavor: LinkerFlavor::Ptx,
             // The linker can be installed from `crates.io`.
             linker: Some("rust-ptx-linker".into()),
             linker_is_gnu: false,
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs
new file mode 100644 (file)
index 0000000..9cb3a67
--- /dev/null
@@ -0,0 +1,17 @@
+use crate::abi::Endian;
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
+
+pub fn target() -> Target {
+    let mut base = super::openbsd_base::opts();
+    base.cpu = "ppc64".into();
+    base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+    base.max_atomic_width = Some(64);
+
+    Target {
+        llvm_target: "powerpc64-unknown-openbsd".into(),
+        pointer_width: 64,
+        data_layout: "E-m:e-i64:64-n32:64".into(),
+        arch: "powerpc64".into(),
+        options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
+    }
+}
index 516b2de37eaa7cc77afb068592b08fd5065f705f..75ac66c276d57c72b454b721c95d252d2280ac1f 100644 (file)
@@ -1,5 +1,5 @@
 use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, RelocModel, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
@@ -15,7 +15,6 @@ pub fn target() -> Target {
         options: TargetOptions {
             endian: Endian::Big,
             features: "+secure-plt".into(),
-            relocation_model: RelocModel::Pic,
             mcount: "_mcount".into(),
             ..base
         },
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_openbsd.rs
new file mode 100644 (file)
index 0000000..cd10f3a
--- /dev/null
@@ -0,0 +1,18 @@
+use crate::spec::{CodeModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "riscv64-unknown-openbsd".into(),
+        pointer_width: 64,
+        data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
+        arch: "riscv64".into(),
+        options: TargetOptions {
+            code_model: Some(CodeModel::Medium),
+            cpu: "generic-rv64".into(),
+            features: "+m,+a,+f,+d,+c".into(),
+            llvm_abiname: "lp64d".into(),
+            max_atomic_width: Some(64),
+            ..super::openbsd_base::opts()
+        },
+    }
+}
index 03e579aee0a96f042c7188a704c10d54cfb608f4..d03f959076de0c0ab5fe7691c1f70daf5756d2ab 100644 (file)
@@ -2,28 +2,31 @@
 use std::assert_matches::assert_matches;
 
 // Test target self-consistency and JSON encoding/decoding roundtrip.
-pub(super) fn test_target(target: Target) {
-    target.check_consistency();
-    assert_eq!(Target::from_json(target.to_json()).map(|(j, _)| j), Ok(target));
+pub(super) fn test_target(mut target: Target, triple: &str) {
+    let recycled_target = Target::from_json(target.to_json()).map(|(j, _)| j);
+    target.update_to_cli();
+    target.check_consistency(triple);
+    assert_eq!(recycled_target, Ok(target));
 }
 
 impl Target {
-    fn check_consistency(&self) {
+    fn check_consistency(&self, triple: &str) {
         assert_eq!(self.is_like_osx, self.vendor == "apple");
         assert_eq!(self.is_like_solaris, self.os == "solaris" || self.os == "illumos");
         assert_eq!(self.is_like_windows, self.os == "windows" || self.os == "uefi");
         assert_eq!(self.is_like_wasm, self.arch == "wasm32" || self.arch == "wasm64");
-        assert!(self.is_like_windows || !self.is_like_msvc);
+        if self.is_like_msvc {
+            assert!(self.is_like_windows);
+        }
 
         // Check that default linker flavor and lld flavor are compatible
         // with some other key properties.
         assert_eq!(self.is_like_osx, matches!(self.lld_flavor, LldFlavor::Ld64));
         assert_eq!(self.is_like_msvc, matches!(self.lld_flavor, LldFlavor::Link));
         assert_eq!(self.is_like_wasm, matches!(self.lld_flavor, LldFlavor::Wasm));
-        assert_eq!(self.os == "l4re", matches!(self.linker_flavor, LinkerFlavor::L4Bender));
-        assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::Em));
-        assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::BpfLinker));
-        assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::PtxLinker));
+        assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::EmCc));
+        assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::Bpf));
+        assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::Ptx));
 
         for args in [
             &self.pre_link_args,
@@ -63,17 +66,14 @@ fn check_consistency(&self) {
                             LinkerFlavor::Lld(LldFlavor::Wasm) | LinkerFlavor::Gcc
                         )
                     }
-                    (LinkerFlavor::L4Bender, LldFlavor::Ld) => {
-                        assert_matches!(flavor, LinkerFlavor::L4Bender)
-                    }
-                    (LinkerFlavor::Em, LldFlavor::Wasm) => {
-                        assert_matches!(flavor, LinkerFlavor::Em)
+                    (LinkerFlavor::EmCc, LldFlavor::Wasm) => {
+                        assert_matches!(flavor, LinkerFlavor::EmCc)
                     }
-                    (LinkerFlavor::BpfLinker, LldFlavor::Ld) => {
-                        assert_matches!(flavor, LinkerFlavor::BpfLinker)
+                    (LinkerFlavor::Bpf, LldFlavor::Ld) => {
+                        assert_matches!(flavor, LinkerFlavor::Bpf)
                     }
-                    (LinkerFlavor::PtxLinker, LldFlavor::Ld) => {
-                        assert_matches!(flavor, LinkerFlavor::PtxLinker)
+                    (LinkerFlavor::Ptx, LldFlavor::Ld) => {
+                        assert_matches!(flavor, LinkerFlavor::Ptx)
                     }
                     flavors => unreachable!("unexpected flavor combination: {:?}", flavors),
                 }
@@ -94,8 +94,9 @@ fn check_consistency(&self) {
                             check_noncc(LinkerFlavor::Ld);
                             check_noncc(LinkerFlavor::Lld(LldFlavor::Ld));
                         }
+                        LldFlavor::Ld64 => check_noncc(LinkerFlavor::Lld(LldFlavor::Ld64)),
                         LldFlavor::Wasm => check_noncc(LinkerFlavor::Lld(LldFlavor::Wasm)),
-                        LldFlavor::Ld64 | LldFlavor::Link => {}
+                        LldFlavor::Link => {}
                     },
                     _ => {}
                 }
@@ -109,20 +110,56 @@ fn check_consistency(&self) {
             );
         }
 
-        assert!(
-            (self.pre_link_objects_self_contained.is_empty()
-                && self.post_link_objects_self_contained.is_empty())
-                || self.link_self_contained != LinkSelfContainedDefault::False
-        );
+        if self.link_self_contained == LinkSelfContainedDefault::False {
+            assert!(
+                self.pre_link_objects_self_contained.is_empty()
+                    && self.post_link_objects_self_contained.is_empty()
+            );
+        }
 
         // If your target really needs to deviate from the rules below,
         // except it and document the reasons.
         // Keep the default "unknown" vendor instead.
         assert_ne!(self.vendor, "");
+        assert_ne!(self.os, "");
         if !self.can_use_os_unknown() {
             // Keep the default "none" for bare metal targets instead.
             assert_ne!(self.os, "unknown");
         }
+
+        // Check dynamic linking stuff
+        // BPF: when targeting user space vms (like rbpf), those can load dynamic libraries.
+        if self.os == "none" && self.arch != "bpf" {
+            assert!(!self.dynamic_linking);
+        }
+        if self.only_cdylib
+            || self.crt_static_allows_dylibs
+            || !self.late_link_args_dynamic.is_empty()
+        {
+            assert!(self.dynamic_linking);
+        }
+        // Apparently PIC was slow on wasm at some point, see comments in wasm_base.rs
+        if self.dynamic_linking && !(self.is_like_wasm && self.os != "emscripten") {
+            assert_eq!(self.relocation_model, RelocModel::Pic);
+        }
+        // PIEs are supported but not enabled by default with linuxkernel target.
+        if self.position_independent_executables && !triple.ends_with("-linuxkernel") {
+            assert_eq!(self.relocation_model, RelocModel::Pic);
+        }
+        if self.relocation_model == RelocModel::Pic {
+            assert!(self.dynamic_linking || self.position_independent_executables);
+        }
+        if self.static_position_independent_executables {
+            assert!(self.position_independent_executables);
+        }
+        if self.position_independent_executables {
+            assert!(self.executables);
+        }
+
+        // Check crt static stuff
+        if self.crt_static_default || self.crt_static_allows_dylibs {
+            assert!(self.crt_static_respected);
+        }
     }
 
     // Add your target to the whitelist if it has `std` library
index aee8eb2e31c7ab4ab0a9483281f0a556b3a4c709..250da03cbd2b656af8fa21df4a369f6a33c82f2d 100644 (file)
@@ -9,7 +9,8 @@
 // the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
 // code runs in the same environment, no process separation is supported.
 
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, StackProbeType, TargetOptions};
+use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy};
+use crate::spec::{RelocModel, StackProbeType, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     let mut base = super::msvc_base::opts();
@@ -46,6 +47,7 @@ pub fn opts() -> TargetOptions {
         stack_probes: StackProbeType::Call,
         singlethread: true,
         linker: Some("rust-lld".into()),
+        relocation_model: RelocModel::Static,
         ..base
     }
 }
index c7e7d22108656ffab3264bc5263cb0a2575e9f12..6f77ef98c015df8c38dc5629d23fa5c496982be8 100644 (file)
@@ -5,13 +5,13 @@ pub fn target() -> Target {
     // Reset flags for non-Em flavors back to empty to satisfy sanity checking tests.
     let pre_link_args = LinkArgs::new();
     let post_link_args = TargetOptions::link_args(
-        LinkerFlavor::Em,
+        LinkerFlavor::EmCc,
         &["-sABORTING_MALLOC=0", "-Wl,--fatal-warnings"],
     );
 
     let opts = TargetOptions {
         os: "emscripten".into(),
-        linker_flavor: LinkerFlavor::Em,
+        linker_flavor: LinkerFlavor::EmCc,
         // emcc emits two files - a .js file to instantiate the wasm and supply platform
         // functionality, and a .wasm file.
         exe_suffix: ".js".into(),
index bae007dc9f3bc0ad21a7bcd0c555cd8a2ea2c298..f30be25497d8a7ef9626658a00d4b7d493eb5d20 100644 (file)
@@ -3,7 +3,7 @@
 pub fn opts() -> TargetOptions {
     // We cannot use `-nodefaultlibs` because compiler-rt has to be passed
     // as a path since it's not added to linker search path by the default.
-    // There were attemts to make it behave like libgcc (so one can just use -l<name>)
+    // There were attempts to make it behave like libgcc (so one can just use -l<name>)
     // but LLVM maintainers rejected it: https://reviews.llvm.org/D51440
     let pre_link_args =
         TargetOptions::link_args(LinkerFlavor::Gcc, &["-nolibc", "--unwindlib=none"]);
index 67282c19541148db7dcd5171e83180c616b2fc8c..21062c337d82522c7920162cfbbbd48ad8e57124 100644 (file)
@@ -1,4 +1,4 @@
-use crate::spec::{cvs, DebuginfoKind, TargetOptions};
+use crate::spec::{cvs, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     let base = super::msvc_base::opts();
@@ -28,7 +28,6 @@ pub fn opts() -> TargetOptions {
         // not ever be possible for us to pass this flag.
         no_default_libraries: false,
         has_thread_local: true,
-        debuginfo_kind: DebuginfoKind::Pdb,
 
         ..base
     }
index 78189a0c0969a3dd14dd1fb4b762246b085a4861..26da7e800114a17994a709771348c6c3585da4d3 100644 (file)
@@ -4,8 +4,6 @@ pub fn target() -> Target {
     let mut base = super::l4re_base::opts();
     base.cpu = "x86-64".into();
     base.max_atomic_width = Some(64);
-    base.crt_static_allows_dylibs = false;
-    base.dynamic_linking = false;
     base.panic_strategy = PanicStrategy::Abort;
 
     Target {
index 809fd642d41143fd12a2df76959972de42d52f80..b9a345127e3724d736c13be060afaae504890c03 100644 (file)
@@ -4,10 +4,8 @@
 // `target-cpu` compiler flags to opt-in more hardware-specific
 // features.
 
-use super::{
-    CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, RelroLevel, StackProbeType,
-    Target, TargetOptions,
-};
+use super::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy};
+use super::{RelroLevel, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let opts = TargetOptions {
@@ -18,7 +16,6 @@ pub fn target() -> Target {
         position_independent_executables: true,
         static_position_independent_executables: true,
         relro_level: RelroLevel::Full,
-        relocation_model: RelocModel::Pic,
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".into()),
         features:
index 8b7e8984a8adbf359b4be7882198932deea4413a..36ab8f3bd8845f6cf6bc754c1432fafccaf365bd 100644 (file)
@@ -1,6 +1,6 @@
+use crate::errors::AutoDerefReachedRecursionLimit;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{self, TraitEngine};
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt};
@@ -222,19 +222,10 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa
         Limit(0) => Limit(2),
         limit => limit * 2,
     };
-    struct_span_err!(
-        tcx.sess,
+    tcx.sess.emit_err(AutoDerefReachedRecursionLimit {
         span,
-        E0055,
-        "reached the recursion limit while auto-dereferencing `{:?}`",
-        ty
-    )
-    .span_label(span, "deref recursion limit reached")
-    .help(&format!(
-        "consider increasing the recursion limit by adding a \
-             `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
+        ty,
         suggested_limit,
-        tcx.crate_name(LOCAL_CRATE),
-    ))
-    .emit();
+        crate_name: tcx.crate_name(LOCAL_CRATE),
+    });
 }
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
new file mode 100644 (file)
index 0000000..81977f2
--- /dev/null
@@ -0,0 +1,102 @@
+use rustc_errors::{fluent, ErrorGuaranteed};
+use rustc_macros::SessionDiagnostic;
+use rustc_middle::ty::{PolyTraitRef, Ty, Unevaluated};
+use rustc_session::{parse::ParseSess, Limit, SessionDiagnostic};
+use rustc_span::{Span, Symbol};
+
+#[derive(SessionDiagnostic)]
+#[diag(trait_selection::dump_vtable_entries)]
+pub struct DumpVTableEntries<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub trait_ref: PolyTraitRef<'a>,
+    pub entries: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(trait_selection::unable_to_construct_constant_value)]
+pub struct UnableToConstructConstantValue<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub unevaluated: Unevaluated<'a>,
+}
+
+#[derive(SessionDiagnostic)]
+#[help]
+#[diag(trait_selection::auto_deref_reached_recursion_limit, code = "E0055")]
+pub struct AutoDerefReachedRecursionLimit<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub ty: Ty<'a>,
+    pub suggested_limit: Limit,
+    pub crate_name: Symbol,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(trait_selection::empty_on_clause_in_rustc_on_unimplemented, code = "E0232")]
+pub struct EmptyOnClauseInOnUnimplemented {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(trait_selection::invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")]
+pub struct InvalidOnClauseInOnUnimplemented {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(trait_selection::no_value_in_rustc_on_unimplemented, code = "E0232")]
+#[note]
+pub struct NoValueInOnUnimplemented {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+pub struct NegativePositiveConflict<'a> {
+    pub impl_span: Span,
+    pub trait_desc: &'a str,
+    pub self_desc: &'a Option<String>,
+    pub negative_impl_span: Result<Span, Symbol>,
+    pub positive_impl_span: Result<Span, Symbol>,
+}
+
+impl SessionDiagnostic<'_> for NegativePositiveConflict<'_> {
+    fn into_diagnostic(
+        self,
+        sess: &ParseSess,
+    ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = sess.struct_err(fluent::trait_selection::negative_positive_conflict);
+        diag.set_arg("trait_desc", self.trait_desc);
+        diag.set_arg(
+            "self_desc",
+            self.self_desc.clone().map_or_else(|| String::from("none"), |ty| ty),
+        );
+        diag.set_span(self.impl_span);
+        diag.code(rustc_errors::error_code!(E0751));
+        match self.negative_impl_span {
+            Ok(span) => {
+                diag.span_label(span, fluent::trait_selection::negative_implementation_here);
+            }
+            Err(cname) => {
+                diag.note(fluent::trait_selection::negative_implementation_in_crate);
+                diag.set_arg("negative_impl_cname", cname.to_string());
+            }
+        }
+        match self.positive_impl_span {
+            Ok(span) => {
+                diag.span_label(span, fluent::trait_selection::positive_implementation_here);
+            }
+            Err(cname) => {
+                diag.note(fluent::trait_selection::positive_implementation_in_crate);
+                diag.set_arg("positive_impl_cname", cname.to_string());
+            }
+        }
+        diag
+    }
+}
index e0dd28bee30b6e5b2ab8ec89c36c5ca13ec8be6b..f039b1fca1817d1069e24d0f489bd659c644b259 100644 (file)
@@ -17,6 +17,7 @@
 #![feature(drain_filter)]
 #![feature(hash_drain_filter)]
 #![cfg_attr(bootstrap, feature(label_break_value))]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(if_let_guard)]
 #![feature(never_type)]
@@ -36,5 +37,6 @@
 extern crate smallvec;
 
 pub mod autoderef;
+pub mod errors;
 pub mod infer;
 pub mod traits;
index 4bab99355012e0792b8e3135040db1be28f11032..1223c7ced7abcb9e04bdaeb1b879ec240092bcf7 100644 (file)
@@ -3,6 +3,7 @@
 
 use super::*;
 
+use crate::errors::UnableToConstructConstantValue;
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::InferCtxt;
 use crate::traits::project::ProjectAndUnifyResult;
@@ -830,8 +831,11 @@ fn evaluate_nested_obligations(
                                 Ok(None) => {
                                     let tcx = self.tcx;
                                     let def_id = unevaluated.def.did;
-                                    let reported = tcx.sess.struct_span_err(tcx.def_span(def_id), &format!("unable to construct a constant value for the unevaluated constant {:?}", unevaluated)).emit();
-
+                                    let reported =
+                                        tcx.sess.emit_err(UnableToConstructConstantValue {
+                                            span: tcx.def_span(def_id),
+                                            unevaluated,
+                                        });
                                     Err(ErrorHandled::Reported(reported))
                                 }
                                 Err(err) => Err(err),
index c0700748c79f9d7df78b0bf21458e92ebd509974..26f8e7d34c6eac056f1b06a4563b0e7c33497906 100644 (file)
@@ -18,7 +18,6 @@
 /// obligations *could be* resolved if we wanted to.
 ///
 /// This also expects that `trait_ref` is fully normalized.
-#[instrument(level = "debug", skip(tcx))]
 pub fn codegen_fulfill_obligation<'tcx>(
     tcx: TyCtxt<'tcx>,
     (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
@@ -74,7 +73,6 @@ pub fn codegen_fulfill_obligation<'tcx>(
         // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
         let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
 
-        debug!("Cache miss: {trait_ref:?} => {impl_source:?}");
         Ok(&*tcx.arena.alloc(impl_source))
     })
 }
index 72533a42d8078dce6949d9d67850eccab50576fa..dba4d4f69dadb519244aa5000cff7ce46657aa3d 100644 (file)
@@ -17,6 +17,7 @@
 
 pub trait TraitEngineExt<'tcx> {
     fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
+    fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self>;
 }
 
 impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
@@ -27,6 +28,14 @@ fn new(tcx: TyCtxt<'tcx>) -> Box<Self> {
             Box::new(FulfillmentContext::new())
         }
     }
+
+    fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self> {
+        if tcx.sess.opts.unstable_opts.chalk {
+            Box::new(ChalkFulfillmentContext::new())
+        } else {
+            Box::new(FulfillmentContext::new_in_snapshot())
+        }
+    }
 }
 
 /// Used if you want to have pleasant experience when dealing
@@ -41,6 +50,10 @@ pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
         Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx.tcx)) }
     }
 
+    pub fn new_in_snapshot(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+        Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new_in_snapshot(infcx.tcx)) }
+    }
+
     pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) {
         self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation);
     }
index e4af7022239b83fa2492b0754ea1688096a76854..99046bd126f937f74d557cb582c8db8d17457305 100644 (file)
@@ -2014,7 +2014,7 @@ fn maybe_report_ambiguity(
         let predicate = self.resolve_vars_if_possible(obligation.predicate);
         let span = obligation.cause.span;
 
-        debug!(?predicate, obligation.cause.code = tracing::field::debug(&obligation.cause.code()));
+        debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
 
         // Ambiguity errors are often caused as fallout from earlier errors.
         // We ignore them if this `infcx` is tainted in some cases below.
index a93f9ec0397d2649400b408a0e0c26cbec9b691a..02adae5bde157f50c086e0b9c3784b1a9d126c0b 100644 (file)
@@ -20,7 +20,7 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::hir::map;
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
@@ -690,13 +690,17 @@ fn suggest_dereferences(
                 real_trait_pred = parent_trait_pred;
             }
 
-            // Skipping binder here, remapping below
-            let real_ty = real_trait_pred.self_ty().skip_binder();
-            if self.can_eq(obligation.param_env, real_ty, arg_ty).is_err() {
+            let real_ty = real_trait_pred.self_ty();
+            // We `erase_late_bound_regions` here because `make_subregion` does not handle
+            // `ReLateBound`, and we don't particularly care about the regions.
+            if self
+                .can_eq(obligation.param_env, self.tcx.erase_late_bound_regions(real_ty), arg_ty)
+                .is_err()
+            {
                 continue;
             }
 
-            if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
+            if let ty::Ref(region, base_ty, mutbl) = *real_ty.skip_binder().kind() {
                 let mut autoderef = Autoderef::new(
                     self,
                     obligation.param_env,
@@ -1585,32 +1589,38 @@ fn report_closure_arg_mismatch(
         expected: ty::PolyTraitRef<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         pub(crate) fn build_fn_sig_ty<'tcx>(
-            tcx: TyCtxt<'tcx>,
+            infcx: &InferCtxt<'_, 'tcx>,
             trait_ref: ty::PolyTraitRef<'tcx>,
         ) -> Ty<'tcx> {
             let inputs = trait_ref.skip_binder().substs.type_at(1);
             let sig = match inputs.kind() {
                 ty::Tuple(inputs)
-                    if tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() =>
+                    if infcx.tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() =>
                 {
-                    tcx.mk_fn_sig(
+                    infcx.tcx.mk_fn_sig(
                         inputs.iter(),
-                        tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))),
+                        infcx.next_ty_var(TypeVariableOrigin {
+                            span: DUMMY_SP,
+                            kind: TypeVariableOriginKind::MiscVariable,
+                        }),
                         false,
                         hir::Unsafety::Normal,
                         abi::Abi::Rust,
                     )
                 }
-                _ => tcx.mk_fn_sig(
+                _ => infcx.tcx.mk_fn_sig(
                     std::iter::once(inputs),
-                    tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))),
+                    infcx.next_ty_var(TypeVariableOrigin {
+                        span: DUMMY_SP,
+                        kind: TypeVariableOriginKind::MiscVariable,
+                    }),
                     false,
                     hir::Unsafety::Normal,
                     abi::Abi::Rust,
                 ),
             };
 
-            tcx.mk_fn_ptr(trait_ref.rebind(sig))
+            infcx.tcx.mk_fn_ptr(trait_ref.rebind(sig))
         }
 
         let argument_kind = match expected.skip_binder().self_ty().kind() {
@@ -1630,11 +1640,10 @@ pub(crate) fn build_fn_sig_ty<'tcx>(
         let found_span = found_span.unwrap_or(span);
         err.span_label(found_span, "found signature defined here");
 
-        let expected = build_fn_sig_ty(self.tcx, expected);
-        let found = build_fn_sig_ty(self.tcx, found);
+        let expected = build_fn_sig_ty(self, expected);
+        let found = build_fn_sig_ty(self, found);
 
-        let (expected_str, found_str) =
-            self.tcx.infer_ctxt().enter(|infcx| infcx.cmp(expected, found));
+        let (expected_str, found_str) = self.cmp(expected, found);
 
         let signature_kind = format!("{argument_kind} signature");
         err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str);
index 556ef466cd11aad35bfb521bcb48e57026c92773..3763a98c488b766c11fc1e863a17e29f1c5c23d2 100644 (file)
@@ -135,7 +135,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
     /// `SomeTrait` or a where-clause that lets us unify `$0` with
     /// something concrete. If this fails, we'll unify `$0` with
     /// `projection_ty` again.
-    #[tracing::instrument(level = "debug", skip(self, infcx, param_env, cause))]
+    #[instrument(level = "debug", skip(self, infcx, param_env, cause))]
     fn normalize_projection_type(
         &mut self,
         infcx: &InferCtxt<'_, 'tcx>,
@@ -597,6 +597,7 @@ fn process_obligation(
         }
     }
 
+    #[inline(never)]
     fn process_backedge<'c, I>(
         &mut self,
         cycle: I,
index e11ea7751aa731e93417895ba681a7f93a265bd2..14e078096783e39239cdb186325910f9df61dd8b 100644 (file)
@@ -23,6 +23,7 @@
 mod util;
 pub mod wf;
 
+use crate::errors::DumpVTableEntries;
 use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::{InferCtxt, TyCtxtInferExt};
 use crate::traits::error_reporting::InferCtxtExt as _;
@@ -763,8 +764,11 @@ fn dump_vtable_entries<'tcx>(
     trait_ref: ty::PolyTraitRef<'tcx>,
     entries: &[VtblEntry<'tcx>],
 ) {
-    let msg = format!("vtable entries for `{}`: {:#?}", trait_ref, entries);
-    tcx.sess.struct_span_err(sp, &msg).emit();
+    tcx.sess.emit_err(DumpVTableEntries {
+        span: sp,
+        trait_ref,
+        entries: format!("{:#?}", entries),
+    });
 }
 
 fn own_existential_vtable_entries<'tcx>(
index 9227bbf011dbfcb2c2d43475778289ed38f2bbf5..3d8840e9e7421b22de38bffe66d9ebb0a4eec556 100644 (file)
@@ -8,6 +8,10 @@
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
+use crate::errors::{
+    EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
+};
+
 #[derive(Clone, Debug)]
 pub struct OnUnimplementedFormatString(Symbol);
 
@@ -35,21 +39,6 @@ pub struct OnUnimplementedNote {
     pub append_const_msg: Option<Option<Symbol>>,
 }
 
-fn parse_error(
-    tcx: TyCtxt<'_>,
-    span: Span,
-    message: &str,
-    label: &str,
-    note: Option<&str>,
-) -> ErrorGuaranteed {
-    let mut diag = struct_span_err!(tcx.sess, span, E0232, "{}", message);
-    diag.span_label(span, label);
-    if let Some(note) = note {
-        diag.note(note);
-    }
-    diag.emit()
-}
-
 impl<'tcx> OnUnimplementedDirective {
     fn parse(
         tcx: TyCtxt<'tcx>,
@@ -70,25 +59,9 @@ fn parse(
         } else {
             let cond = item_iter
                 .next()
-                .ok_or_else(|| {
-                    parse_error(
-                        tcx,
-                        span,
-                        "empty `on`-clause in `#[rustc_on_unimplemented]`",
-                        "empty on-clause here",
-                        None,
-                    )
-                })?
+                .ok_or_else(|| tcx.sess.emit_err(EmptyOnClauseInOnUnimplemented { span }))?
                 .meta_item()
-                .ok_or_else(|| {
-                    parse_error(
-                        tcx,
-                        span,
-                        "invalid `on`-clause in `#[rustc_on_unimplemented]`",
-                        "invalid on-clause here",
-                        None,
-                    )
-                })?;
+                .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
             attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
                 if let Some(value) = cfg.value && let Err(guar) = parse_value(value) {
                     errored = Some(guar);
@@ -150,13 +123,7 @@ fn parse(
             }
 
             // nothing found
-            parse_error(
-                tcx,
-                item.span(),
-                "this attribute must have a valid value",
-                "expected value here",
-                Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#),
-            );
+            tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
         }
 
         if let Some(reported) = errored {
index 444ca6471e2e4d51696f25da4abfd4a1881e4c76..398635674abcfd19a69c7de02f88af6787e209f9 100644 (file)
@@ -231,7 +231,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
 /// If successful, this may result in additional obligations.
 ///
 /// See [poly_project_and_unify_type] for an explanation of the return value.
-#[tracing::instrument(level = "debug", skip(selcx))]
+#[instrument(level = "debug", skip(selcx))]
 fn project_and_unify_type<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionObligation<'tcx>,
@@ -1206,7 +1206,7 @@ fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx
 ///
 /// IMPORTANT:
 /// - `obligation` must be fully normalized
-#[tracing::instrument(level = "info", skip(selcx))]
+#[instrument(level = "info", skip(selcx))]
 fn project<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
@@ -1368,7 +1368,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
     );
 }
 
-#[tracing::instrument(
+#[instrument(
     level = "debug",
     skip(selcx, candidate_set, ctor, env_predicates, potentially_unnormalized_candidates)
 )]
@@ -1419,7 +1419,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
     }
 }
 
-#[tracing::instrument(level = "debug", skip(selcx, obligation, candidate_set))]
+#[instrument(level = "debug", skip(selcx, obligation, candidate_set))]
 fn assemble_candidates_from_impls<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
index d67bd6292b434534556ea19f1896f3597294e377..e84c462ca816195e39badb321ed16c0a2135404b 100644 (file)
@@ -28,7 +28,7 @@
 use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack};
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     pub(super) fn candidate_from_obligation<'o>(
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
@@ -48,7 +48,7 @@ pub(super) fn candidate_from_obligation<'o>(
         if let Some(c) =
             self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred)
         {
-            debug!(candidate = ?c, "CACHE HIT");
+            debug!("CACHE HIT");
             return c;
         }
 
@@ -61,7 +61,7 @@ pub(super) fn candidate_from_obligation<'o>(
         let (candidate, dep_node) =
             self.in_task(|this| this.candidate_from_obligation_no_cache(stack));
 
-        debug!(?candidate, "CACHE MISS");
+        debug!("CACHE MISS");
         self.insert_candidate_cache(
             stack.obligation.param_env,
             cache_fresh_trait_pred,
@@ -337,7 +337,7 @@ pub(super) fn assemble_candidates<'o>(
         Ok(candidates)
     }
 
-    #[tracing::instrument(level = "debug", skip(self, candidates))]
+    #[instrument(level = "debug", skip(self, candidates))]
     fn assemble_candidates_from_projected_tys(
         &mut self,
         obligation: &TraitObligation<'tcx>,
@@ -367,7 +367,7 @@ fn assemble_candidates_from_projected_tys(
     /// supplied to find out whether it is listed among them.
     ///
     /// Never affects the inference environment.
-    #[tracing::instrument(level = "debug", skip(self, stack, candidates))]
+    #[instrument(level = "debug", skip(self, stack, candidates))]
     fn assemble_candidates_from_caller_bounds<'o>(
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
@@ -880,7 +880,7 @@ fn assemble_candidates_for_unsizing(
         };
     }
 
-    #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
+    #[instrument(level = "debug", skip(self, obligation, candidates))]
     fn assemble_candidates_for_transmutability(
         &mut self,
         obligation: &TraitObligation<'tcx>,
@@ -898,7 +898,7 @@ fn assemble_candidates_for_transmutability(
         candidates.vec.push(TransmutabilityCandidate);
     }
 
-    #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
+    #[instrument(level = "debug", skip(self, obligation, candidates))]
     fn assemble_candidates_for_trait_alias(
         &mut self,
         obligation: &TraitObligation<'tcx>,
@@ -917,7 +917,7 @@ fn assemble_candidates_for_trait_alias(
 
     /// Assembles the trait which are built-in to the language itself:
     /// `Copy`, `Clone` and `Sized`.
-    #[tracing::instrument(level = "debug", skip(self, candidates))]
+    #[instrument(level = "debug", skip(self, candidates))]
     fn assemble_builtin_bound_candidates(
         &mut self,
         conditions: BuiltinImplConditions<'tcx>,
index 46b50dd92f1ef7a3ed17fa20b66ccaf9b7b7657b..5da8cfab0b13b77102197cf235c3503b1cef9533 100644 (file)
@@ -295,7 +295,7 @@ pub fn is_intercrate(&self) -> bool {
 
     /// Attempts to satisfy the obligation. If successful, this will affect the surrounding
     /// type environment by performing unification.
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     pub fn select(
         &mut self,
         obligation: &TraitObligation<'tcx>,
@@ -325,10 +325,7 @@ pub fn select(
                 Err(SelectionError::Overflow(OverflowError::Canonical))
             }
             Err(e) => Err(e),
-            Ok(candidate) => {
-                debug!(?candidate, "confirmed");
-                Ok(Some(candidate))
-            }
+            Ok(candidate) => Ok(Some(candidate)),
         }
     }
 
@@ -435,6 +432,7 @@ fn evaluate_predicates_recursively<'o, I>(
         level = "debug",
         skip(self, previous_stack),
         fields(previous_stack = ?previous_stack.head())
+        ret,
     )]
     fn evaluate_predicate_recursively<'o>(
         &mut self,
@@ -450,7 +448,7 @@ fn evaluate_predicate_recursively<'o>(
             None => self.check_recursion_limit(&obligation, &obligation)?,
         }
 
-        let result = ensure_sufficient_stack(|| {
+        ensure_sufficient_stack(|| {
             let bound_predicate = obligation.predicate.kind();
             match bound_predicate.skip_binder() {
                 ty::PredicateKind::Trait(t) => {
@@ -760,14 +758,10 @@ fn evaluate_predicate_recursively<'o>(
                     bug!("TypeWellFormedFromEnv is only used for chalk")
                 }
             }
-        });
-
-        debug!("finished: {:?} from {:?}", result, obligation);
-
-        result
+        })
     }
 
-    #[instrument(skip(self, previous_stack), level = "debug")]
+    #[instrument(skip(self, previous_stack), level = "debug", ret)]
     fn evaluate_trait_predicate_recursively<'o>(
         &mut self,
         previous_stack: TraitObligationStackList<'o, 'tcx>,
@@ -798,12 +792,12 @@ fn evaluate_trait_predicate_recursively<'o>(
         // If a trait predicate is in the (local or global) evaluation cache,
         // then we know it holds without cycles.
         if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) {
-            debug!(?result, "CACHE HIT");
+            debug!("CACHE HIT");
             return Ok(result);
         }
 
         if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) {
-            debug!(?result, "PROVISIONAL CACHE HIT");
+            debug!("PROVISIONAL CACHE HIT");
             stack.update_reached_depth(result.reached_depth);
             return Ok(result.result);
         }
@@ -826,11 +820,11 @@ fn evaluate_trait_predicate_recursively<'o>(
 
         let reached_depth = stack.reached_depth.get();
         if reached_depth >= stack.depth {
-            debug!(?result, "CACHE MISS");
+            debug!("CACHE MISS");
             self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result);
             stack.cache().on_completion(stack.dfn);
         } else {
-            debug!(?result, "PROVISIONAL");
+            debug!("PROVISIONAL");
             debug!(
                 "caching provisionally because {:?} \
                  is a cycle participant (at depth {}, reached depth {})",
@@ -1023,7 +1017,8 @@ fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
     #[instrument(
         level = "debug",
         skip(self, stack),
-        fields(depth = stack.obligation.recursion_depth)
+        fields(depth = stack.obligation.recursion_depth),
+        ret
     )]
     fn evaluate_candidate<'o>(
         &mut self,
@@ -1056,7 +1051,6 @@ fn evaluate_candidate<'o>(
             result = result.max(EvaluatedToOkModuloRegions);
         }
 
-        debug!(?result);
         Ok(result)
     }
 
@@ -1405,7 +1399,7 @@ fn insert_candidate_cache(
     /// a projection, look at the bounds of `T::Bar`, see if we can find a
     /// `Baz` bound. We return indexes into the list returned by
     /// `tcx.item_bounds` for any applicable bounds.
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     fn match_projection_obligation_against_definition_bounds(
         &mut self,
         obligation: &TraitObligation<'tcx>,
@@ -1435,7 +1429,7 @@ fn match_projection_obligation_against_definition_bounds(
         // unnecessary ambiguity.
         let mut distinct_normalized_bounds = FxHashSet::default();
 
-        let matching_bounds = bounds
+        bounds
             .iter()
             .enumerate()
             .filter_map(|(idx, bound)| {
@@ -1462,10 +1456,7 @@ fn match_projection_obligation_against_definition_bounds(
                 }
                 None
             })
-            .collect();
-
-        debug!(?matching_bounds);
-        matching_bounds
+            .collect()
     }
 
     /// Equates the trait in `obligation` with trait bound. If the two traits
@@ -2153,7 +2144,7 @@ fn rematch_impl(
         }
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     fn match_impl(
         &mut self,
         impl_def_id: DefId,
@@ -2194,17 +2185,16 @@ fn match_impl(
             .at(&cause, obligation.param_env)
             .define_opaque_types(false)
             .eq(placeholder_obligation_trait_ref, impl_trait_ref)
-            .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
+            .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{e}`"))?;
         nested_obligations.extend(obligations);
 
         if !self.intercrate
             && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
         {
-            debug!("match_impl: reservation impls only apply in intercrate mode");
+            debug!("reservation impls only apply in intercrate mode");
             return Err(());
         }
 
-        debug!(?impl_substs, ?nested_obligations, "match_impl: success");
         Ok(Normalized { value: impl_substs, obligations: nested_obligations })
     }
 
@@ -2335,7 +2325,7 @@ fn generator_trait_ref_unnormalized(
     /// impl or trait. The obligations are substituted and fully
     /// normalized. This is used when confirming an impl or default
     /// impl.
-    #[tracing::instrument(level = "debug", skip(self, cause, param_env))]
+    #[instrument(level = "debug", skip(self, cause, param_env))]
     fn impl_or_trait_obligations(
         &mut self,
         cause: &ObligationCause<'tcx>,
index 0f76fef0eee228168c49a3d5128776dd1338574f..7d299e30ae041290a3760f6295a0fff0da46c452 100644 (file)
@@ -12,6 +12,7 @@
 pub mod specialization_graph;
 use specialization_graph::GraphExt;
 
+use crate::errors::NegativePositiveConflict;
 use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
@@ -327,35 +328,13 @@ fn report_negative_positive_conflict(
     positive_impl_def_id: DefId,
     sg: &mut specialization_graph::Graph,
 ) {
-    let impl_span = tcx.def_span(local_impl_def_id);
-
-    let mut err = struct_span_err!(
-        tcx.sess,
-        impl_span,
-        E0751,
-        "found both positive and negative implementation of trait `{}`{}:",
-        overlap.trait_desc,
-        overlap.self_desc.clone().map_or_else(String::new, |ty| format!(" for type `{}`", ty))
-    );
-
-    match tcx.span_of_impl(negative_impl_def_id) {
-        Ok(span) => {
-            err.span_label(span, "negative implementation here");
-        }
-        Err(cname) => {
-            err.note(&format!("negative implementation in crate `{}`", cname));
-        }
-    }
-
-    match tcx.span_of_impl(positive_impl_def_id) {
-        Ok(span) => {
-            err.span_label(span, "positive implementation here");
-        }
-        Err(cname) => {
-            err.note(&format!("positive implementation in crate `{}`", cname));
-        }
-    }
-
+    let mut err = tcx.sess.create_err(NegativePositiveConflict {
+        impl_span: tcx.def_span(local_impl_def_id),
+        trait_desc: &overlap.trait_desc,
+        self_desc: &overlap.self_desc,
+        negative_impl_span: tcx.span_of_impl(negative_impl_def_id),
+        positive_impl_span: tcx.span_of_impl(positive_impl_def_id),
+    });
     sg.has_errored = Some(err.emit());
 }
 
index 4bd179d23913143dd663bd7c7899677264f5c3ba..bb6009cb22a37b2df733bb9019e164eae8d5288b 100644 (file)
@@ -841,7 +841,7 @@ pub fn object_region_bounds<'tcx>(
 ///
 /// Requires that trait definitions have been processed so that we can
 /// elaborate predicates and walk supertraits.
-#[instrument(skip(tcx, predicates), level = "debug")]
+#[instrument(skip(tcx, predicates), level = "debug", ret)]
 pub(crate) fn required_region_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     erased_self_ty: Ty<'tcx>,
index c7c604e14e3ee4d235ffc5db02c1b7b1c82d0247..a166371fed1e01c2dc2af7ae5700b1a0829cb7e7 100644 (file)
@@ -191,7 +191,7 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::GoalData<RustInte
                 GenericArgKind::Const(..) => {
                     chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
                 }
-                GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt),
+                GenericArgKind::Lifetime(lt) => bug!("unexpected well formed predicate: {:?}", lt),
             },
 
             ty::PredicateKind::ObjectSafe(t) => chalk_ir::GoalData::DomainGoal(
index d895b647db0b144a8462330a83fdd4325c99e887..60e9b88107dd698a258c044d6042436bbdb9c74a 100644 (file)
@@ -120,6 +120,7 @@ fn subst<T>(&self, value: T, substs: &[GenericArg<'tcx>]) -> T
         EarlyBinder(value).subst(self.tcx(), substs)
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn relate_mir_and_user_ty(
         &mut self,
         mir_ty: Ty<'tcx>,
@@ -132,8 +133,8 @@ fn relate_mir_and_user_ty(
 
         let ty = tcx.type_of(def_id);
         let ty = self.subst(ty, substs);
-        debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
         let ty = self.normalize(ty);
+        debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
 
         self.relate(mir_ty, Variance::Invariant, ty)?;
 
@@ -144,7 +145,7 @@ fn relate_mir_and_user_ty(
         // outlives" error messages.
         let instantiated_predicates =
             self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs);
-        debug!(?instantiated_predicates.predicates);
+        debug!(?instantiated_predicates);
         for instantiated_predicate in instantiated_predicates.predicates {
             let instantiated_predicate = self.normalize(instantiated_predicate);
             self.prove_predicate(instantiated_predicate, span);
index 93cab7ca533954b216e7df75b6efbedc8fae21e1..211c813b8001c8ae626bc5f783213c3c83fc2010 100644 (file)
@@ -317,7 +317,7 @@ pub fn from_ty(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Result<Self, Err> {
                             tcx,
                         )?,
                         AdtKind::Enum => {
-                            tracing::trace!(?adt_def, "treeifying enum");
+                            trace!(?adt_def, "treeifying enum");
                             let mut tree = Tree::uninhabited();
 
                             for (idx, discr) in adt_def.discriminants(tcx) {
@@ -381,7 +381,7 @@ fn from_repr_c_variant(
             let clamp =
                 |align: Align| align.clamp(min_align, max_align).bytes().try_into().unwrap();
 
-            let variant_span = tracing::trace_span!(
+            let variant_span = trace_span!(
                 "treeifying variant",
                 min_align = ?min_align,
                 max_align = ?max_align,
@@ -396,27 +396,27 @@ fn from_repr_c_variant(
 
             // The layout of the variant is prefixed by the discriminant, if any.
             if let Some(discr) = discr {
-                tracing::trace!(?discr, "treeifying discriminant");
+                trace!(?discr, "treeifying discriminant");
                 let discr_layout = alloc::Layout::from_size_align(
                     layout_summary.discriminant_size,
                     clamp(layout_summary.discriminant_align),
                 )
                 .unwrap();
-                tracing::trace!(?discr_layout, "computed discriminant layout");
+                trace!(?discr_layout, "computed discriminant layout");
                 variant_layout = variant_layout.extend(discr_layout).unwrap().0;
                 tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size));
             }
 
             // Next come fields.
-            let fields_span = tracing::trace_span!("treeifying fields").entered();
+            let fields_span = trace_span!("treeifying fields").entered();
             for field_def in variant_def.fields.iter() {
                 let field_ty = field_def.ty(tcx, substs_ref);
-                let _span = tracing::trace_span!("treeifying field", field = ?field_ty).entered();
+                let _span = trace_span!("treeifying field", field = ?field_ty).entered();
 
                 // begin with the field's visibility
                 tree = tree.then(Self::def(Def::Field(field_def)));
 
-                // compute the field's layout charactaristics
+                // compute the field's layout characteristics
                 let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align);
 
                 // next comes the field's padding
@@ -434,7 +434,7 @@ fn from_repr_c_variant(
             drop(fields_span);
 
             // finally: padding
-            let padding_span = tracing::trace_span!("adding trailing padding").entered();
+            let padding_span = trace_span!("adding trailing padding").entered();
             let padding_needed = layout_summary.total_size - variant_layout.size();
             if padding_needed > 0 {
                 tree = tree.then(Self::padding(padding_needed));
@@ -467,7 +467,7 @@ fn layout_of<'tcx>(
             layout.align().abi.bytes().try_into().unwrap(),
         )
         .unwrap();
-        tracing::trace!(?ty, ?layout, "computed layout for type");
+        trace!(?ty, ?layout, "computed layout for type");
         Ok(layout)
     }
 }
index 076d922d1b72b4157a47dd296dc15a3007252d8b..248ff1ec24164c9209c84bdd98b009de8e2679d7 100644 (file)
@@ -110,7 +110,7 @@ pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
             // Remove all `Def` nodes from `src`, without checking their visibility.
             let src = src.prune(&|def| true);
 
-            tracing::trace!(?src, "pruned src");
+            trace!(?src, "pruned src");
 
             // Remove all `Def` nodes from `dst`, additionally...
             let dst = if assume_visibility {
@@ -121,7 +121,7 @@ pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
                 dst.prune(&|def| context.is_accessible_from(def, scope))
             };
 
-            tracing::trace!(?dst, "pruned dst");
+            trace!(?dst, "pruned dst");
 
             // Convert `src` from a tree-based representation to an NFA-based representation.
             // If the conversion fails because `src` is uninhabited, conclude that the transmutation
index 9c2cf4c9a92384821dc5c356372d351982213b83..adab343ac98aaa4b225a4b2bcb790d3000f3c2ea 100644 (file)
@@ -82,7 +82,7 @@ fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool {
                 false
             };
 
-            tracing::trace!(?ret, "ret");
+            trace!(?ret, "ret");
             ret
         }
 
index 16c4d429129a9d499ba5c8524943ba6f520d899e..bb6b3e1ff5d7482f0700b3d324819ae2df70f3be 100644 (file)
@@ -155,9 +155,9 @@ fn pat_is_poly(&mut self, pat: &thir::Pat<'tcx>) -> bool {
                     return true;
                 }
 
-                match pat.kind.as_ref() {
+                match pat.kind {
                     thir::PatKind::Constant { value } => value.has_param_types_or_consts(),
-                    thir::PatKind::Range(thir::PatRange { lo, hi, .. }) => {
+                    thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => {
                         lo.has_param_types_or_consts() || hi.has_param_types_or_consts()
                     }
                     _ => false,
index bd1d568cd9a051079bae294ec74562a557c371ce..661e413fc5b8170defb0d06724fc0b62710b4573 100644 (file)
@@ -15,8 +15,6 @@
 use std::collections::BTreeMap;
 use std::ops::ControlFlow;
 
-use tracing::debug;
-
 // 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
index acfeefb4d12d535d9d7a03477a90049cde370ac6..9d640672cf92c8cd3bc2f7cc861c931a71b3edb7 100644 (file)
@@ -104,7 +104,6 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain
 }
 
 /// See `ParamEnv` struct definition for details.
-#[instrument(level = "debug", skip(tcx))]
 fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     // The param_env of an impl Trait type is its defining function's param_env
     if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
@@ -410,7 +409,6 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
 }
 
 /// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead.
-#[instrument(level = "debug", skip(tcx))]
 pub fn conservative_is_privately_uninhabited_raw<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env_and: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
index 5bb02bc246caf28bf5c05136bf6418a515747109..ef927058df4eef0781c1c7a512921844d540b2c9 100644 (file)
@@ -144,7 +144,7 @@ enum ConvertedBindingKind<'a, 'tcx> {
 /// instantiated with some generic arguments providing `'a` explicitly,
 /// we taint those arguments with `ExplicitLateBound::Yes` so that we
 /// can provide an appropriate diagnostic later.
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub enum ExplicitLateBound {
     Yes,
     No,
@@ -167,7 +167,7 @@ pub(crate) enum GenericArgPosition {
 
 /// A marker denoting that the generic arguments that were
 /// provided did not match the respective generic parameters.
-#[derive(Clone, Default)]
+#[derive(Clone, Default, Debug)]
 pub struct GenericArgCountMismatch {
     /// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`).
     pub reported: Option<ErrorGuaranteed>,
@@ -177,7 +177,7 @@ pub struct GenericArgCountMismatch {
 
 /// Decorates the result of a generic argument count mismatch
 /// check with whether explicit late bounds were provided.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct GenericArgCountResult {
     pub explicit_late_bound: ExplicitLateBound,
     pub correct: Result<(), GenericArgCountMismatch>,
@@ -201,7 +201,7 @@ fn inferred_kind(
 }
 
 impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     pub fn ast_region_to_region(
         &self,
         lifetime: &hir::Lifetime,
@@ -210,7 +210,7 @@ pub fn ast_region_to_region(
         let tcx = self.tcx();
         let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id));
 
-        let r = match tcx.named_region(lifetime.hir_id) {
+        match tcx.named_region(lifetime.hir_id) {
             Some(rl::Region::Static) => tcx.lifetimes.re_static,
 
             Some(rl::Region::LateBound(debruijn, index, def_id)) => {
@@ -222,9 +222,12 @@ pub fn ast_region_to_region(
                 tcx.mk_region(ty::ReLateBound(debruijn, br))
             }
 
-            Some(rl::Region::EarlyBound(index, id)) => {
-                let name = lifetime_name(id.expect_local());
-                tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name }))
+            Some(rl::Region::EarlyBound(def_id)) => {
+                let name = tcx.hir().ty_param_name(def_id.expect_local());
+                let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
+                let generics = tcx.generics_of(item_def_id);
+                let index = generics.param_def_id_to_index[&def_id];
+                tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }))
             }
 
             Some(rl::Region::Free(scope, id)) => {
@@ -252,11 +255,7 @@ pub fn ast_region_to_region(
                     tcx.lifetimes.re_static
                 })
             }
-        };
-
-        debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r);
-
-        r
+        }
     }
 
     /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
@@ -316,7 +315,7 @@ pub fn ast_path_substs_for_ty(
     /// `[Vec<u8>, u8]` and `generic_args` are the arguments for the associated
     /// type itself: `['a]`. The returned `SubstsRef` concatenates these two
     /// lists: `[Vec<u8>, u8, 'a]`.
-    #[tracing::instrument(level = "debug", skip(self, span))]
+    #[instrument(level = "debug", skip(self, span), ret)]
     fn create_substs_for_ast_path<'a>(
         &self,
         span: Span,
@@ -536,11 +535,6 @@ fn inferred_kind(
             &mut substs_ctx,
         );
 
-        debug!(
-            "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}",
-            generics, self_ty, substs
-        );
-
         (substs, arg_count)
     }
 
@@ -715,7 +709,7 @@ fn instantiate_poly_trait_ref_inner(
     /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be
     /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly,
     /// however.
-    #[tracing::instrument(level = "debug", skip(self, span, constness, bounds, speculative))]
+    #[instrument(level = "debug", skip(self, span, constness, bounds, speculative))]
     pub(crate) fn instantiate_poly_trait_ref(
         &self,
         trait_ref: &hir::TraitRef<'_>,
@@ -807,7 +801,7 @@ fn ast_path_to_mono_trait_ref(
         ty::TraitRef::new(trait_def_id, substs)
     }
 
-    #[tracing::instrument(level = "debug", skip(self, span))]
+    #[instrument(level = "debug", skip(self, span))]
     fn create_substs_for_ast_trait_ref<'a>(
         &self,
         span: Span,
@@ -921,7 +915,7 @@ pub(crate) fn add_implicitly_sized<'hir>(
     /// **A note on binders:** there is an implied binder around
     /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
     /// for more details.
-    #[tracing::instrument(level = "debug", skip(self, ast_bounds, bounds))]
+    #[instrument(level = "debug", skip(self, ast_bounds, bounds))]
     pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>>(
         &self,
         param_ty: Ty<'tcx>,
@@ -1027,10 +1021,7 @@ fn compute_bounds_inner(
     /// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the
     /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside*
     /// the binder (e.g., `&'a u32`) and hence may reference bound regions.
-    #[tracing::instrument(
-        level = "debug",
-        skip(self, bounds, speculative, dup_bindings, path_span)
-    )]
+    #[instrument(level = "debug", skip(self, bounds, speculative, dup_bindings, path_span))]
     fn add_predicates_for_ast_type_binding(
         &self,
         hir_ref_id: hir::HirId,
@@ -2598,7 +2589,7 @@ pub fn ast_ty_to_ty_in_path(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
 
     /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait
     /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors.
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> {
         let tcx = self.tcx();
 
@@ -2702,8 +2693,6 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
             hir::TyKind::Err => tcx.ty_error(),
         };
 
-        debug!(?result_ty);
-
         self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
         result_ty
     }
@@ -2853,10 +2842,14 @@ pub fn ty_of_fn(
             );
 
             if !infer_replacements.is_empty() {
-                diag.multipart_suggestion(&format!(
+                diag.multipart_suggestion(
+                    &format!(
                     "try replacing `_` with the type{} in the corresponding trait method signature",
                     rustc_errors::pluralize!(infer_replacements.len()),
-                ), infer_replacements, Applicability::MachineApplicable);
+                ),
+                    infer_replacements,
+                    Applicability::MachineApplicable,
+                );
             }
 
             diag.emit();
index 2d50412007d909b493571c7d774bc4c82b729dd0..25bafdfe859b882af75dee0a021595a9db8f7670 100644 (file)
@@ -12,7 +12,7 @@
 };
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    #[instrument(skip(self), level = "debug")]
+    #[instrument(skip(self), level = "debug", ret)]
     pub fn check_match(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
@@ -212,9 +212,7 @@ pub fn check_match(
         // We won't diverge unless the scrutinee or all arms diverge.
         self.diverges.set(scrut_diverges | all_arms_diverge);
 
-        let match_ty = coercion.complete(self);
-        debug!(?match_ty);
-        match_ty
+        coercion.complete(self)
     }
 
     /// When the previously checked expression (the scrutinee) diverges,
index 5cdb2acd9f3c5b24cf91b65549dafd2f5d527ee7..29a128f27b840f5653dc3796f181f8f317d3d738 100644 (file)
@@ -101,7 +101,7 @@ pub(super) fn check_fn<'a, 'tcx>(
             decl.output.span(),
             param_env,
         ));
-    // If we replaced declared_ret_ty with infer vars, then we must be infering
+    // If we replaced declared_ret_ty with infer vars, then we must be inferring
     // an opaque type, so set a flag so we can improve diagnostics.
     fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
 
@@ -1543,7 +1543,7 @@ fn detect_discriminant_duplicate<'tcx>(
             None => {
                 // At this point we know this discriminant is a duplicate, and was not explicitly
                 // assigned by the user. Here we iterate backwards to fetch the HIR for the last
-                // explictly assigned discriminant, and letting the user know that this was the
+                // explicitly assigned discriminant, and letting the user know that this was the
                 // increment startpoint, and how many steps from there leading to the duplicate
                 if let Some((n, hir::Variant { span, ident, .. })) =
                     vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some())
@@ -1566,7 +1566,7 @@ fn detect_discriminant_duplicate<'tcx>(
     };
 
     // Here we loop through the discriminants, comparing each discriminant to another.
-    // When a duplicate is detected, we instatiate an error and point to both
+    // When a duplicate is detected, we instantiate an error and point to both
     // initial and duplicate value. The duplicate discriminant is then discarded by swapping
     // it with the last element and decrementing the `vec.len` (which is why we have to evaluate
     // `discrs.len()` anew every iteration, and why this could be tricky to do in a functional
index fee872155f5b2d1fa86c3ca4958a8c5d0384ce3a..bc3fec6e7d66a371dc57dfb0fd8a0039a30838fa 100644 (file)
@@ -58,7 +58,7 @@ pub fn check_expr_closure(
         self.check_closure(expr, expected_kind, decl, body, gen, expected_sig)
     }
 
-    #[instrument(skip(self, expr, body, decl), level = "debug")]
+    #[instrument(skip(self, expr, body, decl), level = "debug", ret)]
     fn check_closure(
         &self,
         expr: &hir::Expr<'_>,
@@ -158,11 +158,7 @@ fn check_closure(
             },
         );
 
-        let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs);
-
-        debug!(?expr.hir_id, ?closure_type);
-
-        closure_type
+        self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs)
     }
 
     /// Given the expected type, figures out what it can about this closure we
@@ -262,7 +258,7 @@ fn deduce_expectations_from_obligations(
     /// The `cause_span` should be the span that caused us to
     /// have this expected signature, or `None` if we can't readily
     /// know that.
-    #[instrument(level = "debug", skip(self, cause_span))]
+    #[instrument(level = "debug", skip(self, cause_span), ret)]
     fn deduce_sig_from_projection(
         &self,
         cause_span: Option<Span>,
@@ -317,7 +313,6 @@ fn deduce_sig_from_projection(
             hir::Unsafety::Normal,
             Abi::Rust,
         ));
-        debug!(?sig);
 
         Some(ExpectedSig { cause_span, sig })
     }
@@ -576,7 +571,7 @@ fn check_supplied_sig_against_expectation(
     /// types that the user gave into a signature.
     ///
     /// Also, record this closure signature for later.
-    #[instrument(skip(self, decl, body), level = "debug")]
+    #[instrument(skip(self, decl, body), level = "debug", ret)]
     fn supplied_sig_of_closure(
         &self,
         hir_id: hir::HirId,
@@ -629,8 +624,6 @@ fn supplied_sig_of_closure(
             bound_vars,
         );
 
-        debug!(?result);
-
         let c_result = self.inh.infcx.canonicalize_response(result);
         self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
 
@@ -643,7 +636,7 @@ fn supplied_sig_of_closure(
     /// user specified. The "desugared" return type is an `impl
     /// Future<Output = T>`, so we do this by searching through the
     /// obligations to extract the `T`.
-    #[instrument(skip(self), level = "debug")]
+    #[instrument(skip(self), level = "debug", ret)]
     fn deduce_future_output_from_obligations(
         &self,
         expr_def_id: DefId,
@@ -704,7 +697,6 @@ fn deduce_future_output_from_obligations(
             );
         self.register_predicates(obligations);
 
-        debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty);
         Some(output_ty)
     }
 
index 804306814a24127b2c352a21ec17364e31c0a077..b6bc244d2b14447a5c3d4a96c942a87f8ca0f58a 100644 (file)
@@ -1308,7 +1308,7 @@ fn compare_type_predicate_entailment<'tcx>(
 /// For default associated types the normalization is not possible (the value
 /// from the impl could be overridden). We also can't normalize generic
 /// associated types (yet) because they contain bound parameters.
-#[tracing::instrument(level = "debug", skip(tcx))]
+#[instrument(level = "debug", skip(tcx))]
 pub fn check_type_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ty: &ty::AssocItem,
index 07046f3f0326b119185f836728bd3bf49df39873..b9054898a2e579174a748a275146d570d0074449 100644 (file)
@@ -130,7 +130,7 @@ pub fn demand_coerce(
     ///
     /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
     /// will be permitted if the diverges flag is currently "always".
-    #[tracing::instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
+    #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
     pub fn demand_coerce_diag(
         &self,
         expr: &hir::Expr<'tcx>,
index 71ae54bedce46ed3012fb969b77b9845a9ddd3d4..17ec8afc7379c1a505370ae64b33ba2ae03ea38c 100644 (file)
@@ -21,7 +21,6 @@
 };
 use crate::type_error_struct;
 
-use super::suggest_call_constructor;
 use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
@@ -44,7 +43,7 @@
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
 use rustc_middle::ty::error::TypeError::FieldMisMatch;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeVisitable};
+use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitable};
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -561,17 +560,16 @@ pub(crate) fn check_expr_path(
                     // We just want to check sizedness, so instead of introducing
                     // placeholder lifetimes with probing, we just replace higher lifetimes
                     // with fresh vars.
-                    let arg_span = args.get(i).map(|a| a.span);
-                    let span = arg_span.unwrap_or(expr.span);
+                    let span = args.get(i).map(|a| a.span).unwrap_or(expr.span);
                     let input = self.replace_bound_vars_with_fresh_vars(
                         span,
                         infer::LateBoundRegionConversionTime::FnCall,
                         fn_sig.input(i),
                     );
-                    self.require_type_is_sized(
-                        self.normalize_associated_types_in(span, input),
+                    self.require_type_is_sized_deferred(
+                        input,
                         span,
-                        traits::SizedArgumentType(arg_span),
+                        traits::SizedArgumentType(None),
                     );
                 }
             }
@@ -586,11 +584,7 @@ pub(crate) fn check_expr_path(
                 infer::LateBoundRegionConversionTime::FnCall,
                 fn_sig.output(),
             );
-            self.require_type_is_sized(
-                self.normalize_associated_types_in(expr.span, output),
-                expr.span,
-                traits::SizedReturnType,
-            );
+            self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType);
         }
 
         // We always require that the type provided as the value for
@@ -2141,15 +2135,15 @@ fn check_field(
         field: Ident,
     ) -> Ty<'tcx> {
         debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field);
-        let expr_t = self.check_expr(base);
-        let expr_t = self.structurally_resolved_type(base.span, expr_t);
+        let base_ty = self.check_expr(base);
+        let base_ty = self.structurally_resolved_type(base.span, base_ty);
         let mut private_candidate = None;
-        let mut autoderef = self.autoderef(expr.span, expr_t);
-        while let Some((base_t, _)) = autoderef.next() {
-            debug!("base_t: {:?}", base_t);
-            match base_t.kind() {
+        let mut autoderef = self.autoderef(expr.span, base_ty);
+        while let Some((deref_base_ty, _)) = autoderef.next() {
+            debug!("deref_base_ty: {:?}", deref_base_ty);
+            match deref_base_ty.kind() {
                 ty::Adt(base_def, substs) if !base_def.is_enum() => {
-                    debug!("struct named {:?}", base_t);
+                    debug!("struct named {:?}", deref_base_ty);
                     let (ident, def_scope) =
                         self.tcx.adjust_ident_and_get_scope(field, base_def.did(), self.body_id);
                     let fields = &base_def.non_enum_variant().fields;
@@ -2197,23 +2191,23 @@ fn check_field(
             // (#90483) apply adjustments to avoid ExprUseVisitor from
             // creating erroneous projection.
             self.apply_adjustments(base, adjustments);
-            self.ban_private_field_access(expr, expr_t, field, did);
+            self.ban_private_field_access(expr, base_ty, field, did);
             return field_ty;
         }
 
         if field.name == kw::Empty {
-        } else if self.method_exists(field, expr_t, expr.hir_id, true) {
-            self.ban_take_value_of_method(expr, expr_t, field);
-        } else if !expr_t.is_primitive_ty() {
-            self.ban_nonexisting_field(field, base, expr, expr_t);
+        } else if self.method_exists(field, base_ty, expr.hir_id, true) {
+            self.ban_take_value_of_method(expr, base_ty, field);
+        } else if !base_ty.is_primitive_ty() {
+            self.ban_nonexisting_field(field, base, expr, base_ty);
         } else {
             let field_name = field.to_string();
             let mut err = type_error_struct!(
                 self.tcx().sess,
                 field.span,
-                expr_t,
+                base_ty,
                 E0610,
-                "`{expr_t}` is a primitive type and therefore doesn't have fields",
+                "`{base_ty}` is a primitive type and therefore doesn't have fields",
             );
             let is_valid_suffix = |field: &str| {
                 if field == "f32" || field == "f64" {
@@ -2251,7 +2245,7 @@ fn check_field(
                     None
                 }
             };
-            if let ty::Infer(ty::IntVar(_)) = expr_t.kind()
+            if let ty::Infer(ty::IntVar(_)) = base_ty.kind()
                 && let ExprKind::Lit(Spanned {
                     node: ast::LitKind::Int(_, ast::LitIntType::Unsuffixed),
                     ..
@@ -2280,35 +2274,6 @@ fn check_field(
         self.tcx().ty_error()
     }
 
-    fn check_call_constructor(
-        &self,
-        err: &mut Diagnostic,
-        base: &'tcx hir::Expr<'tcx>,
-        def_id: DefId,
-    ) {
-        if let Some(local_id) = def_id.as_local() {
-            let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id);
-            let node = self.tcx.hir().get(hir_id);
-
-            if let Some(fields) = node.tuple_fields() {
-                let kind = match self.tcx.opt_def_kind(local_id) {
-                    Some(DefKind::Ctor(of, _)) => of,
-                    _ => return,
-                };
-
-                suggest_call_constructor(base.span, kind, fields.len(), err);
-            }
-        } else {
-            // The logic here isn't smart but `associated_item_def_ids`
-            // doesn't work nicely on local.
-            if let DefKind::Ctor(of, _) = self.tcx.def_kind(def_id) {
-                let parent_def_id = self.tcx.parent(def_id);
-                let fields = self.tcx.associated_item_def_ids(parent_def_id);
-                suggest_call_constructor(base.span, of, fields.len(), err);
-            }
-        }
-    }
-
     fn suggest_await_on_field_access(
         &self,
         err: &mut Diagnostic,
@@ -2351,40 +2316,52 @@ fn suggest_await_on_field_access(
 
     fn ban_nonexisting_field(
         &self,
-        field: Ident,
+        ident: Ident,
         base: &'tcx hir::Expr<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
-        expr_t: Ty<'tcx>,
+        base_ty: Ty<'tcx>,
     ) {
         debug!(
-            "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}",
-            field, base, expr, expr_t
+            "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, base_ty={:?}",
+            ident, base, expr, base_ty
         );
-        let mut err = self.no_such_field_err(field, expr_t, base.hir_id);
+        let mut err = self.no_such_field_err(ident, base_ty, base.hir_id);
 
-        match *expr_t.peel_refs().kind() {
+        match *base_ty.peel_refs().kind() {
             ty::Array(_, len) => {
-                self.maybe_suggest_array_indexing(&mut err, expr, base, field, len);
+                self.maybe_suggest_array_indexing(&mut err, expr, base, ident, len);
             }
             ty::RawPtr(..) => {
-                self.suggest_first_deref_field(&mut err, expr, base, field);
+                self.suggest_first_deref_field(&mut err, expr, base, ident);
             }
             ty::Adt(def, _) if !def.is_enum() => {
-                self.suggest_fields_on_recordish(&mut err, def, field, expr.span);
+                self.suggest_fields_on_recordish(&mut err, def, ident, expr.span);
             }
             ty::Param(param_ty) => {
                 self.point_at_param_definition(&mut err, param_ty);
             }
             ty::Opaque(_, _) => {
-                self.suggest_await_on_field_access(&mut err, field, base, expr_t.peel_refs());
-            }
-            ty::FnDef(def_id, _) => {
-                self.check_call_constructor(&mut err, base, def_id);
+                self.suggest_await_on_field_access(&mut err, ident, base, base_ty.peel_refs());
             }
             _ => {}
         }
 
-        if field.name == kw::Await {
+        self.suggest_fn_call(&mut err, base, base_ty, |output_ty| {
+            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)
+                })
+            } else if let ty::Tuple(tys) = output_ty.kind()
+                && let Ok(idx) = ident.as_str().parse::<usize>()
+            {
+                idx < tys.len()
+            } else {
+                false
+            }
+        });
+
+        if ident.name == kw::Await {
             // We know by construction that `<expr>.await` is either on Rust 2015
             // or results in `ExprKind::Await`. Suggest switching the edition to 2018.
             err.note("to `.await` a `Future`, switch to Rust 2018 or later");
@@ -2605,32 +2582,39 @@ fn no_such_field_err(
         if let Some((fields, substs)) =
             self.get_field_candidates_considering_privacy(span, expr_t, mod_id)
         {
-            for candidate_field in fields {
-                if let Some(mut field_path) = self.check_for_nested_field_satisfying(
-                    span,
-                    &|candidate_field, _| candidate_field.ident(self.tcx()) == field,
-                    candidate_field,
-                    substs,
-                    vec![],
-                    mod_id,
-                ) {
-                    // field_path includes `field` that we're looking for, so pop it.
+            let candidate_fields: Vec<_> = fields
+                .filter_map(|candidate_field| {
+                    self.check_for_nested_field_satisfying(
+                        span,
+                        &|candidate_field, _| candidate_field.ident(self.tcx()) == field,
+                        candidate_field,
+                        substs,
+                        vec![],
+                        mod_id,
+                    )
+                })
+                .map(|mut field_path| {
                     field_path.pop();
-
-                    let field_path_str = field_path
+                    field_path
                         .iter()
                         .map(|id| id.name.to_ident_string())
                         .collect::<Vec<String>>()
-                        .join(".");
-                    debug!("field_path_str: {:?}", field_path_str);
-
-                    err.span_suggestion_verbose(
-                        field.span.shrink_to_lo(),
-                        "one of the expressions' fields has a field of the same name",
-                        format!("{field_path_str}."),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
+                        .join(".")
+                })
+                .collect::<Vec<_>>();
+
+            let len = candidate_fields.len();
+            if len > 0 {
+                err.span_suggestions(
+                    field.span.shrink_to_lo(),
+                    format!(
+                        "{} of the expressions' fields {} a field of the same name",
+                        if len > 1 { "some" } else { "one" },
+                        if len > 1 { "have" } else { "has" },
+                    ),
+                    candidate_fields.iter().map(|path| format!("{path}.")),
+                    Applicability::MaybeIncorrect,
+                );
             }
         }
         err
index 20d25d508d224e9749e631f3e8a4cfb5905cbe1e..7e746b7387ad781664a1aeca8c4ae6bb67ce376a 100644 (file)
@@ -83,7 +83,7 @@ pub(in super::super) fn resolve_vars_with_obligations(&self, ty: Ty<'tcx>) -> Ty
         self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {})
     }
 
-    #[instrument(skip(self, mutate_fulfillment_errors), level = "debug")]
+    #[instrument(skip(self, mutate_fulfillment_errors), level = "debug", ret)]
     pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment(
         &self,
         mut ty: Ty<'tcx>,
@@ -107,10 +107,7 @@ pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment(
         // indirect dependencies that don't seem worth tracking
         // precisely.
         self.select_obligations_where_possible(false, mutate_fulfillment_errors);
-        ty = self.resolve_vars_if_possible(ty);
-
-        debug!(?ty);
-        ty
+        self.resolve_vars_if_possible(ty)
     }
 
     pub(in super::super) fn record_deferred_call_resolution(
@@ -442,6 +439,17 @@ pub fn require_type_is_sized(
         }
     }
 
+    pub fn require_type_is_sized_deferred(
+        &self,
+        ty: Ty<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+    ) {
+        if !ty.references_error() {
+            self.deferred_sized_obligations.borrow_mut().push((ty, span, code));
+        }
+    }
+
     pub fn register_bound(
         &self,
         ty: Ty<'tcx>,
@@ -1405,7 +1413,7 @@ pub(crate) fn add_required_obligations_for_hir(
         })
     }
 
-    #[tracing::instrument(level = "debug", skip(self, code, span, def_id, substs))]
+    #[instrument(level = "debug", skip(self, code, span, def_id, substs))]
     fn add_required_obligations_with_code(
         &self,
         span: Span,
index 03bd485096a9c5046a97d1f072e6532094e56538..7ff4aef2d25716a28c6fa44177c35512bcb140e2 100644 (file)
@@ -153,7 +153,7 @@ pub(in super::super) fn check_argument_types(
     ) {
         let tcx = self.tcx;
 
-        // Conceptually, we've got some number of expected inputs, and some number of provided aguments
+        // Conceptually, we've got some number of expected inputs, and some number of provided arguments
         // and we can form a grid of whether each argument could satisfy a given input:
         //      in1 | in2 | in3 | ...
         // arg1  ?  |     |     |
index 57771e0969bac5c80143bcf8c04b8a9217b35ec0..939f4612d44ef6688010343717549e3ce8a0d2a6 100644 (file)
@@ -2,6 +2,7 @@
 use crate::astconv::AstConv;
 use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
 
+use hir::def_id::DefId;
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_errors::{Applicability, Diagnostic, MultiSpan};
 use rustc_hir as hir;
@@ -61,70 +62,51 @@ pub fn suggest_mismatched_types_on_tail(
         pointing_at_return_type
     }
 
-    /// When encountering an fn-like ctor that needs to unify with a value, check whether calling
-    /// the ctor would successfully solve the type mismatch and if so, suggest it:
+    /// When encountering an fn-like type, try accessing the output of the type
+    /// // and suggesting calling it if it satisfies a predicate (i.e. if the
+    /// output has a method or a field):
     /// ```compile_fail,E0308
     /// fn foo(x: usize) -> usize { x }
     /// let x: usize = foo;  // suggest calling the `foo` function: `foo(42)`
     /// ```
-    fn suggest_fn_call(
+    pub(crate) fn suggest_fn_call(
         &self,
         err: &mut Diagnostic,
         expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
         found: Ty<'tcx>,
+        can_satisfy: impl FnOnce(Ty<'tcx>) -> bool,
     ) -> bool {
-        let (def_id, output, inputs) = match *found.kind() {
-            ty::FnDef(def_id, _) => {
-                let fn_sig = found.fn_sig(self.tcx);
-                (def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len())
-            }
-            ty::Closure(def_id, substs) => {
-                let fn_sig = substs.as_closure().sig();
-                (def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len() - 1)
-            }
-            ty::Opaque(def_id, substs) => {
-                let sig = self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
-                    if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
-                    && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
-                    // args tuple will always be substs[1]
-                    && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
-                    {
-                        Some((
-                            pred.kind().rebind(proj.term.ty().unwrap()),
-                            args.len(),
-                        ))
-                    } else {
-                        None
-                    }
-                });
-                if let Some((output, inputs)) = sig {
-                    (def_id, output, inputs)
-                } else {
-                    return false;
-                }
-            }
-            _ => return false,
-        };
-
-        let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
-        let output = self.normalize_associated_types_in(expr.span, output);
-        if !output.is_ty_var() && self.can_coerce(output, expected) {
-            let (sugg_call, mut applicability) = match inputs {
+        let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(expr, found)
+            else { return false; };
+        if can_satisfy(output) {
+            let (sugg_call, mut applicability) = match inputs.len() {
                 0 => ("".to_string(), Applicability::MachineApplicable),
                 1..=4 => (
-                    (0..inputs).map(|_| "_").collect::<Vec<_>>().join(", "),
-                    Applicability::MachineApplicable,
+                    inputs
+                        .iter()
+                        .map(|ty| {
+                            if ty.is_suggestable(self.tcx, false) {
+                                format!("/* {ty} */")
+                            } else {
+                                "".to_string()
+                            }
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", "),
+                    Applicability::HasPlaceholders,
                 ),
-                _ => ("...".to_string(), Applicability::HasPlaceholders),
+                _ => ("/* ... */".to_string(), Applicability::HasPlaceholders),
             };
 
-            let msg = match self.tcx.def_kind(def_id) {
-                DefKind::Fn => "call this function",
-                DefKind::Closure | DefKind::OpaqueTy => "call this closure",
-                DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct",
-                DefKind::Ctor(CtorOf::Variant, _) => "instantiate this tuple variant",
-                _ => "call this function",
+            let msg = match def_id_or_name {
+                DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
+                    DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct".to_string(),
+                    DefKind::Ctor(CtorOf::Variant, _) => {
+                        "instantiate this tuple variant".to_string()
+                    }
+                    kind => format!("call this {}", kind.descr(def_id)),
+                },
+                DefIdOrName::Name(name) => format!("call this {name}"),
             };
 
             let sugg = match expr.kind {
@@ -161,6 +143,179 @@ fn suggest_fn_call(
         false
     }
 
+    fn extract_callable_info(
+        &self,
+        expr: &Expr<'_>,
+        found: Ty<'tcx>,
+    ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
+        // Autoderef is useful here because sometimes we box callables, etc.
+        let Some((def_id_or_name, output, inputs)) = self.autoderef(expr.span, found).silence_errors().find_map(|(found, _)| {
+            match *found.kind() {
+                ty::FnPtr(fn_sig) =>
+                    Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())),
+                ty::FnDef(def_id, _) => {
+                    let fn_sig = found.fn_sig(self.tcx);
+                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
+                }
+                ty::Closure(def_id, substs) => {
+                    let fn_sig = substs.as_closure().sig();
+                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
+                }
+                ty::Opaque(def_id, substs) => {
+                    self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
+                        if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+                        && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+                        // args tuple will always be substs[1]
+                        && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+                        {
+                            Some((
+                                DefIdOrName::DefId(def_id),
+                                pred.kind().rebind(proj.term.ty().unwrap()),
+                                pred.kind().rebind(args.as_slice()),
+                            ))
+                        } else {
+                            None
+                        }
+                    })
+                }
+                ty::Dynamic(data, _) => {
+                    data.iter().find_map(|pred| {
+                        if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
+                        && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
+                        // for existential projection, substs are shifted over by 1
+                        && let ty::Tuple(args) = proj.substs.type_at(0).kind()
+                        {
+                            Some((
+                                DefIdOrName::Name("trait object"),
+                                pred.rebind(proj.term.ty().unwrap()),
+                                pred.rebind(args.as_slice()),
+                            ))
+                        } else {
+                            None
+                        }
+                    })
+                }
+                ty::Param(param) => {
+                    let def_id = self.tcx.generics_of(self.body_id.owner).type_param(&param, self.tcx).def_id;
+                    self.tcx.predicates_of(self.body_id.owner).predicates.iter().find_map(|(pred, _)| {
+                        if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+                        && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+                        && proj.projection_ty.self_ty() == found
+                        // args tuple will always be substs[1]
+                        && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+                        {
+                            Some((
+                                DefIdOrName::DefId(def_id),
+                                pred.kind().rebind(proj.term.ty().unwrap()),
+                                pred.kind().rebind(args.as_slice()),
+                            ))
+                        } else {
+                            None
+                        }
+                    })
+                }
+                _ => None,
+            }
+        }) else { return None; };
+
+        let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
+        let inputs = inputs
+            .skip_binder()
+            .iter()
+            .map(|ty| {
+                self.replace_bound_vars_with_fresh_vars(
+                    expr.span,
+                    infer::FnCall,
+                    inputs.rebind(*ty),
+                )
+            })
+            .collect();
+
+        // We don't want to register any extra obligations, which should be
+        // implied by wf, but also because that would possibly result in
+        // erroneous errors later on.
+        let infer::InferOk { value: output, obligations: _ } =
+            self.normalize_associated_types_in_as_infer_ok(expr.span, output);
+
+        if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
+    }
+
+    pub fn suggest_two_fn_call(
+        &self,
+        err: &mut Diagnostic,
+        lhs_expr: &'tcx hir::Expr<'tcx>,
+        lhs_ty: Ty<'tcx>,
+        rhs_expr: &'tcx hir::Expr<'tcx>,
+        rhs_ty: Ty<'tcx>,
+        can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
+    ) -> bool {
+        let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_expr, lhs_ty)
+            else { return false; };
+        let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_expr, rhs_ty)
+            else { return false; };
+
+        if can_satisfy(lhs_output_ty, rhs_output_ty) {
+            let mut sugg = vec![];
+            let mut applicability = Applicability::MachineApplicable;
+
+            for (expr, inputs) in [(lhs_expr, lhs_inputs), (rhs_expr, rhs_inputs)] {
+                let (sugg_call, this_applicability) = match inputs.len() {
+                    0 => ("".to_string(), Applicability::MachineApplicable),
+                    1..=4 => (
+                        inputs
+                            .iter()
+                            .map(|ty| {
+                                if ty.is_suggestable(self.tcx, false) {
+                                    format!("/* {ty} */")
+                                } else {
+                                    "/* value */".to_string()
+                                }
+                            })
+                            .collect::<Vec<_>>()
+                            .join(", "),
+                        Applicability::HasPlaceholders,
+                    ),
+                    _ => ("/* ... */".to_string(), Applicability::HasPlaceholders),
+                };
+
+                applicability = applicability.max(this_applicability);
+
+                match expr.kind {
+                    hir::ExprKind::Call(..)
+                    | hir::ExprKind::Path(..)
+                    | hir::ExprKind::Index(..)
+                    | hir::ExprKind::Lit(..) => {
+                        sugg.extend([(expr.span.shrink_to_hi(), format!("({sugg_call})"))]);
+                    }
+                    hir::ExprKind::Closure { .. } => {
+                        // Might be `{ expr } || { bool }`
+                        applicability = Applicability::MaybeIncorrect;
+                        sugg.extend([
+                            (expr.span.shrink_to_lo(), "(".to_string()),
+                            (expr.span.shrink_to_hi(), format!(")({sugg_call})")),
+                        ]);
+                    }
+                    _ => {
+                        sugg.extend([
+                            (expr.span.shrink_to_lo(), "(".to_string()),
+                            (expr.span.shrink_to_hi(), format!(")({sugg_call})")),
+                        ]);
+                    }
+                }
+            }
+
+            err.multipart_suggestion_verbose(
+                format!("use parentheses to call these"),
+                sugg,
+                applicability,
+            );
+
+            true
+        } else {
+            false
+        }
+    }
+
     pub fn suggest_deref_ref_or_into(
         &self,
         err: &mut Diagnostic,
@@ -178,12 +333,11 @@ pub fn suggest_deref_ref_or_into(
             } else {
                 err.span_suggestion(sp, &msg, suggestion, applicability);
             }
-        } else if let (ty::FnDef(def_id, ..), true) =
-            (&found.kind(), self.suggest_fn_call(err, expr, expected, found))
+        } else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
+            && let ty::FnDef(def_id, ..) = &found.kind()
+            && let Some(sp) = self.tcx.hir().span_if_local(*def_id)
         {
-            if let Some(sp) = self.tcx.hir().span_if_local(*def_id) {
-                err.span_label(sp, format!("{found} defined here"));
-            }
+            err.span_label(sp, format!("{found} defined here"));
         } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
             let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
             if !methods.is_empty() {
@@ -506,30 +660,30 @@ pub(in super::super) fn suggest_missing_return_type(
             self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
         // Only suggest changing the return type for methods that
         // haven't set a return type at all (and aren't `fn main()` or an impl).
-        match (
-            &fn_decl.output,
-            found.is_suggestable(self.tcx, false),
-            can_suggest,
-            expected.is_unit(),
-        ) {
-            (&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
-                err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found });
-                true
-            }
-            (&hir::FnRetTy::DefaultReturn(span), false, true, true) => {
-                // FIXME: if `found` could be `impl Iterator` or `impl Fn*`, we should suggest
-                // that.
-                err.subdiagnostic(AddReturnTypeSuggestion::MissingHere { span });
-                true
-            }
-            (&hir::FnRetTy::DefaultReturn(span), _, false, true) => {
+        match &fn_decl.output {
+            &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => {
                 // `fn main()` must return `()`, do not suggest changing return type
                 err.subdiagnostic(ExpectedReturnTypeLabel::Unit { span });
-                true
+                return true;
+            }
+            &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
+                if found.is_suggestable(self.tcx, false) {
+                    err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() });
+                    return true;
+                } else if let ty::Closure(_, substs) = found.kind()
+                    // FIXME(compiler-errors): Get better at printing binders...
+                    && let closure = substs.as_closure()
+                    && closure.sig().is_suggestable(self.tcx, false)
+                {
+                    err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: closure.print_as_impl_trait().to_string() });
+                    return true;
+                } else {
+                    // FIXME: if `found` could be `impl Iterator` we should suggest that.
+                    err.subdiagnostic(AddReturnTypeSuggestion::MissingHere { span });
+                    return true
+                }
             }
-            // expectation was caused by something else, not the default return
-            (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false,
-            (&hir::FnRetTy::Return(ref ty), _, _, _) => {
+            &hir::FnRetTy::Return(ref ty) => {
                 // Only point to return type if the expected type is the return type, as if they
                 // are not, the expectation must have been caused by something else.
                 debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
@@ -546,9 +700,10 @@ pub(in super::super) fn suggest_missing_return_type(
                     self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
                     return true;
                 }
-                false
             }
+            _ => {}
         }
+        false
     }
 
     /// check whether the return type is a generic type with a trait bound
@@ -910,3 +1065,8 @@ pub(crate) fn consider_removing_semicolon(
         }
     }
 }
+
+enum DefIdOrName {
+    DefId(DefId),
+    Name(&'static str),
+}
index 85a0d4e44990602e6a6bcdb7172bf0057d0f685f..7fda6f79f238da477bbe80afdfb98098b76c25a0 100644 (file)
@@ -17,7 +17,6 @@
 use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
-use tracing::debug;
 
 mod drop_ranges;
 
@@ -409,8 +408,15 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
             }) {
             self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
         } else {
-            debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id));
-            match self.fcx.tcx.hir().find_parent_node(expr.hir_id) {
+            let parent_expr = self
+                .fcx
+                .tcx
+                .hir()
+                .parent_iter(expr.hir_id)
+                .find(|(_, node)| matches!(node, hir::Node::Expr(_)))
+                .map(|(id, _)| id);
+            debug!("parent_expr: {:?}", parent_expr);
+            match parent_expr {
                 Some(parent) => Some(Scope { id: parent.local_id, data: ScopeData::Node }),
                 None => {
                     self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
index ded0888c33e15db96d8139245f4fed5553d395ac..e22675e9d5f4e5ebc45155f2166788600eafc481 100644 (file)
@@ -159,8 +159,8 @@ fn borrow(
         bk: rustc_middle::ty::BorrowKind,
     ) {
         debug!(
-            "borrow: place_with_id = {place_with_id:?}, diag_expr_id={diag_expr_id:?}, \
-            borrow_kind={bk:?}"
+            "borrow: place_with_id = {place_with_id:#?}, diag_expr_id={diag_expr_id:#?}, \
+            borrow_kind={bk:#?}"
         );
 
         self.borrow_place(place_with_id);
index f3115fc5c023219cf73c42313b329bcbc4bbec75..37c830d4e3850f14c63e2ce1b918b8ae70ae0997 100644 (file)
@@ -1,6 +1,7 @@
 use super::callee::DeferredCallResolution;
 
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::HirIdMap;
@@ -12,7 +13,9 @@
 use rustc_span::def_id::LocalDefIdMap;
 use rustc_span::{self, Span};
 use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
+use rustc_trait_selection::traits::{
+    self, ObligationCause, ObligationCtxt, TraitEngine, TraitEngineExt as _,
+};
 
 use std::cell::RefCell;
 use std::ops::Deref;
@@ -35,6 +38,12 @@ pub struct Inherited<'a, 'tcx> {
 
     pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
 
+    // Some additional `Sized` obligations badly affect type inference.
+    // These obligations are added in a later stage of typeck.
+    // Removing these may also cause additional complications, see #101066.
+    pub(super) deferred_sized_obligations:
+        RefCell<Vec<(Ty<'tcx>, Span, traits::ObligationCauseCode<'tcx>)>>,
+
     // When we process a call like `c()` where `c` is a closure type,
     // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
     // `FnOnce` closure. In that case, we defer full resolution of the
@@ -84,7 +93,29 @@ pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
             infcx: tcx
                 .infer_ctxt()
                 .ignoring_regions()
-                .with_fresh_in_progress_typeck_results(hir_owner),
+                .with_fresh_in_progress_typeck_results(hir_owner)
+                .with_normalize_fn_sig_for_diagnostic(Lrc::new(move |infcx, fn_sig| {
+                    if fn_sig.has_escaping_bound_vars() {
+                        return fn_sig;
+                    }
+                    infcx.probe(|_| {
+                        let ocx = ObligationCtxt::new_in_snapshot(infcx);
+                        let normalized_fn_sig = ocx.normalize(
+                            ObligationCause::dummy(),
+                            // FIXME(compiler-errors): This is probably not the right param-env...
+                            infcx.tcx.param_env(def_id),
+                            fn_sig,
+                        );
+                        if ocx.select_all_or_error().is_empty() {
+                            let normalized_fn_sig =
+                                infcx.resolve_vars_if_possible(normalized_fn_sig);
+                            if !normalized_fn_sig.needs_infer() {
+                                return normalized_fn_sig;
+                            }
+                        }
+                        fn_sig
+                    })
+                })),
             def_id,
         }
     }
@@ -112,6 +143,7 @@ fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
             infcx,
             fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)),
             locals: RefCell::new(Default::default()),
+            deferred_sized_obligations: RefCell::new(Vec::new()),
             deferred_call_resolutions: RefCell::new(Default::default()),
             deferred_cast_checks: RefCell::new(Vec::new()),
             deferred_transmute_checks: RefCell::new(Vec::new()),
index de26a9e56e2d6b57275d2060fb475c540677eda0..a9071cd1fd949efe57c2bfd122425fb0b5277dd7 100644 (file)
@@ -168,7 +168,7 @@ pub(crate) fn suggest_method_call(
     /// * `call_expr`:             the complete method call: (`foo.bar::<T1,...Tn>(...)`)
     /// * `self_expr`:             the self expression (`foo`)
     /// * `args`:                  the expressions of the arguments (`a, b + 1, ...`)
-    #[instrument(level = "debug", skip(self, call_expr, self_expr))]
+    #[instrument(level = "debug", skip(self))]
     pub fn lookup_method(
         &self,
         self_ty: Ty<'tcx>,
@@ -178,11 +178,6 @@ pub fn lookup_method(
         self_expr: &'tcx hir::Expr<'tcx>,
         args: &'tcx [hir::Expr<'tcx>],
     ) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
-        debug!(
-            "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
-            segment.ident, self_ty, call_expr, self_expr
-        );
-
         let pick =
             self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
 
@@ -383,7 +378,7 @@ pub(super) fn obligation_for_op_method(
     /// In particular, it doesn't really do any probing: it simply constructs
     /// an obligation for a particular trait with the given self type and checks
     /// whether that trait is implemented.
-    #[instrument(level = "debug", skip(self, span, opt_input_types))]
+    #[instrument(level = "debug", skip(self, span))]
     pub(super) fn lookup_method_in_trait(
         &self,
         span: Span,
@@ -392,11 +387,6 @@ pub(super) fn lookup_method_in_trait(
         self_ty: Ty<'tcx>,
         opt_input_types: Option<&[Ty<'tcx>]>,
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        debug!(
-            "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})",
-            self_ty, m_name, trait_def_id, opt_input_types
-        );
-
         let (obligation, substs) =
             self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types);
         self.construct_obligation_for_trait(
@@ -576,7 +566,7 @@ fn construct_obligation_for_trait(
     /// * `self_ty`:               the type to search within (`Foo`)
     /// * `self_ty_span`           the span for the type being searched within (span of `Foo`)
     /// * `expr_id`:               the [`hir::HirId`] of the expression composing the entire call
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     pub fn resolve_fully_qualified_call(
         &self,
         span: Span,
@@ -585,11 +575,6 @@ pub fn resolve_fully_qualified_call(
         self_ty_span: Span,
         expr_id: hir::HirId,
     ) -> Result<(DefKind, DefId), MethodError<'tcx>> {
-        debug!(
-            "resolve_fully_qualified_call: method_name={:?} self_ty={:?} expr_id={:?}",
-            method_name, self_ty, expr_id,
-        );
-
         let tcx = self.tcx;
 
         // Check if we have an enum variant.
@@ -633,21 +618,17 @@ pub fn resolve_fully_qualified_call(
             &pick,
         );
 
-        debug!("resolve_fully_qualified_call: pick={:?}", pick);
+        debug!(?pick);
         {
             let mut typeck_results = self.typeck_results.borrow_mut();
             let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap();
             for import_id in pick.import_ids {
-                debug!("resolve_fully_qualified_call: used_trait_import: {:?}", import_id);
+                debug!(used_trait_import=?import_id);
                 used_trait_imports.insert(import_id);
             }
         }
 
         let def_kind = pick.item.kind.as_def_kind();
-        debug!(
-            "resolve_fully_qualified_call: def_kind={:?}, def_id={:?}",
-            def_kind, pick.item.def_id
-        );
         tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span));
         Ok((def_kind, pick.item.def_id))
     }
index d9870060a40bbb974922ac85bce1f00c9d21f838..e9f55ab3406f5df2ea9bc49c8e34985b479c36df 100644 (file)
@@ -253,7 +253,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// would result in an error (basically, the same criteria we
     /// would use to decide if a method is a plausible fit for
     /// ambiguity purposes).
-    #[instrument(level = "debug", skip(self, scope_expr_id))]
+    #[instrument(level = "debug", skip(self))]
     pub fn probe_for_return_type(
         &self,
         span: Span,
@@ -262,10 +262,6 @@ pub fn probe_for_return_type(
         self_ty: Ty<'tcx>,
         scope_expr_id: hir::HirId,
     ) -> Vec<ty::AssocItem> {
-        debug!(
-            "probe(self_ty={:?}, return_type={}, scope_expr_id={})",
-            self_ty, return_type, scope_expr_id
-        );
         let method_names = self
             .probe_op(
                 span,
@@ -299,7 +295,7 @@ pub fn probe_for_return_type(
             .collect()
     }
 
-    #[instrument(level = "debug", skip(self, scope_expr_id))]
+    #[instrument(level = "debug", skip(self))]
     pub fn probe_for_name(
         &self,
         span: Span,
@@ -310,10 +306,6 @@ pub fn probe_for_name(
         scope_expr_id: hir::HirId,
         scope: ProbeScope,
     ) -> PickResult<'tcx> {
-        debug!(
-            "probe(self_ty={:?}, item_name={}, scope_expr_id={})",
-            self_ty, item_name, scope_expr_id
-        );
         self.probe_op(
             span,
             mode,
index 8bb8c7ac51559c6ae164c2c5c6ad3c622bfb4c80..e99782fdc652c5e668064787420e8a96b4d70890 100644 (file)
@@ -31,7 +31,7 @@
 use std::iter;
 
 use super::probe::{Mode, ProbeScope};
-use super::{super::suggest_call_constructor, CandidateSource, MethodError, NoMatchData};
+use super::{CandidateSource, MethodError, NoMatchData};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
@@ -363,44 +363,21 @@ pub fn report_method_error(
                     );
                 }
 
-                if self.is_fn_ty(rcvr_ty, span) {
-                    if let SelfSource::MethodCall(expr) = source {
-                        let suggest = if let ty::FnDef(def_id, _) = rcvr_ty.kind() {
-                            if let Some(local_id) = def_id.as_local() {
-                                let hir_id = tcx.hir().local_def_id_to_hir_id(local_id);
-                                let node = tcx.hir().get(hir_id);
-                                let fields = node.tuple_fields();
-                                if let Some(fields) = fields
-                                    && let Some(DefKind::Ctor(of, _)) = self.tcx.opt_def_kind(local_id) {
-                                        Some((fields.len(), of))
-                                } else {
-                                    None
-                                }
-                            } else {
-                                // The logic here isn't smart but `associated_item_def_ids`
-                                // doesn't work nicely on local.
-                                if let DefKind::Ctor(of, _) = tcx.def_kind(def_id) {
-                                    let parent_def_id = tcx.parent(*def_id);
-                                    Some((tcx.associated_item_def_ids(parent_def_id).len(), of))
-                                } else {
-                                    None
-                                }
-                            }
-                        } else {
-                            None
-                        };
-
-                        // If the function is a tuple constructor, we recommend that they call it
-                        if let Some((fields, kind)) = suggest {
-                            suggest_call_constructor(expr.span, kind, fields, &mut err);
-                        } else {
-                            // General case
-                            err.span_label(
-                                expr.span,
-                                "this is a function, perhaps you wish to call it",
-                            );
-                        }
-                    }
+                if let SelfSource::MethodCall(rcvr_expr) = source {
+                    self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
+                        let call_expr = self
+                            .tcx
+                            .hir()
+                            .expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id));
+                        let probe = self.lookup_probe(
+                            span,
+                            item_name,
+                            output_ty,
+                            call_expr,
+                            ProbeScope::AllTraits,
+                        );
+                        probe.is_ok()
+                    });
                 }
 
                 let mut custom_span_label = false;
@@ -1350,42 +1327,68 @@ fn check_for_field_method(
         item_name: Ident,
     ) {
         if let SelfSource::MethodCall(expr) = source
-            && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
-            && let Some((fields, substs)) = self.get_field_candidates_considering_privacy(span, actual, mod_id)
+        && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
+        && let Some((fields, substs)) =
+            self.get_field_candidates_considering_privacy(span, actual, mod_id)
         {
             let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-            for candidate_field in fields {
-                if let Some(field_path) = self.check_for_nested_field_satisfying(
-                    span,
-                    &|_, field_ty| {
-                        self.lookup_probe(
-                            span,
-                            item_name,
-                            field_ty,
-                            call_expr,
-                            ProbeScope::AllTraits,
-                        )
-                        .is_ok()
-                    },
-                    candidate_field,
-                    substs,
-                    vec![],
-                    mod_id,
-                ) {
-                    let field_path_str = field_path
+
+            let lang_items = self.tcx.lang_items();
+            let never_mention_traits = [
+                lang_items.clone_trait(),
+                lang_items.deref_trait(),
+                lang_items.deref_mut_trait(),
+                self.tcx.get_diagnostic_item(sym::AsRef),
+                self.tcx.get_diagnostic_item(sym::AsMut),
+                self.tcx.get_diagnostic_item(sym::Borrow),
+                self.tcx.get_diagnostic_item(sym::BorrowMut),
+            ];
+            let candidate_fields: Vec<_> = fields
+                .filter_map(|candidate_field| {
+                    self.check_for_nested_field_satisfying(
+                        span,
+                        &|_, field_ty| {
+                            self.lookup_probe(
+                                span,
+                                item_name,
+                                field_ty,
+                                call_expr,
+                                ProbeScope::TraitsInScope,
+                            )
+                            .map_or(false, |pick| {
+                                !never_mention_traits
+                                    .iter()
+                                    .flatten()
+                                    .any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id)
+                            })
+                        },
+                        candidate_field,
+                        substs,
+                        vec![],
+                        mod_id,
+                    )
+                })
+                .map(|field_path| {
+                    field_path
                         .iter()
                         .map(|id| id.name.to_ident_string())
                         .collect::<Vec<String>>()
-                        .join(".");
-                    debug!("field_path_str: {:?}", field_path_str);
-
-                    err.span_suggestion_verbose(
-                        item_name.span.shrink_to_lo(),
-                        "one of the expressions' fields has a method of the same name",
-                        format!("{field_path_str}."),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
+                        .join(".")
+                })
+                .collect();
+
+            let len = candidate_fields.len();
+            if len > 0 {
+                err.span_suggestions(
+                    item_name.span.shrink_to_lo(),
+                    format!(
+                        "{} of the expressions' fields {} a method of the same name",
+                        if len > 1 { "some" } else { "one" },
+                        if len > 1 { "have" } else { "has" },
+                    ),
+                    candidate_fields.iter().map(|path| format!("{path}.")),
+                    Applicability::MaybeIncorrect,
+                );
             }
         }
     }
index fb675212e3ffb4607215ddc7ff0f9003f2e63e87..69eb34b5f802d25b6f5073377be737bf91893b7f 100644 (file)
@@ -96,7 +96,6 @@
 pub use diverges::Diverges;
 pub use expectation::Expectation;
 pub use fn_ctxt::*;
-use hir::def::CtorOf;
 pub use inherited::{Inherited, InheritedBuilder};
 
 use crate::astconv::AstConv;
@@ -342,7 +341,6 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T
     typeck_with_fallback(tcx, def_id, fallback)
 }
 
-#[instrument(skip(tcx, fallback))]
 fn typeck_with_fallback<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
@@ -466,6 +464,11 @@ fn typeck_with_fallback<'tcx>(
         fcx.resolve_rvalue_scopes(def_id.to_def_id());
         fcx.resolve_generator_interiors(def_id.to_def_id());
 
+        for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
+            let ty = fcx.normalize_ty(span, ty);
+            fcx.require_type_is_sized(ty, span, code);
+        }
+
         fcx.select_all_obligations_or_error();
 
         if !fcx.infcx.is_tainted_by_errors() {
@@ -542,13 +545,13 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
     // For the wasm32 target statics with `#[link_section]` are placed into custom
     // sections of the final output file, but this isn't link custom sections of
     // other executable formats. Namely we can only embed a list of bytes,
-    // nothing with pointers to anything else or relocations. If any relocation
-    // show up, reject them here.
+    // nothing with provenance (pointers to anything else). If any provenance
+    // show up, reject it here.
     // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
     // the consumer's responsibility to ensure all bytes that have been read
     // have defined values.
     if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
-        && alloc.inner().relocations().len() != 0
+        && alloc.inner().provenance().len() != 0
     {
         let msg = "statics with a custom `#[link_section]` must be a \
                         simple list of bytes on the wasm target with no \
@@ -960,31 +963,3 @@ fn has_expected_num_generic_args<'tcx>(
         generics.count() == expected + if generics.has_self { 1 } else { 0 }
     })
 }
-
-/// Suggests calling the constructor of a tuple struct or enum variant
-///
-/// * `snippet` - The snippet of code that references the constructor
-/// * `span` - The span of the snippet
-/// * `params` - The number of parameters the constructor accepts
-/// * `err` - A mutable diagnostic builder to add the suggestion to
-fn suggest_call_constructor(span: Span, kind: CtorOf, params: usize, err: &mut Diagnostic) {
-    // Note: tuple-structs don't have named fields, so just use placeholders
-    let args = vec!["_"; params].join(", ");
-    let applicable = if params > 0 {
-        Applicability::HasPlaceholders
-    } else {
-        // When n = 0, it's an empty-tuple struct/enum variant
-        // so we trivially know how to construct it
-        Applicability::MachineApplicable
-    };
-    let kind = match kind {
-        CtorOf::Struct => "a struct",
-        CtorOf::Variant => "an enum variant",
-    };
-    err.span_label(span, &format!("this is the constructor of {kind}"));
-    err.multipart_suggestion(
-        "call the constructor",
-        vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), format!(")({args})"))],
-        applicable,
-    );
-}
index eb0c51bb2f9795052a3c7eac68668edeed476e31..952086e898fc70011fa22d1a19402c0bfab75bb5 100644 (file)
@@ -410,26 +410,8 @@ fn check_overloaded_binop(
                         };
                         let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "{message}");
                         if !lhs_expr.span.eq(&rhs_expr.span) {
-                            self.add_type_neq_err_label(
-                                &mut err,
-                                lhs_expr.span,
-                                lhs_ty,
-                                rhs_ty,
-                                rhs_expr,
-                                op,
-                                is_assign,
-                                expected,
-                            );
-                            self.add_type_neq_err_label(
-                                &mut err,
-                                rhs_expr.span,
-                                rhs_ty,
-                                lhs_ty,
-                                lhs_expr,
-                                op,
-                                is_assign,
-                                expected,
-                            );
+                            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)
@@ -468,17 +450,50 @@ fn check_overloaded_binop(
                     }
                 };
 
+                let is_compatible = |lhs_ty, rhs_ty| {
+                    self.lookup_op_method(
+                        lhs_ty,
+                        Some(rhs_ty),
+                        Some(rhs_expr),
+                        Op::Binary(op, is_assign),
+                        expected,
+                    )
+                    .is_ok()
+                };
+
                 // We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
                 // `a += b` => `*a += b` if a is a mut ref.
-                if is_assign == IsAssign::Yes
-                    && let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
-                        suggest_deref_binop(lhs_deref_ty);
+                if !op.span.can_be_used_for_suggestions() {
+                    // Suppress suggestions when lhs and rhs are not in the same span as the error
+                } else if is_assign == IsAssign::Yes
+                    && let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty)
+                {
+                    suggest_deref_binop(lhs_deref_ty);
                 } else if is_assign == IsAssign::No
-                    && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() {
-                    if self.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) {
+                    && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind()
+                {
+                    if self.type_is_copy_modulo_regions(
+                        self.param_env,
+                        *lhs_deref_ty,
+                        lhs_expr.span,
+                    ) {
                         suggest_deref_binop(*lhs_deref_ty);
                     }
+                } else if self.suggest_fn_call(&mut err, lhs_expr, lhs_ty, |lhs_ty| {
+                    is_compatible(lhs_ty, rhs_ty)
+                }) || self.suggest_fn_call(&mut err, rhs_expr, rhs_ty, |rhs_ty| {
+                    is_compatible(lhs_ty, rhs_ty)
+                }) || self.suggest_two_fn_call(
+                    &mut err,
+                    rhs_expr,
+                    rhs_ty,
+                    lhs_expr,
+                    lhs_ty,
+                    |lhs_ty, rhs_ty| is_compatible(lhs_ty, rhs_ty),
+                ) {
+                    // Cool
                 }
+
                 if let Some(missing_trait) = missing_trait {
                     let mut visitor = TypeParamVisitor(vec![]);
                     visitor.visit_ty(lhs_ty);
@@ -548,69 +563,6 @@ fn check_overloaded_binop(
         (lhs_ty, rhs_ty, return_ty)
     }
 
-    /// If one of the types is an uncalled function and calling it would yield the other type,
-    /// suggest calling the function. Returns `true` if suggestion would apply (even if not given).
-    fn add_type_neq_err_label(
-        &self,
-        err: &mut Diagnostic,
-        span: Span,
-        ty: Ty<'tcx>,
-        other_ty: Ty<'tcx>,
-        other_expr: &'tcx hir::Expr<'tcx>,
-        op: hir::BinOp,
-        is_assign: IsAssign,
-        expected: Expectation<'tcx>,
-    ) -> bool /* did we suggest to call a function because of missing parentheses? */ {
-        err.span_label(span, ty.to_string());
-        if let FnDef(def_id, _) = *ty.kind() {
-            if !self.tcx.has_typeck_results(def_id) {
-                return false;
-            }
-            // FIXME: Instead of exiting early when encountering bound vars in
-            // the function signature, consider keeping the binder here and
-            // propagating it downwards.
-            let Some(fn_sig) = self.tcx.fn_sig(def_id).no_bound_vars() else {
-                return false;
-            };
-
-            let other_ty = if let FnDef(def_id, _) = *other_ty.kind() {
-                if !self.tcx.has_typeck_results(def_id) {
-                    return false;
-                }
-                // We're emitting a suggestion, so we can just ignore regions
-                self.tcx.fn_sig(def_id).skip_binder().output()
-            } else {
-                other_ty
-            };
-
-            if self
-                .lookup_op_method(
-                    fn_sig.output(),
-                    Some(other_ty),
-                    Some(other_expr),
-                    Op::Binary(op, is_assign),
-                    expected,
-                )
-                .is_ok()
-            {
-                let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() {
-                    ("( /* arguments */ )", Applicability::HasPlaceholders)
-                } else {
-                    ("()", Applicability::MaybeIncorrect)
-                };
-
-                err.span_suggestion_verbose(
-                    span.shrink_to_hi(),
-                    "you might have forgotten to call this function",
-                    variable_snippet,
-                    applicability,
-                );
-                return true;
-            }
-        }
-        false
-    }
-
     /// Provide actionable suggestions when trying to add two strings with incorrect types,
     /// like `&str + &str`, `String + String` and `&str + &String`.
     ///
index ce42647c837a54844f8f621668c376ad1e149862..86cf12d224047a664cef7b1942e4da58b09f64fd 100644 (file)
@@ -972,7 +972,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
     }
 }
 
-#[tracing::instrument(level = "debug", skip(tcx, span, sig_if_method))]
+#[instrument(level = "debug", skip(tcx, span, sig_if_method))]
 fn check_associated_item(
     tcx: TyCtxt<'_>,
     item_id: LocalDefId,
@@ -1225,7 +1225,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo
     });
 }
 
-#[tracing::instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))]
+#[instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))]
 fn check_impl<'tcx>(
     tcx: TyCtxt<'tcx>,
     item: &'tcx hir::Item<'tcx>,
@@ -1262,7 +1262,11 @@ fn check_impl<'tcx>(
             }
             None => {
                 let self_ty = tcx.type_of(item.def_id);
-                let self_ty = wfcx.normalize(item.span, None, self_ty);
+                let self_ty = wfcx.normalize(
+                    item.span,
+                    Some(WellFormedLoc::Ty(item.hir_id().expect_owner())),
+                    self_ty,
+                );
                 wfcx.register_wf_obligation(
                     ast_self_ty.span,
                     Some(WellFormedLoc::Ty(item.hir_id().expect_owner())),
@@ -1307,7 +1311,11 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
                     // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
                     // be sure if it will error or not as user might always specify the other.
                     if !ty.needs_subst() {
-                        wfcx.register_wf_obligation(tcx.def_span(param.def_id), None, ty.into());
+                        wfcx.register_wf_obligation(
+                            tcx.def_span(param.def_id),
+                            Some(WellFormedLoc::Ty(param.def_id.expect_local())),
+                            ty.into(),
+                        );
                     }
                 }
             }
@@ -1464,7 +1472,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
     wfcx.register_obligations(obligations);
 }
 
-#[tracing::instrument(level = "debug", skip(wfcx, span, hir_decl))]
+#[instrument(level = "debug", skip(wfcx, span, hir_decl))]
 fn check_fn_or_method<'tcx>(
     wfcx: &WfCheckingCtxt<'_, 'tcx>,
     span: Span,
@@ -1512,7 +1520,14 @@ fn check_fn_or_method<'tcx>(
         );
     }
 
-    wfcx.register_wf_obligation(hir_decl.output.span(), None, sig.output().into());
+    wfcx.register_wf_obligation(
+        hir_decl.output.span(),
+        Some(WellFormedLoc::Param {
+            function: def_id,
+            param_idx: sig.inputs().len().try_into().unwrap(),
+        }),
+        sig.output().into(),
+    );
 
     check_where_clauses(wfcx, span, def_id);
 }
@@ -1521,7 +1536,7 @@ fn check_fn_or_method<'tcx>(
      `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one \
      of the previous types except `Self`)";
 
-#[tracing::instrument(level = "debug", skip(wfcx))]
+#[instrument(level = "debug", skip(wfcx))]
 fn check_method_receiver<'tcx>(
     wfcx: &WfCheckingCtxt<'_, 'tcx>,
     fn_sig: &hir::FnSig<'_>,
index ba687bc4da4cc6ae9d736fe11d255829ebcec859..9ecf34e9ad3e71ac81b187cf6fded98962d1e86a 100644 (file)
@@ -501,7 +501,7 @@ fn visit_user_provided_tys(&mut self) {
 
         if !errors_buffer.is_empty() {
             errors_buffer.sort_by_key(|diag| diag.span.primary_span());
-            for mut diag in errors_buffer.drain(..) {
+            for mut diag in errors_buffer {
                 self.tcx().sess.diagnostic().emit_diagnostic(&mut diag);
             }
         }
index 2467a81638f75bfa0828c61473d9cfde368154a3..d08c0d4dbb72a6b5d12db254d92945dbca97d6bb 100644 (file)
@@ -359,7 +359,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
     let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
 
     let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| {
-        tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
+        tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err.to_string()));
     });
 
     let source = tcx.type_of(impl_did);
index 970b39dc845afbf65225a1b1e966068ef052fa5f..6236ad370df60e1bcd30a14c92b70a2fbd498dac 100644 (file)
@@ -1617,7 +1617,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                         pure_wrt_drop: false,
                         kind: ty::GenericParamDefKind::Type {
                             has_default: false,
-                            object_lifetime_default: rl::Set1::Empty,
                             synthetic: false,
                         },
                     });
@@ -1661,8 +1660,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
         kind: ty::GenericParamDefKind::Lifetime,
     }));
 
-    let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id.owner);
-
     // Now create the real type and const parameters.
     let type_start = own_start - has_self as u32 + params.len() as u32;
     let mut i = 0;
@@ -1687,13 +1684,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                 }
             }
 
-            let kind = ty::GenericParamDefKind::Type {
-                has_default: default.is_some(),
-                object_lifetime_default: object_lifetime_defaults
-                    .as_ref()
-                    .map_or(rl::Set1::Empty, |o| o[i]),
-                synthetic,
-            };
+            let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
 
             let param_def = ty::GenericParamDef {
                 index: type_start + i as u32,
@@ -1745,11 +1736,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             name: Symbol::intern(arg),
             def_id,
             pure_wrt_drop: false,
-            kind: ty::GenericParamDefKind::Type {
-                has_default: false,
-                object_lifetime_default: rl::Set1::Empty,
-                synthetic: false,
-            },
+            kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
         }));
     }
 
@@ -1762,11 +1749,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                 name: Symbol::intern("<const_ty>"),
                 def_id,
                 pure_wrt_drop: false,
-                kind: ty::GenericParamDefKind::Type {
-                    has_default: false,
-                    object_lifetime_default: rl::Set1::Empty,
-                    synthetic: false,
-                },
+                kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
             });
         }
     }
index f1dbe64f13abbb33e3cb4a323abb015be0288489..9f931de6fdedb674b11b6fff3724a49c5b4a361a 100644 (file)
@@ -19,7 +19,6 @@
 /// Computes the relevant generic parameter for a potential generic const argument.
 ///
 /// This should be called using the query `tcx.opt_const_param_of`.
-#[instrument(level = "debug", skip(tcx))]
 pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
     use hir::*;
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
index 2214fc2ced883f357835baf1f417276d69169dd5..14c0558cdde9362fb52dea2cb6ea0054ad9d977a 100644 (file)
@@ -195,7 +195,7 @@ pub struct AddressOfTemporaryTaken {
 }
 
 #[derive(SessionSubdiagnostic)]
-pub enum AddReturnTypeSuggestion<'tcx> {
+pub enum AddReturnTypeSuggestion {
     #[suggestion(
         typeck::add_return_type_add,
         code = "-> {found} ",
@@ -204,7 +204,7 @@ pub enum AddReturnTypeSuggestion<'tcx> {
     Add {
         #[primary_span]
         span: Span,
-        found: Ty<'tcx>,
+        found: String,
     },
     #[suggestion(
         typeck::add_return_type_missing_here,
index 74a5b6e42c30a8a417dce88f60b75322227c08b5..bfc4f061b70f492f7ebfced4da35d8353328e9aa 100644 (file)
@@ -497,7 +497,7 @@ fn walk_local<F>(
         let expr_place = return_if_err!(self.mc.cat_expr(expr));
         f(self);
         if let Some(els) = els {
-            // borrowing because we need to test the descriminant
+            // borrowing because we need to test the discriminant
             self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter());
             self.walk_block(els)
         }
index fd9715e6ca37481b7f6b038a5838a2ba465abec8..7b080dc2942e06afb03b6642821be02055e5a6cc 100644 (file)
@@ -140,6 +140,10 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
             hir::Node::ForeignItem(ForeignItem {
                 kind: ForeignItemKind::Static(ty, _), ..
             }) => Some(*ty),
+            hir::Node::GenericParam(hir::GenericParam {
+                kind: hir::GenericParamKind::Type { default: Some(ty), .. },
+                ..
+            }) => Some(*ty),
             ref node => bug!("Unexpected node {:?}", node),
         },
         WellFormedLoc::Param { function: _, param_idx } => {
index 5699f642bafa946eff9b7e12c4e9ebc0bb8e0bd6..ac66819d2836f03fbd508c9c47c565da9ddc17eb 100644 (file)
@@ -65,6 +65,7 @@
 #![feature(is_sorted)]
 #![feature(iter_intersperse)]
 #![cfg_attr(bootstrap, feature(label_break_value))]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(never_type)]
@@ -443,7 +444,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
 
 fn check_for_entry_fn(tcx: TyCtxt<'_>) {
     match tcx.entry_fn(()) {
-        Some((def_id, EntryFnType::Main)) => check_main_fn_ty(tcx, def_id),
+        Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id),
         Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
         _ => {}
     }
index 6aa1c915542e24bccfbbbdf69771827eddef9854..d4b5e5e2fe44df3e917c11a7d97d9fb72929e067 100644 (file)
@@ -523,6 +523,7 @@ fn suggest(&self, err: &mut Diagnostic) {
                 if self.not_enough_args_provided() {
                     self.suggest_adding_args(err);
                 } else if self.too_many_args_provided() {
+                    self.suggest_moving_args_from_assoc_fn_to_trait(err);
                     self.suggest_removing_args_or_generics(err);
                 } else {
                     unreachable!();
@@ -653,6 +654,123 @@ fn suggest_adding_type_and_const_args(&self, err: &mut Diagnostic) {
         }
     }
 
+    /// Suggests moving redundant argument(s) of an associate function to the
+    /// trait it belongs to.
+    ///
+    /// ```compile_fail
+    /// Into::into::<Option<_>>(42) // suggests considering `Into::<Option<_>>::into(42)`
+    /// ```
+    fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut Diagnostic) {
+        let trait_ = match self.tcx.trait_of_item(self.def_id) {
+            Some(def_id) => def_id,
+            None => return,
+        };
+
+        // Skip suggestion when the associated function is itself generic, it is unclear
+        // how to split the provided parameters between those to suggest to the trait and
+        // those to remain on the associated type.
+        let num_assoc_fn_expected_args =
+            self.num_expected_type_or_const_args() + self.num_expected_lifetime_args();
+        if num_assoc_fn_expected_args > 0 {
+            return;
+        }
+
+        let num_assoc_fn_excess_args =
+            self.num_excess_type_or_const_args() + self.num_excess_lifetime_args();
+
+        let trait_generics = self.tcx.generics_of(trait_);
+        let num_trait_generics_except_self =
+            trait_generics.count() - if trait_generics.has_self { 1 } else { 0 };
+
+        let msg = format!(
+            "consider moving {these} generic argument{s} to the `{name}` trait, which takes up to {num} argument{s}",
+            these = pluralize!("this", num_assoc_fn_excess_args),
+            s = pluralize!(num_assoc_fn_excess_args),
+            name = self.tcx.item_name(trait_),
+            num = num_trait_generics_except_self,
+        );
+
+        if let Some(hir_id) = self.path_segment.hir_id
+        && let Some(parent_node) = self.tcx.hir().find_parent_node(hir_id)
+        && let Some(parent_node) = self.tcx.hir().find(parent_node)
+        && let hir::Node::Expr(expr) = parent_node {
+            match expr.kind {
+                hir::ExprKind::Path(ref qpath) => {
+                    self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
+                        err,
+                        qpath,
+                        msg,
+                        num_assoc_fn_excess_args,
+                        num_trait_generics_except_self
+                    )
+                },
+                hir::ExprKind::MethodCall(..) => {
+                    self.suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
+                        err,
+                        trait_,
+                        expr,
+                        msg,
+                        num_assoc_fn_excess_args,
+                        num_trait_generics_except_self
+                    )
+                },
+                _ => return,
+            }
+        }
+    }
+
+    fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
+        &self,
+        err: &mut Diagnostic,
+        qpath: &'tcx hir::QPath<'tcx>,
+        msg: String,
+        num_assoc_fn_excess_args: usize,
+        num_trait_generics_except_self: usize,
+    ) {
+        if let hir::QPath::Resolved(_, path) = qpath
+        && let Some(trait_path_segment) = path.segments.get(0) {
+            let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params();
+
+            if num_assoc_fn_excess_args == num_trait_generics_except_self - num_generic_args_supplied_to_trait {
+                if let Some(span) = self.gen_args.span_ext()
+                && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+                    let sugg = vec![
+                        (self.path_segment.ident.span, format!("{}::{}", snippet, self.path_segment.ident)),
+                        (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned())
+                    ];
+
+                    err.multipart_suggestion(
+                        msg,
+                        sugg,
+                        Applicability::MaybeIncorrect
+                    );
+                }
+            }
+        }
+    }
+
+    fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
+        &self,
+        err: &mut Diagnostic,
+        trait_: DefId,
+        expr: &'tcx hir::Expr<'tcx>,
+        msg: String,
+        num_assoc_fn_excess_args: usize,
+        num_trait_generics_except_self: usize,
+    ) {
+        if let hir::ExprKind::MethodCall(_, args, _) = expr.kind {
+            assert_eq!(args.len(), 1);
+            if num_assoc_fn_excess_args == num_trait_generics_except_self {
+                if let Some(gen_args) = self.gen_args.span_ext()
+                && let Ok(gen_args) = self.tcx.sess.source_map().span_to_snippet(gen_args)
+                && let Ok(args) = self.tcx.sess.source_map().span_to_snippet(args[0].span) {
+                    let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), args);
+                    err.span_suggestion(expr.span, msg, sugg, Applicability::MaybeIncorrect);
+                }
+            }
+        }
+    }
+
     /// Suggests to remove redundant argument(s):
     ///
     /// ```text
index b320cdcc109ddc061fec4a33b2fea4b379ed89e3..a967d881b029b7facb6af929d2d18c3fc6bc6d93 100644 (file)
@@ -666,6 +666,10 @@ changelog-seen = 2
 # target.
 #llvm-config = <none> (path)
 
+# Override detection of whether this is a Rust-patched LLVM. This would be used
+# in conjunction with either an llvm-config or build.submodules = false.
+#llvm-has-rust-patches = if llvm-config { false } else { true }
+
 # Normally the build system can find LLVM's FileCheck utility, but if
 # not, you can specify an explicit file name for it.
 #llvm-filecheck = "/path/to/llvm-version/bin/FileCheck"
index e21c8aa3bd536d1fa4ecfda330f82df66f8985e1..6480fcaf93d4ee5754d74c01fea9cfec49822b33 100644 (file)
@@ -1570,7 +1570,7 @@ pub fn split_before(&mut self) -> LinkedList<T> {
     /// that the cursor points to is unchanged, even if it is the "ghost" node.
     ///
     /// This operation should compute in *O*(1) time.
-    // `push_front` continues to point to "ghost" when it addes a node to mimic
+    // `push_front` continues to point to "ghost" when it adds a node to mimic
     // the behavior of `insert_before` on an empty list.
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn push_front(&mut self, elt: T) {
index 5cdee0bd4da492fb082151f98ee1633672262105..5b73906a1c97c125961240910511ae13ac521d86 100644 (file)
@@ -1,7 +1,7 @@
 use crate::alloc::{Allocator, Global};
 use core::fmt;
 use core::iter::{FusedIterator, TrustedLen};
-use core::mem;
+use core::mem::{self, ManuallyDrop};
 use core::ptr::{self, NonNull};
 use core::slice::{self};
 
@@ -65,6 +65,77 @@ pub fn as_slice(&self) -> &[T] {
     pub fn allocator(&self) -> &A {
         unsafe { self.vec.as_ref().allocator() }
     }
+
+    /// Keep unyielded elements in the source `Vec`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(drain_keep_rest)]
+    ///
+    /// let mut vec = vec!['a', 'b', 'c'];
+    /// let mut drain = vec.drain(..);
+    ///
+    /// assert_eq!(drain.next().unwrap(), 'a');
+    ///
+    /// // This call keeps 'b' and 'c' in the vec.
+    /// drain.keep_rest();
+    ///
+    /// // If we wouldn't call `keep_rest()`,
+    /// // `vec` would be empty.
+    /// assert_eq!(vec, ['b', 'c']);
+    /// ```
+    #[unstable(feature = "drain_keep_rest", issue = "101122")]
+    pub fn keep_rest(self) {
+        // At this moment layout looks like this:
+        //
+        // [head] [yielded by next] [unyielded] [yielded by next_back] [tail]
+        //        ^-- start         \_________/-- unyielded_len        \____/-- self.tail_len
+        //                          ^-- unyielded_ptr                  ^-- tail
+        //
+        // Normally `Drop` impl would drop [unyielded] and then move [tail] to the `start`.
+        // Here we want to
+        // 1. Move [unyielded] to `start`
+        // 2. Move [tail] to a new start at `start + len(unyielded)`
+        // 3. Update length of the original vec to `len(head) + len(unyielded) + len(tail)`
+        //    a. In case of ZST, this is the only thing we want to do
+        // 4. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
+        let mut this = ManuallyDrop::new(self);
+
+        unsafe {
+            let source_vec = this.vec.as_mut();
+
+            let start = source_vec.len();
+            let tail = this.tail_start;
+
+            let unyielded_len = this.iter.len();
+            let unyielded_ptr = this.iter.as_slice().as_ptr();
+
+            // ZSTs have no identity, so we don't need to move them around.
+            let needs_move = mem::size_of::<T>() != 0;
+
+            if needs_move {
+                let start_ptr = source_vec.as_mut_ptr().add(start);
+
+                // memmove back unyielded elements
+                if unyielded_ptr != start_ptr {
+                    let src = unyielded_ptr;
+                    let dst = start_ptr;
+
+                    ptr::copy(src, dst, unyielded_len);
+                }
+
+                // memmove back untouched tail
+                if tail != (start + unyielded_len) {
+                    let src = source_vec.as_ptr().add(tail);
+                    let dst = start_ptr.add(unyielded_len);
+                    ptr::copy(src, dst, this.tail_len);
+                }
+            }
+
+            source_vec.set_len(start + unyielded_len + this.tail_len);
+        }
+    }
 }
 
 #[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
index 3c37c92ae44b0cbdbe68a8c0cea948afbaa352ef..8c03f1692d940643a1bd1cad768e44112120b3cf 100644 (file)
@@ -1,6 +1,7 @@
 use crate::alloc::{Allocator, Global};
-use core::ptr::{self};
-use core::slice::{self};
+use core::mem::{self, ManuallyDrop};
+use core::ptr;
+use core::slice;
 
 use super::Vec;
 
@@ -54,6 +55,61 @@ impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
     pub fn allocator(&self) -> &A {
         self.vec.allocator()
     }
+
+    /// Keep unyielded elements in the source `Vec`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(drain_filter)]
+    /// #![feature(drain_keep_rest)]
+    ///
+    /// let mut vec = vec!['a', 'b', 'c'];
+    /// let mut drain = vec.drain_filter(|_| true);
+    ///
+    /// assert_eq!(drain.next().unwrap(), 'a');
+    ///
+    /// // This call keeps 'b' and 'c' in the vec.
+    /// drain.keep_rest();
+    ///
+    /// // If we wouldn't call `keep_rest()`,
+    /// // `vec` would be empty.
+    /// assert_eq!(vec, ['b', 'c']);
+    /// ```
+    #[unstable(feature = "drain_keep_rest", issue = "101122")]
+    pub fn keep_rest(self) {
+        // At this moment layout looks like this:
+        //
+        //  _____________________/-- old_len
+        // /                     \
+        // [kept] [yielded] [tail]
+        //        \_______/ ^-- idx
+        //                \-- del
+        //
+        // Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`)
+        //
+        // 1. Move [tail] after [kept]
+        // 2. Update length of the original vec to `old_len - del`
+        //    a. In case of ZST, this is the only thing we want to do
+        // 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
+        let mut this = ManuallyDrop::new(self);
+
+        unsafe {
+            // ZSTs have no identity, so we don't need to move them around.
+            let needs_move = mem::size_of::<T>() != 0;
+
+            if needs_move && this.idx < this.old_len && this.del > 0 {
+                let ptr = this.vec.as_mut_ptr();
+                let src = ptr.add(this.idx);
+                let dst = src.sub(this.del);
+                let tail_len = this.old_len - this.idx;
+                src.copy_to(dst, tail_len);
+            }
+
+            let new_len = this.old_len - this.del;
+            this.vec.set_len(new_len);
+        }
+    }
 }
 
 #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
index 4351548811d2eb9a0ab594cfbce590fb8747cd38..b4157fd58954103340dfb9fb85f33fc7a3b4a9fc 100644 (file)
@@ -4,7 +4,6 @@
 use crate::raw_vec::RawVec;
 use core::array;
 use core::fmt;
-use core::intrinsics::arith_offset;
 use core::iter::{
     FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
 };
@@ -154,7 +153,7 @@ fn next(&mut self) -> Option<T> {
             // purposefully don't use 'ptr.offset' because for
             // vectors with 0-size elements this would return the
             // same pointer.
-            self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T };
+            self.ptr = self.ptr.wrapping_byte_add(1);
 
             // Make up a value of this ZST.
             Some(unsafe { mem::zeroed() })
@@ -184,7 +183,7 @@ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
             // SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound
             // effectively results in unsigned pointers representing positions 0..usize::MAX,
             // which is valid for ZSTs.
-            self.ptr = unsafe { arith_offset(self.ptr as *const i8, step_size as isize) as *mut T }
+            self.ptr = self.ptr.wrapping_byte_add(step_size);
         } else {
             // SAFETY: the min() above ensures that step_size is in bounds
             self.ptr = unsafe { self.ptr.add(step_size) };
@@ -217,7 +216,7 @@ fn count(self) -> usize {
                 return Err(unsafe { array::IntoIter::new_unchecked(raw_ary, 0..len) });
             }
 
-            self.ptr = unsafe { arith_offset(self.ptr as *const i8, N as isize) as *mut T };
+            self.ptr = self.ptr.wrapping_byte_add(N);
             // Safety: ditto
             return Ok(unsafe { MaybeUninit::array_assume_init(raw_ary) });
         }
@@ -267,7 +266,7 @@ fn next_back(&mut self) -> Option<T> {
             None
         } else if mem::size_of::<T>() == 0 {
             // See above for why 'ptr.offset' isn't used
-            self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T };
+            self.end = self.end.wrapping_byte_sub(1);
 
             // Make up a value of this ZST.
             Some(unsafe { mem::zeroed() })
@@ -283,9 +282,7 @@ fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
         let step_size = self.len().min(n);
         if mem::size_of::<T>() == 0 {
             // SAFETY: same as for advance_by()
-            self.end = unsafe {
-                arith_offset(self.end as *const i8, step_size.wrapping_neg() as isize) as *mut T
-            }
+            self.end = self.end.wrapping_byte_sub(step_size);
         } else {
             // SAFETY: same as for advance_by()
             self.end = unsafe { self.end.sub(step_size) };
index 2c786fd511eada2e8a1f96cb708b1e62e7f2a51d..60b36af5e67fcce6af2b855242c0b6e48d2ffe5a 100644 (file)
@@ -59,7 +59,7 @@
 use core::convert::TryFrom;
 use core::fmt;
 use core::hash::{Hash, Hasher};
-use core::intrinsics::{arith_offset, assume};
+use core::intrinsics::assume;
 use core::iter;
 #[cfg(not(no_global_oom_handling))]
 use core::iter::FromIterator;
@@ -436,7 +436,7 @@ pub const fn new() -> Self {
     /// an explanation of the difference between length and capacity, see
     /// *[Capacity and reallocation]*.
     ///
-    /// If it is imporant to know the exact allocated capacity of a `Vec`,
+    /// If it is important to know the exact allocated capacity of a `Vec`,
     /// always use the [`capacity`] method after construction.
     ///
     /// For `Vec<T>` where `T` is a zero-sized type, there will be no allocation
@@ -591,7 +591,7 @@ pub const fn new_in(alloc: A) -> Self {
     /// an explanation of the difference between length and capacity, see
     /// *[Capacity and reallocation]*.
     ///
-    /// If it is imporant to know the exact allocated capacity of a `Vec`,
+    /// If it is important to know the exact allocated capacity of a `Vec`,
     /// always use the [`capacity`] method after construction.
     ///
     /// For `Vec<T, A>` where `T` is a zero-sized type, there will be no allocation
@@ -2678,7 +2678,7 @@ fn into_iter(self) -> IntoIter<T, A> {
             let alloc = ManuallyDrop::new(ptr::read(me.allocator()));
             let begin = me.as_mut_ptr();
             let end = if mem::size_of::<T>() == 0 {
-                arith_offset(begin as *const i8, me.len() as isize) as *const T
+                begin.wrapping_byte_add(me.len())
             } else {
                 begin.add(me.len()) as *const T
             };
index 99bfb2a45ed90434fc79f63d492ed539313bb330..490c0d8f76cdaf64860e6972bd93b28b010596ae 100644 (file)
@@ -44,6 +44,7 @@
 #![feature(bench_black_box)]
 #![feature(strict_provenance)]
 #![feature(once_cell)]
+#![feature(drain_keep_rest)]
 
 use std::collections::hash_map::DefaultHasher;
 use std::hash::{Hash, Hasher};
index 5be4d5f1279e555de2cc1ad125e1fdfc82c4bd22..f140fc4143f3f50c37b54a24cf8357e2b01d90d8 100644 (file)
@@ -839,6 +839,36 @@ fn drop(&mut self) {
     assert_eq!(v, vec![D(0, false), D(1, false), D(6, false),]);
 }
 
+#[test]
+fn test_drain_keep_rest() {
+    let mut v = vec![0, 1, 2, 3, 4, 5, 6];
+    let mut drain = v.drain(1..6);
+    assert_eq!(drain.next(), Some(1));
+    assert_eq!(drain.next_back(), Some(5));
+    assert_eq!(drain.next(), Some(2));
+
+    drain.keep_rest();
+    assert_eq!(v, &[0, 3, 4, 6]);
+}
+
+#[test]
+fn test_drain_keep_rest_all() {
+    let mut v = vec![0, 1, 2, 3, 4, 5, 6];
+    v.drain(1..6).keep_rest();
+    assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6]);
+}
+
+#[test]
+fn test_drain_keep_rest_none() {
+    let mut v = vec![0, 1, 2, 3, 4, 5, 6];
+    let mut drain = v.drain(1..6);
+
+    drain.by_ref().for_each(drop);
+
+    drain.keep_rest();
+    assert_eq!(v, &[0, 6]);
+}
+
 #[test]
 fn test_splice() {
     let mut v = vec![1, 2, 3, 4, 5];
@@ -1074,6 +1104,12 @@ unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
     assert_eq!(drop_count, 2);
 }
 
+#[test]
+fn test_into_iter_zst() {
+    for _ in vec![[0u64; 0]].into_iter() {}
+    for _ in vec![[0u64; 0]; 5].into_iter().rev() {}
+}
+
 #[test]
 fn test_from_iter_specialization() {
     let src: Vec<usize> = vec![0usize; 1];
@@ -1533,6 +1569,35 @@ fn drain_filter_unconsumed() {
     assert_eq!(vec, [2, 4]);
 }
 
+#[test]
+fn test_drain_filter_keep_rest() {
+    let mut v = vec![0, 1, 2, 3, 4, 5, 6];
+    let mut drain = v.drain_filter(|&mut x| x % 2 == 0);
+    assert_eq!(drain.next(), Some(0));
+    assert_eq!(drain.next(), Some(2));
+
+    drain.keep_rest();
+    assert_eq!(v, &[1, 3, 4, 5, 6]);
+}
+
+#[test]
+fn test_drain_filter_keep_rest_all() {
+    let mut v = vec![0, 1, 2, 3, 4, 5, 6];
+    v.drain_filter(|_| true).keep_rest();
+    assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6]);
+}
+
+#[test]
+fn test_drain_filter_keep_rest_none() {
+    let mut v = vec![0, 1, 2, 3, 4, 5, 6];
+    let mut drain = v.drain_filter(|_| true);
+
+    drain.by_ref().for_each(drop);
+
+    drain.keep_rest();
+    assert_eq!(v, &[]);
+}
+
 #[test]
 fn test_reserve_exact() {
     // This is all the same as test_reserve
index e54f6c912d5945eacdc096a27c4b5b52222a6575..1a379ecc11c01d7ae8cdfde75d8a591425eaa2ca 100644 (file)
@@ -796,7 +796,7 @@ pub trait Provider {
     /// impl Provider for SomeConcreteType {
     ///     fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
     ///         demand.provide_ref::<str>(&self.field)
-    ///             .provide_value::<i32>(|| self.num_field);
+    ///             .provide_value::<i32>(self.num_field);
     ///     }
     /// }
     /// ```
@@ -881,28 +881,55 @@ fn new<'b>(erased: &'b mut (dyn Erased<'a> + 'a)) -> &'b mut Demand<'a> {
     ///
     /// # Examples
     ///
+    /// Provides an `u8`.
+    ///
+    /// ```rust
+    /// #![feature(provide_any)]
+    ///
+    /// use std::any::{Provider, Demand};
+    /// # struct SomeConcreteType { field: u8 }
+    ///
+    /// impl Provider for SomeConcreteType {
+    ///     fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+    ///         demand.provide_value::<u8>(self.field);
+    ///     }
+    /// }
+    /// ```
+    #[unstable(feature = "provide_any", issue = "96024")]
+    pub fn provide_value<T>(&mut self, value: T) -> &mut Self
+    where
+        T: 'static,
+    {
+        self.provide::<tags::Value<T>>(value)
+    }
+
+    /// Provide a value or other type with only static lifetimes computed using a closure.
+    ///
+    /// # Examples
+    ///
     /// Provides a `String` by cloning.
     ///
     /// ```rust
-    /// # #![feature(provide_any)]
+    /// #![feature(provide_any)]
+    ///
     /// use std::any::{Provider, Demand};
     /// # struct SomeConcreteType { field: String }
     ///
     /// impl Provider for SomeConcreteType {
     ///     fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
-    ///         demand.provide_value::<String>(|| self.field.clone());
+    ///         demand.provide_value_with::<String>(|| self.field.clone());
     ///     }
     /// }
     /// ```
     #[unstable(feature = "provide_any", issue = "96024")]
-    pub fn provide_value<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self
+    pub fn provide_value_with<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self
     where
         T: 'static,
     {
         self.provide_with::<tags::Value<T>>(fulfil)
     }
 
-    /// Provide a reference, note that the referee type must be bounded by `'static`,
+    /// Provide a reference. The referee type must be bounded by `'static`,
     /// but may be unsized.
     ///
     /// # Examples
@@ -910,7 +937,8 @@ pub fn provide_value<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self
     /// Provides a reference to a field as a `&str`.
     ///
     /// ```rust
-    /// # #![feature(provide_any)]
+    /// #![feature(provide_any)]
+    ///
     /// use std::any::{Provider, Demand};
     /// # struct SomeConcreteType { field: String }
     ///
@@ -925,6 +953,40 @@ pub fn provide_ref<T: ?Sized + 'static>(&mut self, value: &'a T) -> &mut Self {
         self.provide::<tags::Ref<tags::MaybeSizedValue<T>>>(value)
     }
 
+    /// Provide a reference computed using a closure. The referee type
+    /// must be bounded by `'static`, but may be unsized.
+    ///
+    /// # Examples
+    ///
+    /// Provides a reference to a field as a `&str`.
+    ///
+    /// ```rust
+    /// #![feature(provide_any)]
+    ///
+    /// use std::any::{Provider, Demand};
+    /// # struct SomeConcreteType { business: String, party: String }
+    /// # fn today_is_a_weekday() -> bool { true }
+    ///
+    /// impl Provider for SomeConcreteType {
+    ///     fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+    ///         demand.provide_ref_with::<str>(|| {
+    ///             if today_is_a_weekday() {
+    ///                 &self.business
+    ///             } else {
+    ///                 &self.party
+    ///             }
+    ///         });
+    ///     }
+    /// }
+    /// ```
+    #[unstable(feature = "provide_any", issue = "96024")]
+    pub fn provide_ref_with<T: ?Sized + 'static>(
+        &mut self,
+        fulfil: impl FnOnce() -> &'a T,
+    ) -> &mut Self {
+        self.provide_with::<tags::Ref<tags::MaybeSizedValue<T>>>(fulfil)
+    }
+
     /// Provide a value with the given `Type` tag.
     fn provide<I>(&mut self, value: I::Reified) -> &mut Self
     where
@@ -946,6 +1008,156 @@ fn provide_with<I>(&mut self, fulfil: impl FnOnce() -> I::Reified) -> &mut Self
         }
         self
     }
+
+    /// Check if the `Demand` would be satisfied if provided with a
+    /// value of the specified type. If the type does not match or has
+    /// already been provided, returns false.
+    ///
+    /// # Examples
+    ///
+    /// Check if an `u8` still needs to be provided and then provides
+    /// it.
+    ///
+    /// ```rust
+    /// #![feature(provide_any)]
+    ///
+    /// use std::any::{Provider, Demand};
+    ///
+    /// struct Parent(Option<u8>);
+    ///
+    /// impl Provider for Parent {
+    ///     fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+    ///         if let Some(v) = self.0 {
+    ///             demand.provide_value::<u8>(v);
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// struct Child {
+    ///     parent: Parent,
+    /// }
+    ///
+    /// impl Child {
+    ///     // Pretend that this takes a lot of resources to evaluate.
+    ///     fn an_expensive_computation(&self) -> Option<u8> {
+    ///         Some(99)
+    ///     }
+    /// }
+    ///
+    /// impl Provider for Child {
+    ///     fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+    ///         // In general, we don't know if this call will provide
+    ///         // an `u8` value or not...
+    ///         self.parent.provide(demand);
+    ///
+    ///         // ...so we check to see if the `u8` is needed before
+    ///         // we run our expensive computation.
+    ///         if demand.would_be_satisfied_by_value_of::<u8>() {
+    ///             if let Some(v) = self.an_expensive_computation() {
+    ///                 demand.provide_value::<u8>(v);
+    ///             }
+    ///         }
+    ///
+    ///         // The demand will be satisfied now, regardless of if
+    ///         // the parent provided the value or we did.
+    ///         assert!(!demand.would_be_satisfied_by_value_of::<u8>());
+    ///     }
+    /// }
+    ///
+    /// let parent = Parent(Some(42));
+    /// let child = Child { parent };
+    /// assert_eq!(Some(42), std::any::request_value::<u8>(&child));
+    ///
+    /// let parent = Parent(None);
+    /// let child = Child { parent };
+    /// assert_eq!(Some(99), std::any::request_value::<u8>(&child));
+    /// ```
+    #[unstable(feature = "provide_any", issue = "96024")]
+    pub fn would_be_satisfied_by_value_of<T>(&self) -> bool
+    where
+        T: 'static,
+    {
+        self.would_be_satisfied_by::<tags::Value<T>>()
+    }
+
+    /// Check if the `Demand` would be satisfied if provided with a
+    /// reference to a value of the specified type. If the type does
+    /// not match or has already been provided, returns false.
+    ///
+    /// # Examples
+    ///
+    /// Check if a `&str` still needs to be provided and then provides
+    /// it.
+    ///
+    /// ```rust
+    /// #![feature(provide_any)]
+    ///
+    /// use std::any::{Provider, Demand};
+    ///
+    /// struct Parent(Option<String>);
+    ///
+    /// impl Provider for Parent {
+    ///     fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+    ///         if let Some(v) = &self.0 {
+    ///             demand.provide_ref::<str>(v);
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// struct Child {
+    ///     parent: Parent,
+    ///     name: String,
+    /// }
+    ///
+    /// impl Child {
+    ///     // Pretend that this takes a lot of resources to evaluate.
+    ///     fn an_expensive_computation(&self) -> Option<&str> {
+    ///         Some(&self.name)
+    ///     }
+    /// }
+    ///
+    /// impl Provider for Child {
+    ///     fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+    ///         // In general, we don't know if this call will provide
+    ///         // a `str` reference or not...
+    ///         self.parent.provide(demand);
+    ///
+    ///         // ...so we check to see if the `&str` is needed before
+    ///         // we run our expensive computation.
+    ///         if demand.would_be_satisfied_by_ref_of::<str>() {
+    ///             if let Some(v) = self.an_expensive_computation() {
+    ///                 demand.provide_ref::<str>(v);
+    ///             }
+    ///         }
+    ///
+    ///         // The demand will be satisfied now, regardless of if
+    ///         // the parent provided the reference or we did.
+    ///         assert!(!demand.would_be_satisfied_by_ref_of::<str>());
+    ///     }
+    /// }
+    ///
+    /// let parent = Parent(Some("parent".into()));
+    /// let child = Child { parent, name: "child".into() };
+    /// assert_eq!(Some("parent"), std::any::request_ref::<str>(&child));
+    ///
+    /// let parent = Parent(None);
+    /// let child = Child { parent, name: "child".into() };
+    /// assert_eq!(Some("child"), std::any::request_ref::<str>(&child));
+    /// ```
+    #[unstable(feature = "provide_any", issue = "96024")]
+    pub fn would_be_satisfied_by_ref_of<T>(&self) -> bool
+    where
+        T: ?Sized + 'static,
+    {
+        self.would_be_satisfied_by::<tags::Ref<tags::MaybeSizedValue<T>>>()
+    }
+
+    fn would_be_satisfied_by<I>(&self) -> bool
+    where
+        I: tags::Type<'a>,
+    {
+        matches!(self.0.downcast::<I>(), Some(TaggedOption(None)))
+    }
 }
 
 #[unstable(feature = "provide_any", issue = "96024")]
@@ -1050,6 +1262,21 @@ impl<'a> dyn Erased<'a> + 'a {
     /// Returns some reference to the dynamic value if it is tagged with `I`,
     /// or `None` otherwise.
     #[inline]
+    fn downcast<I>(&self) -> Option<&TaggedOption<'a, I>>
+    where
+        I: tags::Type<'a>,
+    {
+        if self.tag_id() == TypeId::of::<I>() {
+            // SAFETY: Just checked whether we're pointing to an I.
+            Some(unsafe { &*(self as *const Self).cast::<TaggedOption<'a, I>>() })
+        } else {
+            None
+        }
+    }
+
+    /// Returns some mutable reference to the dynamic value if it is tagged with `I`,
+    /// or `None` otherwise.
+    #[inline]
     fn downcast_mut<I>(&mut self) -> Option<&mut TaggedOption<'a, I>>
     where
         I: tags::Type<'a>,
index 32d1a4e55083428dee2923730ce162130a63bb94..7da49b04aaae99cd51f8c48cc6a15296b7283061 100644 (file)
@@ -28,24 +28,14 @@ fn wrap<'slot, 'fmt: 'buf + 'slot>(
 }
 
 impl fmt::Write for PadAdapter<'_, '_> {
-    fn write_str(&mut self, mut s: &str) -> fmt::Result {
-        while !s.is_empty() {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        for s in s.split_inclusive('\n') {
             if self.state.on_newline {
                 self.buf.write_str("    ")?;
             }
 
-            let split = match s.find('\n') {
-                Some(pos) => {
-                    self.state.on_newline = true;
-                    pos + 1
-                }
-                None => {
-                    self.state.on_newline = false;
-                    s.len()
-                }
-            };
-            self.buf.write_str(&s[..split])?;
-            s = &s[split..];
+            self.state.on_newline = s.ends_with('\n');
+            self.buf.write_str(s)?;
         }
 
         Ok(())
index 81b6d5737ea753d9dd867e3a97f37fba3a22b5c9..20340d42962efbbf1caf5fd8bb06f4b6515d1b91 100644 (file)
@@ -31,7 +31,7 @@
 ///
 /// `unreachable_unchecked()` can be used in situations where the compiler
 /// can't prove invariants that were previously established. Such situations
-/// have a higher chance of occuring if those invariants are upheld by
+/// have a higher chance of occurring if those invariants are upheld by
 /// external code that the compiler can't analyze.
 /// ```
 /// fn prepare_inputs(divisors: &mut Vec<u32>) {
index 5f8e6efa0cf5fd1c4c21fed8c7d193c2f6caaadc..d610f0a02f40310d8b1090e65395c432ce141fd9 100644 (file)
@@ -1082,7 +1082,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined
     /// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave
     /// as expected -- this is touching on many unspecified aspects of the Rust memory model.
-    /// Depending on what the code is doing, the following alternatives are preferrable to
+    /// Depending on what the code is doing, the following alternatives are preferable to
     /// pointer-to-integer transmutation:
     /// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a
     ///   type for that buffer, it can use [`MaybeUninit`][mem::MaybeUninit].
index 0bd9c8e9acfcb7424908c1ee8a041e2ff108a256..b37e9142d889638edab0c77462b117fad07d5493 100644 (file)
@@ -350,10 +350,12 @@ macro_rules! matches {
 
 /// Unwraps a result or propagates its error.
 ///
-/// The `?` operator was added to replace `try!` and should be used instead.
-/// Furthermore, `try` is a reserved word in Rust 2018, so if you must use
-/// it, you will need to use the [raw-identifier syntax][ris]: `r#try`.
+/// The [`?` operator][propagating-errors] was added to replace `try!`
+/// and should be used instead. Furthermore, `try` is a reserved word
+/// in Rust 2018, so if you must use it, you will need to use the
+/// [raw-identifier syntax][ris]: `r#try`.
 ///
+/// [propagating-errors]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
 /// [ris]: https://doc.rust-lang.org/nightly/rust-by-example/compatibility/raw_identifiers.html
 ///
 /// `try!` matches the given [`Result`]. In case of the `Ok` variant, the
index 997494c769ec7eabe630cdaabba62eb54b919a50..2490c07679dd0f60940898a1d806c1ef08714a81 100644 (file)
@@ -54,9 +54,6 @@
 /// // The equivalent code with `MaybeUninit<i32>`:
 /// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️
 /// ```
-/// (Notice that the rules around uninitialized integers are not finalized yet, but
-/// until they are, it is advisable to avoid them.)
-///
 /// On top of that, remember that most types have additional invariants beyond merely
 /// being considered initialized at the type level. For example, a `1`-initialized [`Vec<T>`]
 /// is considered initialized (under the current implementation; this does not constitute
index 20b2d5e2681c23f611466b44f2e54da0db93210a..d2dd2941d590f42c08f65e0a1a7a81a55c8e9c1b 100644 (file)
@@ -665,14 +665,14 @@ pub unsafe fn zeroed<T>() -> T {
 /// correctly: it has the same effect as [`MaybeUninit::uninit().assume_init()`][uninit].
 /// As the [`assume_init` documentation][assume_init] explains,
 /// [the Rust compiler assumes][inv] that values are properly initialized.
-/// As a consequence, calling e.g. `mem::uninitialized::<bool>()` causes immediate
-/// undefined behavior for returning a `bool` that is not definitely either `true`
-/// or `false`. Worse, truly uninitialized memory like what gets returned here
+///
+/// Truly uninitialized memory like what gets returned here
 /// is special in that the compiler knows that it does not have a fixed value.
 /// This makes it undefined behavior to have uninitialized data in a variable even
 /// if that variable has an integer type.
-/// (Notice that the rules around uninitialized integers are not finalized yet, but
-/// until they are, it is advisable to avoid them.)
+///
+/// Therefore, it is immediate undefined behavior to call this function on nearly all types,
+/// including integer types and arrays of integer types, and even if the result is unused.
 ///
 /// [uninit]: MaybeUninit::uninit
 /// [assume_init]: MaybeUninit::assume_init
index 6196c4da4e32928670529a82433ff98baaea50ba..1cf306f2103b4ff02ca0dfdeee6918725054fdf1 100644 (file)
@@ -309,8 +309,8 @@ macro_rules! nonzero_unsigned_operations {
     ( $( $Ty: ident($Int: ident); )+ ) => {
         $(
             impl $Ty {
-                /// Add an unsigned integer to a non-zero value.
-                /// Check for overflow and return [`None`] on overflow
+                /// Adds an unsigned integer to a non-zero value.
+                /// Checks for overflow and returns [`None`] on overflow.
                 /// As a consequence, the result cannot wrap to zero.
                 ///
                 ///
@@ -346,7 +346,7 @@ pub const fn checked_add(self, other: $Int) -> Option<$Ty> {
                     }
                 }
 
-                /// Add an unsigned integer to a non-zero value.
+                /// Adds an unsigned integer to a non-zero value.
                 #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")]
                 ///
                 /// # Examples
@@ -377,7 +377,7 @@ pub const fn saturating_add(self, other: $Int) -> $Ty {
                     unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) }
                 }
 
-                /// Add an unsigned integer to a non-zero value,
+                /// Adds an unsigned integer to a non-zero value,
                 /// assuming overflow cannot occur.
                 /// Overflow is unchecked, and it is undefined behaviour to overflow
                 /// *even if the result would wrap to a non-zero value*.
@@ -409,7 +409,7 @@ pub const fn saturating_add(self, other: $Int) -> $Ty {
                 }
 
                 /// Returns the smallest power of two greater than or equal to n.
-                /// Check for overflow and return [`None`]
+                /// Checks for overflow and returns [`None`]
                 /// if the next power of two is greater than the type’s maximum value.
                 /// As a consequence, the result cannot wrap to zero.
                 ///
@@ -545,7 +545,7 @@ pub const fn abs(self) -> $Ty {
                 }
 
                 /// Checked absolute value.
-                /// Check for overflow and returns [`None`] if
+                /// Checks for overflow and returns [`None`] if
                 #[doc = concat!("`self == ", stringify!($Int), "::MIN`.")]
                 /// The result cannot be zero.
                 ///
@@ -740,8 +740,8 @@ macro_rules! nonzero_unsigned_signed_operations {
     ( $( $signedness:ident $Ty: ident($Int: ty); )+ ) => {
         $(
             impl $Ty {
-                /// Multiply two non-zero integers together.
-                /// Check for overflow and return [`None`] on overflow.
+                /// Multiplies two non-zero integers together.
+                /// Checks for overflow and returns [`None`] on overflow.
                 /// As a consequence, the result cannot wrap to zero.
                 ///
                 /// # Examples
@@ -777,7 +777,7 @@ pub const fn checked_mul(self, other: $Ty) -> Option<$Ty> {
                     }
                 }
 
-                /// Multiply two non-zero integers together.
+                /// Multiplies two non-zero integers together.
                 #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")]
                 ///
                 /// # Examples
@@ -809,7 +809,7 @@ pub const fn saturating_mul(self, other: $Ty) -> $Ty {
                     unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) }
                 }
 
-                /// Multiply two non-zero integers together,
+                /// Multiplies two non-zero integers together,
                 /// assuming overflow cannot occur.
                 /// Overflow is unchecked, and it is undefined behaviour to overflow
                 /// *even if the result would wrap to a non-zero value*.
@@ -849,8 +849,8 @@ pub const fn saturating_mul(self, other: $Ty) -> $Ty {
                     unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) }
                 }
 
-                /// Raise non-zero value to an integer power.
-                /// Check for overflow and return [`None`] on overflow.
+                /// Raises non-zero value to an integer power.
+                /// Checks for overflow and returns [`None`] on overflow.
                 /// As a consequence, the result cannot wrap to zero.
                 ///
                 /// # Examples
index a3b14847342cbcdc4ad9f57e54165ac24b9fb327..728202835818436bcc8e1c05438c548603f091c9 100644 (file)
@@ -677,7 +677,7 @@ pub enum Bound<T> {
 impl<T> Bound<T> {
     /// Converts from `&Bound<T>` to `Bound<&T>`.
     #[inline]
-    #[unstable(feature = "bound_as_ref", issue = "80996")]
+    #[stable(feature = "bound_as_ref_shared", since = "CURRENT_RUSTC_VERSION")]
     pub fn as_ref(&self) -> Bound<&T> {
         match *self {
             Included(ref x) => Included(x),
index 2b2ef64fdb1c3f31cacc27592ee7fc8f43d5d108..242f44ade8a2d121a5ae775d1952e7594204b608 100644 (file)
@@ -1223,7 +1223,7 @@ mod prim_usize {}
 #[doc(alias = "&")]
 #[doc(alias = "&mut")]
 //
-/// References, both shared and mutable.
+/// References, `&T` and `&mut T`.
 ///
 /// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut`
 /// operators on a value, or by using a [`ref`](../std/keyword.ref.html) or
index 3f3eb3b3c5c52f69e2cf7e69d92283e89f0c9817..f5c72d797553450b5c103d6ff05c48e842a2c489 100644 (file)
@@ -154,7 +154,7 @@ pub fn from_bits(bits: usize) -> Self
     /// This is similar to `self as usize`, which semantically discards *provenance* and
     /// *address-space* information. However, unlike `self as usize`, casting the returned address
     /// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To
-    /// properly restore the lost information and obtain a dereferencable pointer, use
+    /// properly restore the lost information and obtain a dereferenceable pointer, use
     /// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
     ///
     /// If using those APIs is not possible because there is no way to preserve a pointer with the
@@ -249,7 +249,7 @@ pub fn with_addr(self, addr: usize) -> Self
         let offset = dest_addr.wrapping_sub(self_addr);
 
         // This is the canonical desugarring of this operation
-        self.cast::<u8>().wrapping_offset(offset).cast::<T>()
+        self.wrapping_byte_offset(offset)
     }
 
     /// Creates a new pointer by mapping `self`'s address to a new one.
index 203531f66aa367e47ea00c1127124a27665b82ae..41a2685d361c805a1696cc39d899f6da3ff76fd1 100644 (file)
@@ -90,7 +90,7 @@
 //! isn't *pointer*-sized but address-space/offset/allocation-sized (we'll probably continue
 //! to conflate these notions). This would potentially make it possible to more efficiently
 //! target platforms where pointers are larger than offsets, such as CHERI and maybe some
-//! segmented architecures.
+//! segmented architectures.
 //!
 //! ## Provenance
 //!
 //! a pointer to a usize is generally an operation which *only* extracts the address. It is
 //! therefore *impossible* to construct a valid pointer from a usize because there is no way
 //! to restore the address-space and provenance. In other words, pointer-integer-pointer
-//! roundtrips are not possible (in the sense that the resulting pointer is not dereferencable).
+//! roundtrips are not possible (in the sense that the resulting pointer is not dereferenceable).
 //!
 //! The key insight to making this model *at all* viable is the [`with_addr`][] method:
 //!
 //!
 //! * Create an invalid pointer from just an address (see [`ptr::invalid`][]). This can
 //!   be used for sentinel values like `null` *or* to represent a tagged pointer that will
-//!   never be dereferencable. In general, it is always sound for an integer to pretend
+//!   never be dereferenceable. In general, it is always sound for an integer to pretend
 //!   to be a pointer "for fun" as long as you don't use operations on it which require
 //!   it to be valid (offset, read, write, etc).
 //!
index 03ee879f7da28808c7c34283a5ef7c0f56b313ae..3e4c3ae07567565da53e13364d3ed28a88890fa5 100644 (file)
@@ -160,7 +160,7 @@ pub fn from_bits(bits: usize) -> Self
     /// This is similar to `self as usize`, which semantically discards *provenance* and
     /// *address-space* information. However, unlike `self as usize`, casting the returned address
     /// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To
-    /// properly restore the lost information and obtain a dereferencable pointer, use
+    /// properly restore the lost information and obtain a dereferenceable pointer, use
     /// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
     ///
     /// If using those APIs is not possible because there is no way to preserve a pointer with the
@@ -255,7 +255,7 @@ pub fn with_addr(self, addr: usize) -> Self
         let offset = dest_addr.wrapping_sub(self_addr);
 
         // This is the canonical desugarring of this operation
-        self.cast::<u8>().wrapping_offset(offset).cast::<T>()
+        self.wrapping_byte_offset(offset)
     }
 
     /// Creates a new pointer by mapping `self`'s address to a new one.
index f43b780ec9a900a18f202d2e8e3cf55a574894d1..395c5678451cdc03841c026eab1932bc19260721 100644 (file)
@@ -2754,10 +2754,10 @@ fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
                 None => 0,
             };
             // SAFETY: This type ensures that self.v is a valid pointer with a correct len.
-            // Therefore the bounds check in split_at_mut guarantess the split point is inbounds.
+            // Therefore the bounds check in split_at_mut guarantees the split point is inbounds.
             let (head, tail) = unsafe { self.v.split_at_mut(start) };
             // SAFETY: This type ensures that self.v is a valid pointer with a correct len.
-            // Therefore the bounds check in split_at_mut guarantess the split point is inbounds.
+            // Therefore the bounds check in split_at_mut guarantees the split point is inbounds.
             let (nth, _) = unsafe { tail.split_at_mut(end - start) };
             self.v = head;
             // SAFETY: Nothing else points to or will point to the contents of this slice.
index c05242222dde7e54c1b4b5477a2efb397073593b..47455760a4bd7f9199185a32d3d15bc68ab7b11a 100644 (file)
@@ -64,7 +64,7 @@ macro_rules! next_back_unchecked {
         // backwards by `n`. `n` must not exceed `self.len()`.
         macro_rules! zst_shrink {
             ($self: ident, $n: ident) => {
-                $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T;
+                $self.end = $self.end.wrapping_byte_offset(-$n);
             }
         }
 
index 38f05f471cde52a81d3057a32875282513ccce8f..1958745b5868c79f240b45087db2c272608503ce 100644 (file)
@@ -1541,7 +1541,7 @@ pub fn group_by_mut<F>(&mut self, pred: F) -> GroupByMut<'_, T, F>
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_slice_split_at_not_mut", issue = "none")]
+    #[rustc_const_unstable(feature = "const_slice_split_at_not_mut", issue = "101158")]
     #[inline]
     #[track_caller]
     #[must_use]
@@ -2321,7 +2321,7 @@ pub fn strip_suffix<P: SlicePattern<Item = T> + ?Sized>(&self, suffix: &P) -> Op
     }
 
     /// Binary searches this slice for a given element.
-    /// This behaves similary to [`contains`] if this slice is sorted.
+    /// This behaves similarly to [`contains`] if this slice is sorted.
     ///
     /// If the value is found then [`Result::Ok`] is returned, containing the
     /// index of the matching element. If there are multiple matches, then any
@@ -3530,7 +3530,7 @@ pub unsafe fn align_to_mut<U>(&mut self) -> (&mut [T], &mut [U], &mut [T]) {
         // alignment targeted for U.
         // `crate::ptr::align_offset` is called with a correctly aligned and
         // valid pointer `ptr` (it comes from a reference to `self`) and with
-        // a size that is a power of two (since it comes from the alignement for U),
+        // a size that is a power of two (since it comes from the alignment for U),
         // satisfying its safety constraints.
         let offset = unsafe { crate::ptr::align_offset(ptr, mem::align_of::<U>()) };
         if offset > self.len() {
index 153dc4dbb0835e02c74493061fe904eb1e65e8fc..4f29ecc0fba8b55c681714dce9a14de126f1ee0b 100644 (file)
@@ -1280,7 +1280,7 @@ macro_rules! try_from_secs {
             let rem_msb = nanos_tmp & rem_msb_mask == 0;
             let add_ns = !(rem_msb || (is_even && is_tie));
 
-            // f32 does not have enough presicion to trigger the second branch
+            // f32 does not have enough precision to trigger the second branch
             // since it can not represent numbers between 0.999_999_940_395 and 1.0.
             let nanos = nanos + add_ns as u32;
             if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) { (0, nanos) } else { (1, 0) }
@@ -1299,9 +1299,9 @@ macro_rules! try_from_secs {
             let rem_msb = nanos_tmp & rem_msb_mask == 0;
             let add_ns = !(rem_msb || (is_even && is_tie));
 
-            // f32 does not have enough presicion to trigger the second branch.
+            // f32 does not have enough precision to trigger the second branch.
             // For example, it can not represent numbers between 1.999_999_880...
-            // and 2.0. Bigger values result in even smaller presicion of the
+            // and 2.0. Bigger values result in even smaller precision of the
             // fractional part.
             let nanos = nanos + add_ns as u32;
             if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) {
index 8ed0c88808fe27fc47d36b4734dae75a0401e11b..9538b81394957be74e188531cb1d9e9b9f4fa9ad 100644 (file)
@@ -142,7 +142,7 @@ fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
         demand
             .provide_ref::<String>(&self.some_string)
             .provide_ref::<str>(&self.some_string)
-            .provide_value::<String>(|| "bye".to_owned());
+            .provide_value_with::<String>(|| "bye".to_owned());
     }
 }
 
index 13b12db209a76ea59415aafb61195d4b9543e376..94b0310603bf41ccd7d16675513a544098e7561e 100644 (file)
@@ -155,7 +155,7 @@ fn ptr_add_data() {
 
     assert_eq!(atom.fetch_ptr_sub(1, SeqCst), n.wrapping_add(1));
     assert_eq!(atom.load(SeqCst), n);
-    let bytes_from_n = |b| n.cast::<u8>().wrapping_add(b).cast::<i64>();
+    let bytes_from_n = |b| n.wrapping_byte_add(b);
 
     assert_eq!(atom.fetch_byte_add(1, SeqCst), n);
     assert_eq!(atom.load(SeqCst), bytes_from_n(1));
index 12861794c2d2c248d50ebcbb41c9c6d3a749dbf3..97a369810056dceefcdef14ad542fe4a0e15fd93 100644 (file)
@@ -650,7 +650,7 @@ pub fn new<Value: std::marker::Unsize<T>>(value: Value) -> Self {
                     .unwrap_or_else(|| handle_alloc_error(layout))
                     .cast::<DynMetadata<T>>();
                 ptr.as_ptr().write(meta);
-                ptr.cast::<u8>().as_ptr().add(offset).cast::<Value>().write(value);
+                ptr.as_ptr().byte_add(offset).cast::<Value>().write(value);
                 Self { ptr, phantom: PhantomData }
             }
         }
index 65d3ce9be65ecfa123585f3b6e9ccedb0ae07d58..2235f016c7144e762a0339bc300d0dd76f0a34ae 100644 (file)
@@ -70,7 +70,7 @@ impl ToBitMask<BitMask=u32> for Mask<_, 32>
     impl ToBitMask<BitMask=u64> for Mask<_, 64>
 }
 
-/// Returns the minimum numnber of bytes in a bitmask with `lanes` lanes.
+/// Returns the minimum number of bytes in a bitmask with `lanes` lanes.
 #[cfg(feature = "generic_const_exprs")]
 pub const fn bitmask_len(lanes: usize) -> usize {
     (lanes + 7) / 8
index 1516f084ab8b65b3db8821f78cc314dd6712cd2b..4461b21802adbeb91709c3c1ce7fb7f35fab604f 100644 (file)
@@ -176,8 +176,6 @@ fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
     FreeFunctions,
     TokenStream,
     SourceFile,
-    MultiSpan,
-    Diagnostic,
 
     'interned:
     Span,
index 5cde966bf173d163efa4130f18ae2180ea21fef8..4c1e196b5ad165c5e679a5a9ffdb0a3c434e1450 100644 (file)
@@ -57,6 +57,7 @@ macro_rules! with_api {
                 fn track_env_var(var: &str, value: Option<&str>);
                 fn track_path(path: &str);
                 fn literal_from_str(s: &str) -> Result<Literal<$S::Span, $S::Symbol>, ()>;
+                fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>);
             },
             TokenStream {
                 fn drop($self: $S::TokenStream);
@@ -87,22 +88,6 @@ fn into_trees(
                 fn path($self: &$S::SourceFile) -> String;
                 fn is_real($self: &$S::SourceFile) -> bool;
             },
-            MultiSpan {
-                fn drop($self: $S::MultiSpan);
-                fn new() -> $S::MultiSpan;
-                fn push($self: &mut $S::MultiSpan, span: $S::Span);
-            },
-            Diagnostic {
-                fn drop($self: $S::Diagnostic);
-                fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic;
-                fn sub(
-                    $self: &mut $S::Diagnostic,
-                    level: Level,
-                    msg: &str,
-                    span: $S::MultiSpan,
-                );
-                fn emit($self: $S::Diagnostic);
-            },
             Span {
                 fn debug($self: $S::Span) -> String;
                 fn source_file($self: $S::Span) -> $S::SourceFile;
@@ -510,6 +495,18 @@ enum TokenTree<TokenStream, Span, Symbol> {
     }
 );
 
+#[derive(Clone, Debug)]
+pub struct Diagnostic<Span> {
+    pub level: Level,
+    pub message: String,
+    pub spans: Vec<Span>,
+    pub children: Vec<Diagnostic<Span>>,
+}
+
+compound_traits!(
+    struct Diagnostic<Span> { level, message, spans, children }
+);
+
 /// Globals provided alongside the initial inputs for a macro expansion.
 /// Provides values such as spans which are used frequently to avoid RPC.
 #[derive(Clone)]
index e068ec60b6af0d654c07db30bf06d39e5fe53173..e47a77f6c1350530e4f985a31701bc0c28c96e39 100644 (file)
@@ -11,8 +11,6 @@ pub trait Types {
     type FreeFunctions: 'static;
     type TokenStream: 'static + Clone;
     type SourceFile: 'static + Clone;
-    type MultiSpan: 'static;
-    type Diagnostic: 'static;
     type Span: 'static + Copy + Eq + Hash;
     type Symbol: 'static;
 }
index 6e46dc0367d07b2dd8dadf6c6e238c81477228f3..5a209f7c7aa1858577d1a4044cb7fddd487f9f54 100644 (file)
@@ -161,22 +161,15 @@ pub fn children(&self) -> Children<'_> {
     /// Emit the diagnostic.
     #[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
     pub fn emit(self) {
-        fn to_internal(spans: Vec<Span>) -> crate::bridge::client::MultiSpan {
-            let mut multi_span = crate::bridge::client::MultiSpan::new();
-            for span in spans {
-                multi_span.push(span.0);
+        fn to_internal(diag: Diagnostic) -> crate::bridge::Diagnostic<crate::bridge::client::Span> {
+            crate::bridge::Diagnostic {
+                level: diag.level,
+                message: diag.message,
+                spans: diag.spans.into_iter().map(|s| s.0).collect(),
+                children: diag.children.into_iter().map(to_internal).collect(),
             }
-            multi_span
         }
 
-        let mut diag = crate::bridge::client::Diagnostic::new(
-            self.level,
-            &self.message[..],
-            to_internal(self.spans),
-        );
-        for c in self.children {
-            diag.sub(c.level, &c.message[..], to_internal(c.spans));
-        }
-        diag.emit();
+        crate::bridge::client::FreeFunctions::emit_diagnostic(to_internal(self));
     }
 }
index abff82788a38dc55d9a8cfbb3b5900c5ea9ac53d..5b6a415fadc1e2a83f737adbbdb6b95522553a7d 100644 (file)
@@ -239,7 +239,7 @@ pub fn is_empty(&self) -> bool {
     ///
     /// If the returned iterator is dropped before being fully consumed, it
     /// drops the remaining elements. The returned iterator keeps a mutable
-    /// borrow on the vector to optimize its implementation.
+    /// borrow on the set to optimize its implementation.
     ///
     /// # Examples
     ///
index e1ab06b0d0f69fc8eb77fc65e838970ce7c191a7..28a2c99f7e5e3e8d2ef77993fc6eb7e09564e5d8 100644 (file)
@@ -377,6 +377,35 @@ pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
         OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
     }
 
+    /// Creates a new file in read-write mode; error if the file exists.
+    ///
+    /// This function will create a file if it does not exist, or return an error if it does. This
+    /// way, if the call succeeds, the file returned is guaranteed to be new.
+    ///
+    /// This option is useful because it is atomic. Otherwise between checking whether a file
+    /// exists and creating a new one, the file may have been created by another process (a TOCTOU
+    /// race condition / attack).
+    ///
+    /// This can also be written using
+    /// `File::options().read(true).write(true).create_new(true).open(...)`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(file_create_new)]
+    ///
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let mut f = File::create_new("foo.txt")?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "file_create_new", issue = "none")]
+    pub fn create_new<P: AsRef<Path>>(path: P) -> io::Result<File> {
+        OpenOptions::new().read(true).write(true).create_new(true).open(path.as_ref())
+    }
+
     /// Returns a new OpenOptions object.
     ///
     /// This function returns a new OpenOptions object that you can use to
index 292bf4826fd237a3d9dafe63b3d9ae1b5deac1d5..781ae03ad45dcb865c66d90b45a6109d28c7fad8 100644 (file)
@@ -269,10 +269,10 @@ unsafe fn decode_repr<C, F>(ptr: NonNull<()>, make_custom: F) -> ErrorData<C>
         }
         TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()),
         TAG_CUSTOM => {
-            // It would be correct for us to use `ptr::sub` here (see the
+            // It would be correct for us to use `ptr::byte_sub` here (see the
             // comment above the `wrapping_add` call in `new_custom` for why),
             // but it isn't clear that it makes a difference, so we don't.
-            let custom = ptr.as_ptr().cast::<u8>().wrapping_sub(TAG_CUSTOM).cast::<Custom>();
+            let custom = ptr.as_ptr().wrapping_byte_sub(TAG_CUSTOM).cast::<Custom>();
             ErrorData::Custom(make_custom(custom))
         }
         _ => {
index a9fa7b0a6aca0699a551c04743cd9bc02dc3c380..01a3873c75cec6c5b81459a8de83740a8297e559 100644 (file)
@@ -1037,8 +1037,6 @@ fn take(self, limit: u64) -> Take<Self>
 /// # Examples
 ///
 /// ```no_run
-/// #![feature(io_read_to_string)]
-///
 /// # use std::io;
 /// fn main() -> io::Result<()> {
 ///     let stdin = io::read_to_string(io::stdin())?;
@@ -1047,7 +1045,7 @@ fn take(self, limit: u64) -> Take<Self>
 ///     Ok(())
 /// }
 /// ```
-#[unstable(feature = "io_read_to_string", issue = "80218")]
+#[stable(feature = "io_read_to_string", since = "CURRENT_RUSTC_VERSION")]
 pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
     let mut buf = String::new();
     reader.read_to_string(&mut buf)?;
index 4d3736f79146c8df36976ba06397e108ef532af7..07239746258d109adb6130bd10b95cafe5d3190b 100644 (file)
@@ -986,10 +986,10 @@ pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> {
 /// otherwise. `label` identifies the stream in a panic message.
 ///
 /// This function is used to print error messages, so it takes extra
-/// care to avoid causing a panic when `local_s` is unusable.
-/// For instance, if the TLS key for the local stream is
-/// already destroyed, or if the local stream is locked by another
-/// thread, it will just fall back to the global stream.
+/// care to avoid causing a panic when `OUTPUT_CAPTURE` is unusable.
+/// For instance, if the TLS key for output capturing is already destroyed, or
+/// if the local stream is in use by another thread, it will just fall back to
+/// the global stream.
 ///
 /// However, if the actual I/O causes an error, this function does panic.
 fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
index 7157b5af00cf48fd1440ec7970b8bd1ef7ca481f..a4b0522b050244b2e4e32e9f7a30afd35e219796 100644 (file)
@@ -1921,7 +1921,7 @@ mod type_keyword {}
 /// and [proposal]s exist to use `unsafe {}` blocks inside such functions when
 /// making `unsafe` operations.
 ///
-/// See the [Rustnomicon] and the [Reference] for more informations.
+/// See the [Rustnomicon] and the [Reference] for more information.
 ///
 /// # Examples
 ///
@@ -2113,7 +2113,7 @@ mod use_keyword {}
 /// Add constraints that must be upheld to use an item.
 ///
 /// `where` allows specifying constraints on lifetime and generic parameters.
-/// The [RFC] introducing `where` contains detailed informations about the
+/// The [RFC] introducing `where` contains detailed information about the
 /// keyword.
 ///
 /// # Examples
@@ -2355,7 +2355,7 @@ mod dyn_keyword {}
 /// println!("f = {f} and i = {i}");
 /// ```
 ///
-/// See the [Reference][union] for more informations on `union`s.
+/// See the [Reference][union] for more information on `union`s.
 ///
 /// [`struct`]: keyword.struct.html
 /// [union]: ../reference/items/unions.html
index f5dcdab4cd570afbaf40ec3c61ac2361fc4b0895..f13500de01431c40a17b1f598730760de46f90d4 100644 (file)
 #![feature(intra_doc_pointers)]
 #![cfg_attr(bootstrap, feature(label_break_value))]
 #![feature(lang_items)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(linkage)]
 #![feature(link_cfg)]
 #![feature(panic_can_unwind)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
+#![feature(pointer_byte_offsets)]
 #![feature(pointer_is_aligned)]
 #![feature(portable_simd)]
 #![feature(prelude_2024)]
index 2b2ef64fdb1c3f31cacc27592ee7fc8f43d5d108..242f44ade8a2d121a5ae775d1952e7594204b608 100644 (file)
@@ -1223,7 +1223,7 @@ mod prim_usize {}
 #[doc(alias = "&")]
 #[doc(alias = "&mut")]
 //
-/// References, both shared and mutable.
+/// References, `&T` and `&mut T`.
 ///
 /// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut`
 /// operators on a value, or by using a [`ref`](../std/keyword.ref.html) or
index 663537a05fa32f91c78545f732ec5837c60daef1..98f6cc7aa3ea152aa424a58f95e15046bf6dbfde 100644 (file)
@@ -72,10 +72,29 @@ macro_rules! rtunwrap {
 // Runs before `main`.
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
+//
+// # The `sigpipe` parameter
+//
+// Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to
+// `SIG_IGN`. Applications have good reasons to want a different behavior
+// though, so there is a `#[unix_sigpipe = "..."]` attribute on `fn main()` that
+// can be used to select how `SIGPIPE` shall be setup (if changed at all) before
+// `fn main()` is called. See <https://github.com/rust-lang/rust/issues/97889>
+// for more info.
+//
+// The `sigpipe` parameter to this function gets its value via the code that
+// rustc generates to invoke `fn lang_start()`. The reason we have `sigpipe` for
+// all platforms and not only Unix, is because std is not allowed to have `cfg`
+// directives as this high level. See the module docs in
+// `src/tools/tidy/src/pal.rs` for more info. On all other platforms, `sigpipe`
+// has a value, but its value is ignored.
+//
+// Even though it is an `u8`, it only ever has 3 values. These are documented in
+// `compiler/rustc_session/src/config/sigpipe.rs`.
 #[cfg_attr(test, allow(dead_code))]
-unsafe fn init(argc: isize, argv: *const *const u8) {
+unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     unsafe {
-        sys::init(argc, argv);
+        sys::init(argc, argv, sigpipe);
 
         let main_guard = sys::thread::guard::init();
         // Next, set up the current Thread with the guard information we just
@@ -107,6 +126,7 @@ fn lang_start_internal(
     main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe),
     argc: isize,
     argv: *const *const u8,
+    sigpipe: u8,
 ) -> Result<isize, !> {
     use crate::{mem, panic};
     let rt_abort = move |e| {
@@ -124,7 +144,7 @@ fn lang_start_internal(
     // prevent libstd from accidentally introducing a panic to these functions. Another is from
     // user code from `main` or, more nefariously, as described in e.g. issue #86030.
     // SAFETY: Only called once during runtime initialization.
-    panic::catch_unwind(move || unsafe { init(argc, argv) }).map_err(rt_abort)?;
+    panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;
     let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
         .map_err(move |e| {
             mem::forget(e);
@@ -140,11 +160,16 @@ fn lang_start<T: crate::process::Termination + 'static>(
     main: fn() -> T,
     argc: isize,
     argv: *const *const u8,
+    #[cfg(not(bootstrap))] sigpipe: u8,
 ) -> isize {
     let Ok(v) = lang_start_internal(
         &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report().to_i32(),
         argc,
         argv,
+        #[cfg(bootstrap)]
+        2, // Temporary inlining of sigpipe::DEFAULT until bootstrap stops being special
+        #[cfg(not(bootstrap))]
+        sigpipe,
     );
     v
 }
index e0d13cd648c64ceeb003da18d1401e02104bccf2..de851c8fbbed51743776477b338dda1677fd925a 100644 (file)
@@ -192,6 +192,7 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
                       and cause Futures to not implement `Send`"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[clippy::has_significant_drop]
+#[cfg_attr(not(test), rustc_diagnostic_item = "MutexGuard")]
 pub struct MutexGuard<'a, T: ?Sized + 'a> {
     lock: &'a Mutex<T>,
     poison: poison::Guard,
index 6e4a2cfc82afd07b80b1efd0d3a2e6a47ce2d35a..9ab781561e9b1280460d858bd36d737bfe5aa7e1 100644 (file)
@@ -101,6 +101,7 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
                       and cause Futures to not implement `Send`"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[clippy::has_significant_drop]
+#[cfg_attr(not(test), rustc_diagnostic_item = "RwLockReadGuard")]
 pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
     // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a
     // `Ref` argument doesn't hold immutability for its whole scope, only until it drops.
@@ -130,6 +131,7 @@ unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {}
                       and cause Future's to not implement `Send`"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[clippy::has_significant_drop]
+#[cfg_attr(not(test), rustc_diagnostic_item = "RwLockWriteGuard")]
 pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
     lock: &'a RwLock<T>,
     poison: poison::Guard,
index 60b7a973cc2c1d7c94a2c66640b6194e6e5b11dd..61da096ae163883f73370305916aea26aa48d8b5 100644 (file)
@@ -98,7 +98,7 @@ pub extern "C" fn __rust_abort() {
 
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(argc: isize, argv: *const *const u8) {
+pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
     let _ = net::init();
     args::init(argc, argv);
 }
index 696400670e04d1f8f543b258602a258191e6158c..b1d32929ecfde469ee9a03ef2c9158f1cbd8a2ac 100644 (file)
@@ -47,7 +47,7 @@ pub mod locks {
 
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(argc: isize, argv: *const *const u8) {
+pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
     unsafe {
         args::init(argc, argv);
     }
index 778a589d1b724434f38d6f90eb51c370039f6027..5867979a2a729408db7b7be74eaf6d68499b5937 100644 (file)
@@ -56,7 +56,7 @@ pub mod locks {
 
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
+pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
 
 // SAFETY: must be called only once during runtime cleanup.
 pub unsafe fn cleanup() {}
index ce427599c3bddc9ace0a1add4647dd8d51521a82..dbb9829bb666dc89cfbc789204c0b654079ffcd4 100644 (file)
@@ -138,7 +138,7 @@ fn lock_contested(&self, mut state: u32, thread_self: zx_handle_t) {
                 }
             }
 
-            // The state has changed or a wakeup occured, try to lock the mutex.
+            // The state has changed or a wakeup occurred, try to lock the mutex.
             match self.futex.compare_exchange(UNLOCKED, owned_state, Acquire, Relaxed) {
                 Ok(_) => return,
                 Err(updated) => state = updated,
index 99ba86e5f996dce0bb445c5e12c99d494b441fcf..1b5be46c6050230aab31e2bad89031ff6517ce13 100644 (file)
@@ -53,7 +53,7 @@ fn lock_contended(&self) {
             // We avoid an unnecessary write if it as already set to 2,
             // to be friendlier for the caches.
             if state != 2 && self.futex.swap(2, Acquire) == 0 {
-                // We changed it from 0 to 2, so we just succesfully locked it.
+                // We changed it from 0 to 2, so we just successfully locked it.
                 return;
             }
 
index b3bbbf743f84c8ac63302b7a7d63cfae43b3bf4c..0cc92244ecad3a195e2eecb5d18a6792ebf5146a 100644 (file)
@@ -54,7 +54,7 @@ fn is_read_lockable(state: u32) -> bool {
     // We don't allow read-locking if there's readers waiting, even if the lock is unlocked
     // and there's no writers waiting. The only situation when this happens is after unlocking,
     // at which point the unlocking thread might be waking up writers, which have priority over readers.
-    // The unlocking thread will clear the readers waiting bit and wake up readers, if necssary.
+    // The unlocking thread will clear the readers waiting bit and wake up readers, if necessary.
     state & MASK < MAX_READERS && !has_readers_waiting(state) && !has_writers_waiting(state)
 }
 
index 3a3750930998509fca767f8decf488a8f30797d5..c84e292eac152b0dd45d65922fedd7aabc39868f 100644 (file)
 pub mod time;
 
 #[cfg(target_os = "espidf")]
-pub fn init(argc: isize, argv: *const *const u8) {}
+pub fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {}
 
 #[cfg(not(target_os = "espidf"))]
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(argc: isize, argv: *const *const u8) {
+// See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`.
+pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     // The standard streams might be closed on application startup. To prevent
     // std::io::{stdin, stdout,stderr} objects from using other unrelated file
     // resources opened later, we reopen standards streams when they are closed.
@@ -61,8 +62,9 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
     // want!
     //
     // Hence, we set SIGPIPE to ignore when the program starts up in order
-    // to prevent this problem.
-    reset_sigpipe();
+    // to prevent this problem. Add `#[unix_sigpipe = "..."]` above `fn main()` to
+    // alter this behavior.
+    reset_sigpipe(sigpipe);
 
     stack_overflow::init();
     args::init(argc, argv);
@@ -151,9 +153,31 @@ unsafe fn sanitize_standard_fds() {
         }
     }
 
-    unsafe fn reset_sigpipe() {
+    unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) {
         #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))]
-        rtassert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
+        {
+            // We don't want to add this as a public type to libstd, nor do we
+            // want to `include!` a file from the compiler (which would break
+            // Miri and xargo for example), so we choose to duplicate these
+            // constants from `compiler/rustc_session/src/config/sigpipe.rs`.
+            // See the other file for docs. NOTE: Make sure to keep them in
+            // sync!
+            mod sigpipe {
+                pub const INHERIT: u8 = 1;
+                pub const SIG_IGN: u8 = 2;
+                pub const SIG_DFL: u8 = 3;
+            }
+
+            let handler = match sigpipe {
+                sigpipe::INHERIT => None,
+                sigpipe::SIG_IGN => Some(libc::SIG_IGN),
+                sigpipe::SIG_DFL => Some(libc::SIG_DFL),
+                _ => unreachable!(),
+            };
+            if let Some(handler) = handler {
+                rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR);
+            }
+        }
     }
 }
 
index a6fe07873d7ee4263b9362d9a5dda75c35916582..40885417308b80a2007591f17af0984a44215831 100644 (file)
@@ -137,11 +137,9 @@ pub fn fill_bytes(v: &mut [u8]) {
     }
 }
 
-#[cfg(target_os = "macos")]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
 mod imp {
-    use crate::fs::File;
-    use crate::io::Read;
-    use crate::sys::os::errno;
+    use crate::io;
     use crate::sys::weak::weak;
     use libc::{c_int, c_void, size_t};
 
@@ -155,7 +153,7 @@ fn getentropy_fill_bytes(v: &mut [u8]) -> bool {
                 for s in v.chunks_mut(256) {
                     let ret = unsafe { f(s.as_mut_ptr() as *mut c_void, s.len()) };
                     if ret == -1 {
-                        panic!("unexpected getentropy error: {}", errno());
+                        panic!("unexpected getentropy error: {}", io::Error::last_os_error());
                     }
                 }
                 true
@@ -163,14 +161,64 @@ fn getentropy_fill_bytes(v: &mut [u8]) -> bool {
             .unwrap_or(false)
     }
 
+    #[cfg(target_os = "macos")]
+    fn fallback_fill_bytes(v: &mut [u8]) {
+        use crate::fs::File;
+        use crate::io::Read;
+
+        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
+        file.read_exact(v).expect("failed to read /dev/urandom")
+    }
+
+    // On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
+    // `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
+    // from `/dev/random` and which runs on its own thread accessed via GCD.
+    //
+    // This is very heavyweight compared to the alternatives, but they may not be usable:
+    // - `getentropy` was added in iOS 10, but we support a minimum of iOS 7
+    // - `/dev/urandom` is not accessible inside the iOS app sandbox.
+    //
+    // Therefore `SecRandomCopyBytes` is only used on older iOS versions where no
+    // better options are present.
+    #[cfg(target_os = "ios")]
+    fn fallback_fill_bytes(v: &mut [u8]) {
+        use crate::ptr;
+
+        enum SecRandom {}
+
+        #[allow(non_upper_case_globals)]
+        const kSecRandomDefault: *const SecRandom = ptr::null();
+
+        extern "C" {
+            fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int;
+        }
+
+        let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) };
+        if ret == -1 {
+            panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
+        }
+    }
+
+    // All supported versions of watchOS (>= 5) have support for `getentropy`.
+    #[cfg(target_os = "watchos")]
+    #[cold]
+    fn fallback_fill_bytes(_: &mut [u8]) {
+        unreachable!()
+    }
+
     pub fn fill_bytes(v: &mut [u8]) {
         if getentropy_fill_bytes(v) {
             return;
         }
 
-        // for older macos which doesn't support getentropy
-        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
-        file.read_exact(v).expect("failed to read /dev/urandom")
+        // Older macOS versions (< 10.12) don't support `getentropy`. Fallback to
+        // reading from `/dev/urandom` on these systems.
+        //
+        // Older iOS versions (< 10) don't support it either. Fallback to
+        // `SecRandomCopyBytes` on these systems. On watchOS, this is unreachable
+        // because the minimum supported version is 5 while `getentropy` became accessible
+        // in 3.
+        fallback_fill_bytes(v)
     }
 }
 
@@ -189,36 +237,6 @@ pub fn fill_bytes(v: &mut [u8]) {
     }
 }
 
-// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
-// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
-// from `/dev/random` and which runs on its own thread accessed via GCD.
-// This seems needlessly heavyweight for the purposes of generating two u64s
-// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
-// only used on iOS where direct access to `/dev/urandom` is blocked by the
-// sandbox.
-#[cfg(any(target_os = "ios", target_os = "watchos"))]
-mod imp {
-    use crate::io;
-    use crate::ptr;
-    use libc::{c_int, size_t};
-
-    enum SecRandom {}
-
-    #[allow(non_upper_case_globals)]
-    const kSecRandomDefault: *const SecRandom = ptr::null();
-
-    extern "C" {
-        fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int;
-    }
-
-    pub fn fill_bytes(v: &mut [u8]) {
-        let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) };
-        if ret == -1 {
-            panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
-        }
-    }
-}
-
 #[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
 mod imp {
     use crate::ptr;
index 4c9ade4a8c7906714b84cd6437243a2501ab2d77..5cd9e57de19ee28e4763887b49d108fe7987b44c 100644 (file)
@@ -6,7 +6,7 @@ pub mod memchr {
 
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
+pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
 
 // SAFETY: must be called only once during runtime cleanup.
 // NOTE: this is not guaranteed to run, for example when the program aborts.
index 4cc0e4ed5a45a775f2a9879153fcd31b4e2b526d..d2081771b6ec79d267a9dba2377dc014cfb35a07 100644 (file)
@@ -4,7 +4,7 @@
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::mem::ManuallyDrop;
 use crate::os::raw;
-use crate::os::wasi::io::{AsRawFd, FromRawFd};
+use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd};
 
 pub struct Stdin;
 pub struct Stdout;
@@ -23,6 +23,13 @@ fn as_raw_fd(&self) -> raw::c_int {
     }
 }
 
+impl AsFd for Stdin {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        unsafe { BorrowedFd::borrow_raw(0) }
+    }
+}
+
 impl io::Read for Stdin {
     fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
         self.read_vectored(&mut [IoSliceMut::new(data)])
@@ -51,6 +58,13 @@ fn as_raw_fd(&self) -> raw::c_int {
     }
 }
 
+impl AsFd for Stdout {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        unsafe { BorrowedFd::borrow_raw(1) }
+    }
+}
+
 impl io::Write for Stdout {
     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         self.write_vectored(&[IoSlice::new(data)])
@@ -82,6 +96,13 @@ fn as_raw_fd(&self) -> raw::c_int {
     }
 }
 
+impl AsFd for Stderr {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        unsafe { BorrowedFd::borrow_raw(2) }
+    }
+}
+
 impl io::Write for Stderr {
     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         self.write_vectored(&[IoSlice::new(data)])
index ef3f6a9ba175545c9b10c1a72df432989feb6121..78d6ce3eff493452f934fcec8c23b4d8065bc9d1 100644 (file)
@@ -228,8 +228,6 @@ fn clone(&self) -> Self {
 pub const IPV6_DROP_MEMBERSHIP: c_int = 13;
 pub const MSG_PEEK: c_int = 0x2;
 
-pub const LOAD_LIBRARY_SEARCH_SYSTEM32: u32 = 0x800;
-
 #[repr(C)]
 #[derive(Copy, Clone)]
 pub struct linger {
@@ -287,7 +285,7 @@ pub fn nt_success(status: NTSTATUS) -> bool {
     status >= 0
 }
 
-pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002;
+pub const BCRYPT_RNG_ALG_HANDLE: usize = 0x81;
 
 #[repr(C)]
 pub struct UNICODE_STRING {
@@ -456,6 +454,12 @@ pub enum FILE_INFO_BY_HANDLE_CLASS {
     MaximumFileInfoByHandlesClass,
 }
 
+#[repr(C)]
+pub struct FILE_ATTRIBUTE_TAG_INFO {
+    pub FileAttributes: DWORD,
+    pub ReparseTag: DWORD,
+}
+
 #[repr(C)]
 pub struct FILE_DISPOSITION_INFO {
     pub DeleteFile: BOOLEAN,
@@ -503,6 +507,8 @@ pub struct FILE_END_OF_FILE_INFO {
     pub EndOfFile: LARGE_INTEGER,
 }
 
+/// NB: Use carefully! In general using this as a reference is likely to get the
+/// provenance wrong for the `rest` field!
 #[repr(C)]
 pub struct REPARSE_DATA_BUFFER {
     pub ReparseTag: c_uint,
@@ -511,6 +517,8 @@ pub struct REPARSE_DATA_BUFFER {
     pub rest: (),
 }
 
+/// NB: Use carefully! In general using this as a reference is likely to get the
+/// provenance wrong for the `PathBuffer` field!
 #[repr(C)]
 pub struct SYMBOLIC_LINK_REPARSE_BUFFER {
     pub SubstituteNameOffset: c_ushort,
@@ -521,6 +529,8 @@ pub struct SYMBOLIC_LINK_REPARSE_BUFFER {
     pub PathBuffer: WCHAR,
 }
 
+/// NB: Use carefully! In general using this as a reference is likely to get the
+/// provenance wrong for the `PathBuffer` field!
 #[repr(C)]
 pub struct MOUNT_POINT_REPARSE_BUFFER {
     pub SubstituteNameOffset: c_ushort,
@@ -1032,7 +1042,6 @@ pub fn CreateFileW(
     pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void;
     pub fn GetModuleHandleA(lpModuleName: LPCSTR) -> HMODULE;
     pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
-    pub fn LoadLibraryExA(lplibfilename: *const i8, hfile: HANDLE, dwflags: u32) -> HINSTANCE;
 
     pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
     pub fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO);
index 1a5421facd0c1aba216ebd195b0e72f4800e7560..43ab8c7ee659f5e08d6d7815c27c2d3ff21897c8 100644 (file)
@@ -44,7 +44,7 @@ mod shims {
 }
 
 // On 32-bit x86 MSVC these functions aren't defined, so we just define shims
-// which promote everything fo f64, perform the calculation, and then demote
+// which promote everything to f64, perform the calculation, and then demote
 // back to f32. While not precisely correct should be "correct enough" for now.
 #[cfg(all(target_env = "msvc", target_arch = "x86"))]
 mod shims {
index 9c8ddc3aa1d256f6ecbd43d067b388c54c8129b9..7dff81ecb8ddeebb6e4d938dad632c198727dc78 100644 (file)
 
 use crate::ffi::{c_void, CStr};
 use crate::ptr::NonNull;
-use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::atomic::Ordering;
 use crate::sys::c;
 
+// This uses a static initializer to preload some imported functions.
+// The CRT (C runtime) executes static initializers before `main`
+// is called (for binaries) and before `DllMain` is called (for DLLs).
+//
+// It works by contributing a global symbol to the `.CRT$XCT` section.
+// The linker builds a table of all static initializer functions.
+// The CRT startup code then iterates that table, calling each
+// initializer function.
+//
+// NOTE: User code should instead use .CRT$XCU to reliably run after std's initializer.
+// If you're reading this and would like a guarantee here, please
+// file an issue for discussion; currently we don't guarantee any functionality
+// before main.
+// See https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-170
+#[used]
+#[link_section = ".CRT$XCT"]
+static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init;
+
+/// Preload some imported functions.
+///
+/// Note that any functions included here will be unconditionally loaded in
+/// the final binary, regardless of whether or not they're actually used.
+///
+/// Therefore, this should be limited to `compat_fn_optional` functions which
+/// must be preloaded or any functions where lazier loading demonstrates a
+/// negative performance impact in practical situations.
+///
+/// Currently we only preload `WaitOnAddress` and `WakeByAddressSingle`.
+unsafe extern "C" fn init() {
+    // In an exe this code is executed before main() so is single threaded.
+    // In a DLL the system's loader lock will be held thereby synchronizing
+    // access. So the same best practices apply here as they do to running in DllMain:
+    // https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
+    //
+    // DO NOT do anything interesting or complicated in this function! DO NOT call
+    // any Rust functions or CRT functions if those functions touch any global state,
+    // because this function runs during global initialization. For example, DO NOT
+    // do any dynamic allocation, don't call LoadLibrary, etc.
+
+    // Attempt to preload the synch functions.
+    load_synch_functions();
+}
+
 /// Helper macro for creating CStrs from literals and symbol names.
 macro_rules! ansi_str {
     (sym $ident:ident) => {{
@@ -75,20 +118,6 @@ pub unsafe fn new(name: &CStr) -> Option<Self> {
         NonNull::new(module).map(Self)
     }
 
-    /// Load the library (if not already loaded)
-    ///
-    /// # Safety
-    ///
-    /// The module must not be unloaded.
-    pub unsafe fn load_system_library(name: &CStr) -> Option<Self> {
-        let module = c::LoadLibraryExA(
-            name.as_ptr(),
-            crate::ptr::null_mut(),
-            c::LOAD_LIBRARY_SEARCH_SYSTEM32,
-        );
-        NonNull::new(module).map(Self)
-    }
-
     // Try to get the address of a function.
     pub fn proc_address(self, name: &CStr) -> Option<NonNull<c_void>> {
         // SAFETY:
@@ -182,14 +211,10 @@ pub mod $symbol {
 
                 #[inline(always)]
                 pub fn option() -> Option<F> {
-                    let f = PTR.load(Ordering::Acquire);
-                    if !f.is_null() { Some(unsafe { mem::transmute(f) }) } else { try_load() }
-                }
-
-                #[cold]
-                fn try_load() -> Option<F> {
-                    $load_functions;
-                    NonNull::new(PTR.load(Ordering::Acquire)).map(|f| unsafe { mem::transmute(f) })
+                    // Miri does not understand the way we do preloading
+                    // therefore load the function here instead.
+                    #[cfg(miri)] $load_functions;
+                    NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| unsafe { mem::transmute(f) })
                 }
             }
         )+
@@ -205,17 +230,14 @@ fn try_load() -> Option<()> {
 
         // Try loading the library and all the required functions.
         // If any step fails, then they all fail.
-        let library = unsafe { Module::load_system_library(MODULE_NAME) }?;
+        let library = unsafe { Module::new(MODULE_NAME) }?;
         let wait_on_address = library.proc_address(WAIT_ON_ADDRESS)?;
         let wake_by_address_single = library.proc_address(WAKE_BY_ADDRESS_SINGLE)?;
 
-        c::WaitOnAddress::PTR.store(wait_on_address.as_ptr(), Ordering::Release);
-        c::WakeByAddressSingle::PTR.store(wake_by_address_single.as_ptr(), Ordering::Release);
+        c::WaitOnAddress::PTR.store(wait_on_address.as_ptr(), Ordering::Relaxed);
+        c::WakeByAddressSingle::PTR.store(wake_by_address_single.as_ptr(), Ordering::Relaxed);
         Some(())
     }
 
-    // Try to load the module but skip loading if a previous attempt failed.
-    static LOAD_MODULE: AtomicBool = AtomicBool::new(true);
-    let module_loaded = LOAD_MODULE.load(Ordering::Acquire) && try_load().is_some();
-    LOAD_MODULE.store(module_loaded, Ordering::Release)
+    try_load();
 }
index 9653b1abfc3d88a4bb43ab37385ec5fd7e4da3ee..c2ad592dfea73379ca8a433aab2179307a7f2ab0 100644 (file)
@@ -3,7 +3,7 @@
 use crate::ffi::OsString;
 use crate::fmt;
 use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
-use crate::mem;
+use crate::mem::{self, MaybeUninit};
 use crate::os::windows::io::{AsHandle, BorrowedHandle};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
@@ -11,7 +11,7 @@
 use crate::sync::Arc;
 use crate::sys::handle::Handle;
 use crate::sys::time::SystemTime;
-use crate::sys::{c, cvt};
+use crate::sys::{c, cvt, Align8};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::thread;
 
@@ -326,9 +326,15 @@ pub fn file_attr(&self) -> io::Result<FileAttr> {
             cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?;
             let mut reparse_tag = 0;
             if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
-                let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
-                if let Ok((_, buf)) = self.reparse_point(&mut b) {
-                    reparse_tag = buf.ReparseTag;
+                let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed();
+                cvt(c::GetFileInformationByHandleEx(
+                    self.handle.as_raw_handle(),
+                    c::FileAttributeTagInfo,
+                    ptr::addr_of_mut!(attr_tag).cast(),
+                    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;
                 }
             }
             Ok(FileAttr {
@@ -389,9 +395,15 @@ pub fn file_attr(&self) -> io::Result<FileAttr> {
             attr.file_size = info.AllocationSize as u64;
             attr.number_of_links = Some(info.NumberOfLinks);
             if attr.file_type().is_reparse_point() {
-                let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
-                if let Ok((_, buf)) = self.reparse_point(&mut b) {
-                    attr.reparse_tag = buf.ReparseTag;
+                let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed();
+                cvt(c::GetFileInformationByHandleEx(
+                    self.handle.as_raw_handle(),
+                    c::FileAttributeTagInfo,
+                    ptr::addr_of_mut!(attr_tag).cast(),
+                    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;
                 }
             }
             Ok(attr)
@@ -458,38 +470,46 @@ pub fn duplicate(&self) -> io::Result<File> {
         Ok(Self { handle: self.handle.try_clone()? })
     }
 
-    fn reparse_point<'a>(
+    // NB: returned pointer is derived from `space`, and has provenance to
+    // match. A raw pointer is returned rather than a reference in order to
+    // avoid narrowing provenance to the actual `REPARSE_DATA_BUFFER`.
+    fn reparse_point(
         &self,
-        space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE],
-    ) -> io::Result<(c::DWORD, &'a c::REPARSE_DATA_BUFFER)> {
+        space: &mut Align8<[MaybeUninit<u8>]>,
+    ) -> io::Result<(c::DWORD, *const c::REPARSE_DATA_BUFFER)> {
         unsafe {
             let mut bytes = 0;
             cvt({
+                // Grab this in advance to avoid it invalidating the pointer
+                // we get from `space.0.as_mut_ptr()`.
+                let len = space.0.len();
                 c::DeviceIoControl(
                     self.handle.as_raw_handle(),
                     c::FSCTL_GET_REPARSE_POINT,
                     ptr::null_mut(),
                     0,
-                    space.as_mut_ptr() as *mut _,
-                    space.len() as c::DWORD,
+                    space.0.as_mut_ptr().cast(),
+                    len as c::DWORD,
                     &mut bytes,
                     ptr::null_mut(),
                 )
             })?;
-            Ok((bytes, &*(space.as_ptr() as *const c::REPARSE_DATA_BUFFER)))
+            const _: () = assert!(core::mem::align_of::<c::REPARSE_DATA_BUFFER>() <= 8);
+            Ok((bytes, space.0.as_ptr().cast::<c::REPARSE_DATA_BUFFER>()))
         }
     }
 
     fn readlink(&self) -> io::Result<PathBuf> {
-        let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+        let mut space = Align8([MaybeUninit::<u8>::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
         let (_bytes, buf) = self.reparse_point(&mut space)?;
         unsafe {
-            let (path_buffer, subst_off, subst_len, relative) = match buf.ReparseTag {
+            let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag {
                 c::IO_REPARSE_TAG_SYMLINK => {
                     let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER =
-                        &buf.rest as *const _ as *const _;
+                        ptr::addr_of!((*buf).rest).cast();
+                    assert!(info.is_aligned());
                     (
-                        &(*info).PathBuffer as *const _ as *const u16,
+                        ptr::addr_of!((*info).PathBuffer).cast::<u16>(),
                         (*info).SubstituteNameOffset / 2,
                         (*info).SubstituteNameLength / 2,
                         (*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0,
@@ -497,9 +517,10 @@ fn readlink(&self) -> io::Result<PathBuf> {
                 }
                 c::IO_REPARSE_TAG_MOUNT_POINT => {
                     let info: *const c::MOUNT_POINT_REPARSE_BUFFER =
-                        &buf.rest as *const _ as *const _;
+                        ptr::addr_of!((*buf).rest).cast();
+                    assert!(info.is_aligned());
                     (
-                        &(*info).PathBuffer as *const _ as *const u16,
+                        ptr::addr_of!((*info).PathBuffer).cast::<u16>(),
                         (*info).SubstituteNameOffset / 2,
                         (*info).SubstituteNameLength / 2,
                         false,
@@ -649,27 +670,31 @@ fn fill_dir_buff(&self, buffer: &mut DirBuff, restart: bool) -> io::Result<bool>
 
 /// A buffer for holding directory entries.
 struct DirBuff {
-    buffer: Vec<u8>,
+    buffer: Box<Align8<[MaybeUninit<u8>; Self::BUFFER_SIZE]>>,
 }
 impl DirBuff {
+    const BUFFER_SIZE: usize = 1024;
     fn new() -> Self {
-        const BUFFER_SIZE: usize = 1024;
-        Self { buffer: vec![0_u8; BUFFER_SIZE] }
+        Self {
+            // Safety: `Align8<[MaybeUninit<u8>; N]>` does not need
+            // initialization.
+            buffer: unsafe { Box::new_uninit().assume_init() },
+        }
     }
     fn capacity(&self) -> usize {
-        self.buffer.len()
+        self.buffer.0.len()
     }
     fn as_mut_ptr(&mut self) -> *mut u8 {
-        self.buffer.as_mut_ptr().cast()
+        self.buffer.0.as_mut_ptr().cast()
     }
     /// Returns a `DirBuffIter`.
     fn iter(&self) -> DirBuffIter<'_> {
         DirBuffIter::new(self)
     }
 }
-impl AsRef<[u8]> for DirBuff {
-    fn as_ref(&self) -> &[u8] {
-        &self.buffer
+impl AsRef<[MaybeUninit<u8>]> for DirBuff {
+    fn as_ref(&self) -> &[MaybeUninit<u8>] {
+        &self.buffer.0
     }
 }
 
@@ -677,7 +702,7 @@ fn as_ref(&self) -> &[u8] {
 ///
 /// Currently only returns file names (UTF-16 encoded).
 struct DirBuffIter<'a> {
-    buffer: Option<&'a [u8]>,
+    buffer: Option<&'a [MaybeUninit<u8>]>,
     cursor: usize,
 }
 impl<'a> DirBuffIter<'a> {
@@ -692,14 +717,21 @@ fn next(&mut self) -> Option<Self::Item> {
         let buffer = &self.buffer?[self.cursor..];
 
         // Get the name and next entry from the buffer.
-        // SAFETY: The buffer contains a `FILE_ID_BOTH_DIR_INFO` struct but the
-        // last field (the file name) is unsized. So an offset has to be
-        // used to get the file name slice.
+        // SAFETY:
+        // - The buffer contains a `FILE_ID_BOTH_DIR_INFO` struct but the last
+        //   field (the file name) is unsized. So an offset has to be used to
+        //   get the file name slice.
+        // - The OS has guaranteed initialization of the fields of
+        //   `FILE_ID_BOTH_DIR_INFO` and the trailing filename (for at least
+        //   `FileNameLength` bytes)
         let (name, is_directory, next_entry) = unsafe {
             let info = buffer.as_ptr().cast::<c::FILE_ID_BOTH_DIR_INFO>();
+            // Guaranteed to be aligned in documentation for
+            // https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_both_dir_info
+            assert!(info.is_aligned());
             let next_entry = (*info).NextEntryOffset as usize;
             let name = crate::slice::from_raw_parts(
-                (*info).FileName.as_ptr().cast::<u16>(),
+                ptr::addr_of!((*info).FileName).cast::<u16>(),
                 (*info).FileNameLength as usize / size_of::<u16>(),
             );
             let is_directory = ((*info).FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) != 0;
@@ -1337,9 +1369,10 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
     let h = f.as_inner().as_raw_handle();
 
     unsafe {
-        let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
-        let db = data.as_mut_ptr() as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER;
-        let buf = &mut (*db).ReparseTarget as *mut c::WCHAR;
+        let mut data = Align8([MaybeUninit::<u8>::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
+        let data_ptr = data.0.as_mut_ptr();
+        let db = data_ptr.cast::<c::REPARSE_MOUNTPOINT_DATA_BUFFER>();
+        let buf = ptr::addr_of_mut!((*db).ReparseTarget).cast::<c::WCHAR>();
         let mut i = 0;
         // FIXME: this conversion is very hacky
         let v = br"\??\";
@@ -1359,7 +1392,7 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
         cvt(c::DeviceIoControl(
             h as *mut _,
             c::FSCTL_SET_REPARSE_POINT,
-            data.as_ptr() as *mut _,
+            data_ptr.cast(),
             (*db).ReparseDataLength + 8,
             ptr::null_mut(),
             0,
index a9846a484880befb3e0aca62cb9a91d65bc57bca..eab9b961279c9a60428c97fbdf05b43bff987a30 100644 (file)
@@ -48,7 +48,7 @@
 
 // SAFETY: must be called only once during runtime initialization.
 // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
-pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
     stack_overflow::init();
 
     // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already
@@ -329,3 +329,11 @@ pub fn abort_internal() -> ! {
     }
     crate::intrinsics::abort();
 }
+
+/// Align the inner value to 8 bytes.
+///
+/// This is enough for almost all of the buffers we're likely to work with in
+/// the Windows APIs we use.
+#[repr(C, align(8))]
+#[derive(Copy, Clone)]
+pub(crate) struct Align8<T: ?Sized>(pub T);
index 2f7ec433bf26119fff40524224ca5463aa341d52..a71175069052f0539c8af1b850fc9ad48eee3d7d 100644 (file)
@@ -115,7 +115,7 @@ fn test_parse_prefix_verbatim_device() {
     assert_eq!(prefix, parse_prefix(r"\\?/C:\windows\system32\notepad.exe"));
 }
 
-// See #93586 for more infomation.
+// See #93586 for more information.
 #[test]
 fn test_windows_prefix_components() {
     use crate::path::Path;
index f8fd93a7398e1b75c35d255e30e24447461b9cc4..8b9697884364c837ac44f8308d184ee7ab0eb78d 100644 (file)
@@ -1,16 +1,49 @@
+//! # Random key generation
+//!
+//! This module wraps the RNG provided by the OS. There are a few different
+//! ways to interface with the OS RNG so it's worth exploring each of the options.
+//! Note that at the time of writing these all go through the (undocumented)
+//! `bcryptPrimitives.dll` but they use different route to get there.
+//!
+//! Originally we were using [`RtlGenRandom`], however that function is
+//! deprecated and warns it "may be altered or unavailable in subsequent versions".
+//!
+//! So we switched to [`BCryptGenRandom`] with the `BCRYPT_USE_SYSTEM_PREFERRED_RNG`
+//! flag to query and find the system configured RNG. However, this change caused a small
+//! but significant number of users to experience panics caused by a failure of
+//! this function. See [#94098].
+//!
+//! The current version changes this to use the `BCRYPT_RNG_ALG_HANDLE`
+//! [Pseudo-handle], which gets the default RNG algorithm without querying the
+//! system preference thus hopefully avoiding the previous issue.
+//! This is only supported on Windows 10+ so a fallback is used for older versions.
+//!
+//! [#94098]: https://github.com/rust-lang/rust/issues/94098
+//! [`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;
 
+/// Generates high quality secure random keys for use by [`HashMap`].
+///
+/// This is used to seed the default [`RandomState`].
+///
+/// [`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(
-            ptr::null_mut(),
-            &mut v as *mut _ as *mut u8,
-            mem::size_of_val(&v) as c::ULONG,
-            c::BCRYPT_USE_SYSTEM_PREFERRED_RNG,
+            // 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 }
index a001d6b9858234a79bce1044e4d8c7e49bcf02b6..70c9b14a08fa7f41deea5d3c48580e0269f734b5 100644 (file)
@@ -3,6 +3,7 @@
 use crate::char::decode_utf16;
 use crate::cmp;
 use crate::io;
+use crate::mem::MaybeUninit;
 use crate::os::windows::io::{FromRawHandle, IntoRawHandle};
 use crate::ptr;
 use crate::str;
@@ -169,13 +170,14 @@ fn write(
 }
 
 fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usize> {
-    let mut utf16 = [0u16; MAX_BUFFER_SIZE / 2];
+    let mut utf16 = [MaybeUninit::<u16>::uninit(); MAX_BUFFER_SIZE / 2];
     let mut len_utf16 = 0;
     for (chr, dest) in utf8.encode_utf16().zip(utf16.iter_mut()) {
-        *dest = chr;
+        *dest = MaybeUninit::new(chr);
         len_utf16 += 1;
     }
-    let utf16 = &utf16[..len_utf16];
+    // Safety: We've initialized `len_utf16` values.
+    let utf16: &[u16] = unsafe { MaybeUninit::slice_assume_init_ref(&utf16[..len_utf16]) };
 
     let mut written = write_u16s(handle, &utf16)?;
 
@@ -250,11 +252,14 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
             return Ok(bytes_copied);
         } else if buf.len() - bytes_copied < 4 {
             // Not enough space to get a UTF-8 byte. We will use the incomplete UTF8.
-            let mut utf16_buf = [0u16; 1];
+            let mut utf16_buf = [MaybeUninit::new(0); 1];
             // Read one u16 character.
             let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, 1, &mut self.surrogate)?;
             // Read bytes, using the (now-empty) self.incomplete_utf8 as extra space.
-            let read_bytes = utf16_to_utf8(&utf16_buf[..read], &mut self.incomplete_utf8.bytes)?;
+            let read_bytes = utf16_to_utf8(
+                unsafe { MaybeUninit::slice_assume_init_ref(&utf16_buf[..read]) },
+                &mut self.incomplete_utf8.bytes,
+            )?;
 
             // Read in the bytes from incomplete_utf8 until the buffer is full.
             self.incomplete_utf8.len = read_bytes as u8;
@@ -262,15 +267,18 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
             bytes_copied += self.incomplete_utf8.read(&mut buf[bytes_copied..]);
             Ok(bytes_copied)
         } else {
-            let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2];
+            let mut utf16_buf = [MaybeUninit::<u16>::uninit(); MAX_BUFFER_SIZE / 2];
+
             // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So
             // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets
             // lost.
             let amount = cmp::min(buf.len() / 3, utf16_buf.len());
             let read =
                 read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?;
-
-            match utf16_to_utf8(&utf16_buf[..read], buf) {
+            // Safety `read_u16s_fixup_surrogates` returns the number of items
+            // initialized.
+            let utf16s = unsafe { MaybeUninit::slice_assume_init_ref(&utf16_buf[..read]) };
+            match utf16_to_utf8(utf16s, buf) {
                 Ok(value) => return Ok(bytes_copied + value),
                 Err(e) => return Err(e),
             }
@@ -283,14 +291,14 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
 // This is a best effort, and might not work if we are not the only reader on Stdin.
 fn read_u16s_fixup_surrogates(
     handle: c::HANDLE,
-    buf: &mut [u16],
+    buf: &mut [MaybeUninit<u16>],
     mut amount: usize,
     surrogate: &mut u16,
 ) -> io::Result<usize> {
     // Insert possibly remaining unpaired surrogate from last read.
     let mut start = 0;
     if *surrogate != 0 {
-        buf[0] = *surrogate;
+        buf[0] = MaybeUninit::new(*surrogate);
         *surrogate = 0;
         start = 1;
         if amount == 1 {
@@ -303,7 +311,10 @@ fn read_u16s_fixup_surrogates(
     let mut amount = read_u16s(handle, &mut buf[start..amount])? + start;
 
     if amount > 0 {
-        let last_char = buf[amount - 1];
+        // Safety: The returned `amount` is the number of values initialized,
+        // and it is not 0, so we know that `buf[amount - 1]` have been
+        // initialized.
+        let last_char = unsafe { buf[amount - 1].assume_init() };
         if last_char >= 0xD800 && last_char <= 0xDBFF {
             // high surrogate
             *surrogate = last_char;
@@ -313,7 +324,8 @@ fn read_u16s_fixup_surrogates(
     Ok(amount)
 }
 
-fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result<usize> {
+// Returns `Ok(n)` if it initialized `n` values in `buf`.
+fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit<u16>]) -> io::Result<usize> {
     // Configure the `pInputControl` parameter to not only return on `\r\n` but also Ctrl-Z, the
     // traditional DOS method to indicate end of character stream / user input (SUB).
     // See #38274 and https://stackoverflow.com/questions/43836040/win-api-readconsole.
@@ -346,8 +358,9 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result<usize> {
         }
         break;
     }
-
-    if amount > 0 && buf[amount as usize - 1] == CTRL_Z {
+    // Safety: if `amount > 0`, then that many bytes were written, so
+    // `buf[amount as usize - 1]` has been initialized.
+    if amount > 0 && unsafe { buf[amount as usize - 1].assume_init() } == CTRL_Z {
         amount -= 1;
     }
     Ok(amount as usize)
index 9301c5a2ff300da1103c65ac4f8ddd3ecdf9ba55..cc08ae5f99f0e80d03c36998ad02df043dcf10d0 100644 (file)
@@ -85,7 +85,7 @@ def _download(path, url, probably_big, verbose, exception):
             option = "-#"
         else:
             option = "-s"
-        # If curl is not present on Win32, we shoud not sys.exit
+        # If curl is not present on Win32, we should not sys.exit
         #   but raise `CalledProcessError` or `OSError` instead
         require(["curl", "--version"], exception=platform_is_win32)
         run(["curl", option,
@@ -793,6 +793,8 @@ class RustBuild(object):
 
     def check_vendored_status(self):
         """Check that vendoring is configured properly"""
+        # keep this consistent with the equivalent check in rustbuild:
+        # https://github.com/rust-lang/rust/blob/a8a33cf27166d3eabaffc58ed3799e054af3b0c6/src/bootstrap/lib.rs#L399-L405
         if 'SUDO_USER' in os.environ and not self.use_vendored_sources:
             if os.getuid() == 0:
                 self.use_vendored_sources = True
index 1e764811ea7977129ed794dc9176af204d7a7060..14e8ebd6876b45646a2bdbe97ae3b26248f8f35e 100644 (file)
@@ -946,7 +946,7 @@ pub(crate) fn fix_bin_or_dylib(&self, fname: &Path) {
         };
         patchelf.args(&[OsString::from("--set-rpath"), rpath_entries]);
         if !fname.extension().map_or(false, |ext| ext == "so") {
-            // Finally, set the corret .interp for binaries
+            // Finally, set the correct .interp for binaries
             let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker");
             // FIXME: can we support utf8 here? `args` doesn't accept Vec<u8>, only OsString ...
             let dynamic_linker = t!(String::from_utf8(t!(fs::read(dynamic_linker_path))));
@@ -962,7 +962,7 @@ pub(crate) fn download_component(&self, url: &str, dest_path: &Path, help_on_err
         let tempfile = self.tempdir().join(dest_path.file_name().unwrap());
         // While bootstrap itself only supports http and https downloads, downstream forks might
         // need to download components from other protocols. The match allows them adding more
-        // protocols without worrying about merge conficts if we change the HTTP implementation.
+        // protocols without worrying about merge conflicts if we change the HTTP implementation.
         match url.split_once("://").map(|(proto, _)| proto) {
             Some("http") | Some("https") => {
                 self.download_http_with_retries(&tempfile, url, help_on_error)
index c3aabb16a9b9af131c70095d4ecc6e667efe5a07..c13e83f6c86126c82563b80f224f6252bf6dfc2e 100644 (file)
@@ -1281,7 +1281,9 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
                 compiler: build_compiler,
                 target: target_compiler.host,
             });
-            builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe("ld", target_compiler.host)));
+            for name in crate::LLD_FILE_NAMES {
+                builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe(name, target_compiler.host)));
+            }
         }
 
         if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
index 13e3049f2c81ff001a9bfbbce5efb075c676772c..7c062460c4f16e8eb21475c0e5da443bbc015f64 100644 (file)
@@ -388,6 +388,7 @@ fn eq(&self, other: &&str) -> bool {
 pub struct Target {
     /// Some(path to llvm-config) if using an external LLVM.
     pub llvm_config: Option<PathBuf>,
+    pub llvm_has_rust_patches: Option<bool>,
     /// Some(path to FileCheck) if one was specified.
     pub llvm_filecheck: Option<PathBuf>,
     pub llvm_libunwind: Option<LlvmLibunwind>,
@@ -733,6 +734,7 @@ struct TomlTarget {
         default_linker: Option<PathBuf> = "default-linker",
         linker: Option<String> = "linker",
         llvm_config: Option<String> = "llvm-config",
+        llvm_has_rust_patches: Option<bool> = "llvm-has-rust-patches",
         llvm_filecheck: Option<String> = "llvm-filecheck",
         llvm_libunwind: Option<String> = "llvm-libunwind",
         android_ndk: Option<String> = "android-ndk",
@@ -1109,6 +1111,7 @@ pub fn parse(args: &[String]) -> Config {
                 if let Some(ref s) = cfg.llvm_config {
                     target.llvm_config = Some(config.src.join(s));
                 }
+                target.llvm_has_rust_patches = cfg.llvm_has_rust_patches;
                 if let Some(ref s) = cfg.llvm_filecheck {
                     target.llvm_filecheck = Some(config.src.join(s));
                 }
index c01afa1fd3b75c3fbc07f38f4fcac5c158846e35..1a59b3958f1060844999fa0dac6ab6e7f30c3807 100644 (file)
@@ -423,8 +423,11 @@ fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
                 let gcc_lld_src_dir = src_dir.join("gcc-ld");
                 let gcc_lld_dst_dir = dst_dir.join("gcc-ld");
                 t!(fs::create_dir(&gcc_lld_dst_dir));
-                let exe_name = exe("ld", compiler.host);
-                builder.copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name));
+                for name in crate::LLD_FILE_NAMES {
+                    let exe_name = exe(name, compiler.host);
+                    builder
+                        .copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name));
+                }
             }
 
             // Man pages
index 2852442d0be6fbb7986a84f211a84a6494cde744..f909ecc0ab858404403aaa3edb7df83d6043df97 100644 (file)
@@ -793,7 +793,7 @@ fn run(self, builder: &Builder<'_>) {
         t!(fs::create_dir_all(&out));
         let mut index = tool::ErrorIndex::command(builder);
         index.arg("html");
-        index.arg(out.join("error-index.html"));
+        index.arg(out);
         index.arg(&builder.version);
 
         builder.run(&mut index);
index 30ea1c20b31b9c7e2fd04f0bac0626b89c79f770..cc0cf12bd187a7fc48ed6c06bfa09a9af5e064b0 100644 (file)
 use std::process::Command;
 use std::str;
 
+use config::Target;
 use filetime::FileTime;
 use once_cell::sync::OnceCell;
 
@@ -186,6 +187,9 @@ pub unsafe fn setup(_build: &mut crate::Build) {}
     "opt",           // used to optimize LLVM bytecode
 ];
 
+/// LLD file names for all flavors.
+const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"];
+
 pub const VERSION: usize = 2;
 
 /// Extra --check-cfg to add when building
@@ -395,13 +399,18 @@ pub fn new(config: Config) -> Build {
         let src = config.src.clone();
         let out = config.out.clone();
 
+        #[cfg(unix)]
+        // keep this consistent with the equivalent check in x.py:
+        // https://github.com/rust-lang/rust/blob/a8a33cf27166d3eabaffc58ed3799e054af3b0c6/src/bootstrap/bootstrap.py#L796-L797
         let is_sudo = match env::var_os("SUDO_USER") {
-            Some(sudo_user) => match env::var_os("USER") {
-                Some(user) => user != sudo_user,
-                None => false,
-            },
+            Some(_sudo_user) => {
+                let uid = unsafe { libc::getuid() };
+                uid == 0
+            }
             None => false,
         };
+        #[cfg(not(unix))]
+        let is_sudo = false;
 
         let ignore_git = config.ignore_git;
         let rust_info = channel::GitInfo::new(ignore_git, &src);
@@ -534,7 +543,6 @@ pub fn new(config: Config) -> Build {
         let rust_submodules = [
             "src/tools/rust-installer",
             "src/tools/cargo",
-            "src/tools/rls",
             "src/tools/miri",
             "library/backtrace",
             "library/stdarch",
@@ -835,12 +843,13 @@ fn md_doc_out(&self, target: TargetSelection) -> Interned<PathBuf> {
     ///
     /// If no custom `llvm-config` was specified then Rust's llvm will be used.
     fn is_rust_llvm(&self, target: TargetSelection) -> bool {
-        if self.config.llvm_from_ci && target == self.config.build {
-            return true;
-        }
-
         match self.config.target_config.get(&target) {
-            Some(ref c) => c.llvm_config.is_none(),
+            Some(Target { llvm_has_rust_patches: Some(patched), .. }) => *patched,
+            Some(Target { llvm_config, .. }) => {
+                // If the user set llvm-config we assume Rust is not patched,
+                // but first check to see if it was configured by llvm-from-ci.
+                (self.config.llvm_from_ci && target == self.config.build) || llvm_config.is_none()
+            }
             None => true,
         }
     }
@@ -1630,7 +1639,7 @@ fn chmod(_path: &Path, _perms: u32) {}
 /// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.)
 /// If the test is running and code is an error code, it will cause a panic.
 fn detail_exit(code: i32) -> ! {
-    // if in test and code is an error code, panic with staus code provided
+    // if in test and code is an error code, panic with status code provided
     if cfg!(test) && code != 0 {
         panic!("status code: {}", code);
     } else {
index 7ecf74d3068d0a54e1b1278449af6bf33ceddd2b..62b56994afe70e773b4ba587dfb18dd8d6f2dffb 100644 (file)
@@ -432,12 +432,13 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
         }
 
-        if target.starts_with("riscv") && !target.contains("freebsd") {
+        if target.starts_with("riscv") && !target.contains("freebsd") && !target.contains("openbsd")
+        {
             // RISC-V GCC erroneously requires linking against
             // `libatomic` when using 1-byte and 2-byte C++
             // atomics but the LLVM build system check cannot
             // detect this. Therefore it is set manually here.
-            // FreeBSD uses Clang as its system compiler and
+            // Some BSD uses Clang as its system compiler and
             // provides no libatomic in its base system so does
             // not want this.
             ldflags.exe.push(" -latomic");
@@ -637,7 +638,7 @@ fn configure_cmake(
 
         if target.contains("darwin") {
             // Make sure that CMake does not build universal binaries on macOS.
-            // Explicitly specifiy the one single target architecture.
+            // Explicitly specify the one single target architecture.
             if target.starts_with("aarch64") {
                 // macOS uses a different name for building arm64
                 cfg.define("CMAKE_OSX_ARCHITECTURES", "arm64");
index f1c2a21de59f7fe39b03ca1df7715100c3683b31..f61c95830858fb6f4b869b79701305627c7adc55 100644 (file)
@@ -854,7 +854,10 @@ fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String>
         .output()
         .map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
         .unwrap_or(String::new());
-    lines.lines().find_map(|l| l.split(":browser-ui-test@").skip(1).next()).map(|v| v.to_owned())
+    lines
+        .lines()
+        .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
+        .map(|v| v.to_owned())
 }
 
 fn get_browser_ui_test_version(npm: &Path) -> Option<String> {
index d0d367b39b493850cfce53e8095f2f05f7127905..7a875c960e13312d77d11983c0f4bab304b4c554 100644 (file)
@@ -1,5 +1,6 @@
-FROM ubuntu:16.04
+FROM ubuntu:22.04
 
+ARG DEBIAN_FRONTEND=noninteractive
 COPY scripts/android-base-apt-get.sh /scripts/
 RUN sh /scripts/android-base-apt-get.sh
 
@@ -13,7 +14,7 @@ RUN dpkg --add-architecture i386 && \
   libgl1-mesa-glx \
   libpulse0 \
   libstdc++6:i386 \
-  openjdk-9-jre-headless \
+  openjdk-8-jre-headless \
   tzdata \
   wget \
   python3
@@ -29,20 +30,12 @@ ENV PATH=$PATH:/android/sdk/platform-tools
 
 ENV TARGETS=arm-linux-androideabi
 
-# We are intentionally allowing an old toolchain on this builder (and that's
-# incompatible with LLVM downloads today).
-ENV NO_DOWNLOAD_CI_LLVM 1
-
-ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14 \
-    --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14
 
 ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 COPY scripts/android-start-emulator.sh /scripts/
 ENTRYPOINT ["/scripts/android-start-emulator.sh"]
index c98fa496d4861d22c274e17d3f38c2ca12fc7ccf..2328db4ab8b1d126dd774a67a744afb990bde1e0 100644 (file)
@@ -1,4 +1,4 @@
-FROM ubuntu:16.04
+FROM ubuntu:22.04
 
 COPY scripts/android-base-apt-get.sh /scripts/
 RUN sh /scripts/android-base-apt-get.sh
@@ -32,13 +32,9 @@ ENV RUST_CONFIGURE_ARGS \
       --i686-linux-android-ndk=/android/ndk/x86-14 \
       --aarch64-linux-android-ndk=/android/ndk/arm64-21 \
       --x86_64-linux-android-ndk=/android/ndk/x86_64-21 \
-      --disable-docs \
-      --set llvm.allow-old-toolchain
+      --disable-docs
 
 ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
-
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
index 71ea13071bd1f1345d0841f3208fa92f131b77a5..dd74726f856915a73311b92112066fe976d6e34a 100644 (file)
@@ -1,5 +1,6 @@
-FROM ubuntu:16.04
+FROM ubuntu:22.04
 
+ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++-multilib \
   make \
@@ -20,18 +21,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 RUN mkdir -p /config
 RUN echo "[rust]" > /config/nopt-std-config.toml
 RUN echo "optimize = false" >> /config/nopt-std-config.toml
 
-# We are intentionally allowing an old toolchain on this builder (and that's
-# incompatible with LLVM downloads today).
-ENV NO_DOWNLOAD_CI_LLVM 1
-
-ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests \
-    --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
 ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \
   && python3 ../x.py --stage 2 test
index ebeab3dbdb79913c87a55877c553e80e15dca62a..0c36cfd66bdef05ac0842102035c2288fc84b271 100644 (file)
@@ -1,5 +1,6 @@
-FROM ubuntu:16.04
+FROM ubuntu:22.04
 
+ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++-multilib \
   make \
@@ -20,14 +21,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
-# We are intentionally allowing an old toolchain on this builder (and that's
-# incompatible with LLVM downloads today).
-ENV NO_DOWNLOAD_CI_LLVM 1
-ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu \
-    --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu
 # Exclude some tests that are unlikely to be platform specific, to speed up
 # this slow job.
 ENV SCRIPT python3 ../x.py --stage 2 test \
index 321b3d6ace486d84f5cc9bbe0cd6df052a96e7e0..d55d5b56ad3f5e8cccfced590d0d2c0a81dcbf0f 100644 (file)
@@ -1,5 +1,6 @@
-FROM ubuntu:16.04
+FROM ubuntu:22.04
 
+ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
   make \
@@ -23,13 +24,5 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
-# We are intentionally allowing an old toolchain on this builder (and that's
-# incompatible with LLVM downloads today).
-ENV NO_DOWNLOAD_CI_LLVM 1
-
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \
-    --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
 ENV RUST_CHECK_TARGET check-aux
index be4def85f14c4735c41b63da42f00a317273d438..80a004501a81bb590553c4d77e8861587f331d07 100644 (file)
@@ -1,5 +1,6 @@
-FROM ubuntu:16.04
+FROM ubuntu:22.04
 
+ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
   make \
@@ -19,14 +20,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
-# We are intentionally allowing an old toolchain on this builder (and that's
-# incompatible with LLVM downloads today).
+# We are disabling CI LLVM since distcheck is an offline build.
 ENV NO_DOWNLOAD_CI_LLVM 1
 
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false \
-    --set llvm.allow-old-toolchain
+ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false
 ENV SCRIPT python3 ../x.py --stage 2 test distcheck
 ENV DIST_SRC 1
index e2ec4f275001b53d24fececc91607eaa810e1a75..4350ca205862ce742923d79c642b2511ad19f955 100644 (file)
@@ -1,5 +1,6 @@
-FROM ubuntu:16.04
+FROM ubuntu:22.04
 
+ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
   make \
@@ -27,6 +28,7 @@ RUN apt-get install -y \
   libdbus-1-3 \
   libexpat1 \
   libfontconfig1 \
+  libgbm1 \
   libgcc1 \
   libgconf-2-4 \
   libgdk-pixbuf2.0-0 \
@@ -59,13 +61,10 @@ RUN apt-get install -y \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 COPY host-x86_64/x86_64-gnu-tools/checktools.sh /tmp/
 
-RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ
-ENV NODE_FOLDER=/node-v14.4.0-linux-x64/bin
+RUN curl -sL https://nodejs.org/dist/v14.20.0/node-v14.20.0-linux-x64.tar.xz | tar -xJ
+ENV NODE_FOLDER=/node-v14.20.0-linux-x64/bin
 ENV PATH="$NODE_FOLDER:${PATH}"
 
 COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/
@@ -80,14 +79,10 @@ COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/
 # the local version of the package is different than the one used by the CI.
 RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true
 
-# We are intentionally allowing an old toolchain on this builder (and that's
-# incompatible with LLVM downloads today).
-ENV NO_DOWNLOAD_CI_LLVM 1
-
 ENV RUST_CONFIGURE_ARGS \
-  --set llvm.allow-old-toolchain \
   --build=x86_64-unknown-linux-gnu \
   --save-toolstates=/tmp/toolstate/toolstates.json
 
 ENV SCRIPT /tmp/checktools.sh ../x.py && \
-  NODE_PATH=`npm root -g` python3 ../x.py test src/test/rustdoc-gui --stage 2
+  NODE_PATH=`npm root -g` python3 ../x.py test src/test/rustdoc-gui --stage 2 \
+    --test-args "'--no-sandbox --jobs 1'"
index f1761f80643ba32321af88365051aac4c49b6c52..22e2e243e430a0d7a9d103b3bcdb63ed697c2691 100644 (file)
@@ -10,6 +10,7 @@ apt-get install -y --no-install-recommends \
   g++ \
   git \
   libssl-dev \
+  libncurses5 \
   make \
   ninja-build \
   pkg-config \
index 42ca0ef484fcc8437a0682cee23abe4b7c407d52..0a5421ceb238357b3634fb75234eba4d1dad643c 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 42ca0ef484fcc8437a0682cee23abe4b7c407d52
+Subproject commit 0a5421ceb238357b3634fb75234eba4d1dad643c
index 8e6aa3448515a0654e347b5e2510f1d4bc4d5a64..d880e6ac2acf133dce640da24b9fb692844f02d4 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8e6aa3448515a0654e347b5e2510f1d4bc4d5a64
+Subproject commit d880e6ac2acf133dce640da24b9fb692844f02d4
index e647eb102890e8927f488bea12672b079eff8d9d..f62e93c28323ed9637d0a205a0c256498674a509 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e647eb102890e8927f488bea12672b079eff8d9d
+Subproject commit f62e93c28323ed9637d0a205a0c256498674a509
index d3daa1f28e169087becbc5e2b49ac91ca0405a44..04892c1a6fc145602ac7367945fda9d4ee83c9fb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d3daa1f28e169087becbc5e2b49ac91ca0405a44
+Subproject commit 04892c1a6fc145602ac7367945fda9d4ee83c9fb
index f0f57f9338672e98ce41f99f09c5a34f6138e834..742fbe11d9c6fbab4ae13be216ad7a35e65643c8 100644 (file)
@@ -277,6 +277,7 @@ target | std | host | notes
 `powerpc64-unknown-linux-musl` | ? |  |
 `powerpc64-wrs-vxworks` | ? |  |
 `powerpc64le-unknown-linux-musl` | ? |  |
+[`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64
 `riscv32gc-unknown-linux-gnu` |   |   | RISC-V Linux (kernel 5.4, glibc 2.33)
 `riscv32gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
 `riscv32im-unknown-none-elf` | * |  | Bare RISC-V (RV32IM ISA)
@@ -284,6 +285,7 @@ target | std | host | notes
 `riscv32imc-esp-espidf` | ✓ |  | RISC-V ESP-IDF
 `riscv64gc-unknown-freebsd` |   |   | RISC-V FreeBSD
 `riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.0)
+[`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
 `s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 3.2, MUSL)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
 `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
new file mode 100644 (file)
index 0000000..cf831e1
--- /dev/null
@@ -0,0 +1,70 @@
+# armv4t-none-eabi
+
+Tier 3
+
+Bare-metal target for any cpu in the ARMv4T architecture family, supporting
+ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code
+generation.
+
+In particular this supports the Gameboy Advance (GBA), but there's nothing GBA
+specific with this target, so any ARMv4T device should work fine.
+
+## Target Maintainers
+
+* [@Lokathor](https://github.com/lokathor)
+
+## Requirements
+
+The target is cross-compiled, and uses static linking.
+
+The linker that comes with rustc cannot link for this platform (the platform is
+too old). You will need the `arm-none-eabi-ld` linker from a GNU Binutils
+targeting ARM. This can be obtained for Windows/Mac/Linux from the [ARM
+Developer Website][arm-dev], or possibly from your OS's package manager.
+
+[arm-dev]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
+
+This target doesn't provide a linker script, you'll need to bring your own
+according to the specific device you want to target. Pass
+`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
+`your_script.ld` during linking.
+
+## Building Rust Programs
+
+Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target.
+
+Just use the `build-std` nightly cargo feature to build the `core` library. You
+can pass this as a command line argument to cargo, or your `.cargo/config.toml`
+file might include the following lines:
+
+```toml
+[unstable]
+build-std = ["core"]
+```
+
+Most of `core` should work as expected, with the following notes:
+* the target is "soft float", so `f32` and `f64` operations are emulated in
+  software.
+* integer division is also emulated in software.
+* the target is old enough that it doesn't have atomic instructions.
+
+Rust programs are output as ELF files.
+
+For running on hardware, you'll generally need to extract the "raw" program code
+out of the ELF and into a file of its own. The `objcopy` program provided as
+part of the GNU Binutils can do this:
+
+```shell
+arm-none-eabi-objcopy --output-target binary [in_file] [out_file]
+```
+
+## Testing
+
+This is a cross-compiled target that you will need to emulate during testing.
+
+Because this is a device-agnostic target, and the exact emulator that you'll
+need depends on the specific device you want to run your code on.
+
+For example, when programming for the Gameboy Advance, the
+[mgba-test-runner](https://github.com/agbrs/agb) program could be used to make a
+normal set of rust tests be run within the `mgba` emulator.
diff --git a/src/doc/rustc/src/platform-support/armv4t_none_eabi.md b/src/doc/rustc/src/platform-support/armv4t_none_eabi.md
deleted file mode 100644 (file)
index cf831e1..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-# armv4t-none-eabi
-
-Tier 3
-
-Bare-metal target for any cpu in the ARMv4T architecture family, supporting
-ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code
-generation.
-
-In particular this supports the Gameboy Advance (GBA), but there's nothing GBA
-specific with this target, so any ARMv4T device should work fine.
-
-## Target Maintainers
-
-* [@Lokathor](https://github.com/lokathor)
-
-## Requirements
-
-The target is cross-compiled, and uses static linking.
-
-The linker that comes with rustc cannot link for this platform (the platform is
-too old). You will need the `arm-none-eabi-ld` linker from a GNU Binutils
-targeting ARM. This can be obtained for Windows/Mac/Linux from the [ARM
-Developer Website][arm-dev], or possibly from your OS's package manager.
-
-[arm-dev]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
-
-This target doesn't provide a linker script, you'll need to bring your own
-according to the specific device you want to target. Pass
-`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
-`your_script.ld` during linking.
-
-## Building Rust Programs
-
-Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target.
-
-Just use the `build-std` nightly cargo feature to build the `core` library. You
-can pass this as a command line argument to cargo, or your `.cargo/config.toml`
-file might include the following lines:
-
-```toml
-[unstable]
-build-std = ["core"]
-```
-
-Most of `core` should work as expected, with the following notes:
-* the target is "soft float", so `f32` and `f64` operations are emulated in
-  software.
-* integer division is also emulated in software.
-* the target is old enough that it doesn't have atomic instructions.
-
-Rust programs are output as ELF files.
-
-For running on hardware, you'll generally need to extract the "raw" program code
-out of the ELF and into a file of its own. The `objcopy` program provided as
-part of the GNU Binutils can do this:
-
-```shell
-arm-none-eabi-objcopy --output-target binary [in_file] [out_file]
-```
-
-## Testing
-
-This is a cross-compiled target that you will need to emulate during testing.
-
-Because this is a device-agnostic target, and the exact emulator that you'll
-need depends on the specific device you want to run your code on.
-
-For example, when programming for the Gameboy Advance, the
-[mgba-test-runner](https://github.com/agbrs/agb) program could be used to make a
-normal set of rust tests be run within the `mgba` emulator.
index 8b204949a6eefe367aa10362a2e4622114067649..5a815635f4be2c5bae27c90ed336b7a3ee81f789 100644 (file)
@@ -5,14 +5,10 @@
 [Fuchsia] is a modern open source operating system that's simple, secure,
 updatable, and performant.
 
-[Fuchsia]: https://fuchsia.dev/
-
 ## Target maintainers
 
 The [Fuchsia team]:
 
-[Fuchsia team]: https://team-api.infra.rust-lang.org/v1/teams/fuchsia.json
-
 - Tyler Mandry ([@tmandry](https://github.com/tmandry))
 - Dan Johnson ([@computerdruid](https://github.com/computerdruid))
 - David Koloski ([@djkoloski](https://github.com/djkoloski))
@@ -24,27 +20,169 @@ the members reported by the API. The API should be considered to be
 authoritative if this occurs. Instead of pinging individual members, use
 `@rustbot ping fuchsia` to contact the team on GitHub.
 
+## Table of contents
+
+1. [Requirements](#requirements)
+1. [Walkthrough structure](#walkthrough-structure)
+1. [Compiling a Rust binary targeting Fuchsia](#compiling-a-rust-binary-targeting-fuchsia)
+    1. [Targeting Fuchsia with rustup and cargo](#targeting-fuchsia-with-rustup-and-cargo)
+    1. [Targeting Fuchsia with a compiler built from source](#targeting-fuchsia-with-a-compiler-built-from-source)
+1. [Creating a Fuchsia package](#creating-a-fuchsia-package)
+    1. [Creating a Fuchsia component](#creating-a-fuchsia-component)
+    1. [Building a Fuchsia package](#building-a-fuchsia-package)
+1. [Publishing a Fuchsia package](#publishing-a-fuchsia-package)
+    1. [Creating a Fuchsia package repository](#creating-a-fuchsia-package-repository)
+    1. [Publishing Fuchsia package to repository](#publishing-fuchsia-package-to-repository)
+1. [Running a Fuchsia component on an emulator](#running-a-fuchsia-component-on-an-emulator)
+    1. [Starting the Fuchsia emulator](#starting-the-fuchsia-emulator)
+    1. [Watching emulator logs](#watching-emulator-logs)
+    1. [Serving a Fuchsia package](#serving-a-fuchsia-package)
+    1. [Running a Fuchsia component](#running-a-fuchsia-component)
+1. [`.gitignore` extensions](#gitignore-extensions)
+1. [Testing](#testing)
+    1. [Running unit tests](#running-unit-tests)
+    1. [Running the compiler test suite](#running-the-compiler-test-suite)
+
 ## Requirements
 
-This target is cross-compiled from a host environment. Development may be done
-from the [source tree] or using the Fuchsia SDK.
+This target is cross-compiled from a host environment. You will need a recent
+copy of the [Fuchsia SDK], which provides the tools, libraries, and binaries
+required to build and link programs for Fuchsia.
 
-[source tree]: https://fuchsia.dev/fuchsia-src/get-started/learn/build
+Development may also be done from the [source tree].
 
-Fuchsia targets support std and follow the `sysv64` calling convention on
+Fuchsia targets support `std` and follow the `sysv64` calling convention on
 x86_64. Fuchsia binaries use the ELF file format.
 
-## Building the target
+## Walkthrough structure
+
+This walkthrough will cover:
+
+1. Compiling a Rust binary targeting Fuchsia.
+1. Building a Fuchsia package.
+1. Publishing and running a Fuchsia package to a Fuchsia emulator.
+
+For the purposes of this walkthrough, we will only target `x86_64-fuchsia`.
+
+## Compiling a Rust binary targeting Fuchsia
+
+Today, there are two main ways to build a Rust binary targeting Fuchsia
+using the Fuchsia SDK:
+1. Allow [rustup] to handle the installation of Fuchsia targets for you.
+1. Build a toolchain locally that can target Fuchsia.
+
+### Targeting Fuchsia with rustup and cargo
+
+The easiest way to build a Rust binary targeting Fuchsia is by allowing [rustup]
+to handle the installation of Fuchsia targets for you. This can be done by issuing
+the following commands:
+
+```sh
+rustup target add x86_64-fuchsia
+rustup target add aarch64-fuchsia
+```
+
+After installing our Fuchsia targets, we can now compile a Rust binary that targets
+Fuchsia.
+
+To create our Rust project, we can issue a standard `cargo` command as follows:
+
+**From base working directory**
+```sh
+cargo new hello_fuchsia
+```
+
+The rest of this walkthrough will take place from `hello_fuchsia`, so we can
+change into that directory now:
+
+```sh
+cd hello_fuchsia
+```
+
+*Note: From this point onwards, all commands will be issued from the `hello_fuchsia/`
+directory, and all `hello_fuchsia/` prefixes will be removed from references for sake of brevity.*
+
+We can edit our `src/main.rs` to include a test as follows:
+
+**`src/main.rs`**
+```rust
+fn main() {
+    println!("Hello Fuchsia!");
+}
+
+#[test]
+fn it_works() {
+    assert_eq!(2 + 2, 4);
+}
+```
+
+In addition to the standard workspace created, we will want to create a
+`.cargo/config.toml` file to link necessary libraries
+during compilation:
+
+**`.cargo/config.toml`**
+```txt
+[target.x86_64-fuchsia]
+
+rustflags = [
+    "-Lnative=<SDK_PATH>/arch/x64/lib",
+    "-Lnative=<SDK_PATH>/arch/x64/sysroot/lib"
+]
+```
+
+*Note: Make sure to fill out `<SDK_PATH>` with the path to the downloaded [Fuchsia SDK].*
+
+These options configure the following:
+
+* `-Lnative=${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from
+  the SDK
+* `-Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia kernel
+  libraries from the SDK
+
+In total, our new project will look like:
+
+**Current directory structure**
+```txt
+hello_fuchsia/
+┣━ src/
+┃  ┗━ main.rs
+┣━ Cargo.toml
+┗━ .cargo/
+   ┗━ config.toml
+```
+
+Finally, we can build our rust binary as:
+
+```sh
+cargo build --target x86_64-fuchsia
+```
+
+Now we have a Rust binary at `target/x86_64-fuchsia/debug/hello_fuchsia`,
+targeting our desired Fuchsia target.
+
+**Current directory structure**
+```txt
+hello_fuchsia/
+┣━ src/
+┃  ┗━ main.rs
+┣━ target/
+┃  ┗━ x86_64-fuchsia/
+┃     ┗━ debug/
+┃        ┗━ hello_fuchsia
+┣━ Cargo.toml
+┗━ .cargo/
+   ┗━ config.toml
+```
+
+### Targeting Fuchsia with a compiler built from source
+
+An alternative to the first workflow is to target Fuchsia by using
+`rustc` built from source.
 
 Before building Rust for Fuchsia, you'll need a clang toolchain that supports
 Fuchsia as well. A recent version (14+) of clang should be sufficient to compile
 Rust for Fuchsia.
 
-You'll also need a recent copy of the [Fuchsia SDK], which provides the tools
-and binaries required to build and link programs for Fuchsia.
-
-[Fuchsia SDK]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core
-
 x86-64 and AArch64 Fuchsia targets can be enabled using the following
 configuration.
 
@@ -75,15 +213,21 @@ export CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/
 These can be run together in a shell environment by executing
 `(source config-env.sh && ./x.py install)`.
 
-## Building Rust programs
+Once `rustc` is installed, we can create a new working directory to work from,
+`hello_fuchsia` along with `hello_fuchsia/src`:
+
+```sh
+mkdir hello_fuchsia
+cd hello_fuchsia
+mkdir src
+```
 
-After compiling Rust binaries, you'll need to build a component, package it, and
-serve it to a Fuchsia device or emulator. All of this can be done using the
-Fuchsia SDK.
+*Note: From this point onwards, all commands will be issued from the `hello_fuchsia/`
+directory, and all `hello_fuchsia/` prefixes will be removed from references for sake of brevity.*
 
-As an example, we'll compile and run this simple program on a Fuchsia emulator:
+There, we can create a new file named `src/hello_fuchsia.rs`:
 
-**`hello_fuchsia.rs`**
+**`src/hello_fuchsia.rs`**
 ```rust
 fn main() {
     println!("Hello Fuchsia!");
@@ -95,31 +239,87 @@ fn it_works() {
 }
 ```
 
-Create a new file named `hello_fuchsia.rs` and fill out its contents with that
-code.
+**Current directory structure**
+```txt
+hello_fuchsia/
+┗━ src/
+    ┗━ hello_fuchsia.rs
+```
 
-### Create a package
+Using your freshly installed `rustc`, you can compile a binary for Fuchsia using
+the following options:
+
+* `--target x86_64-fuchsia`/`--target aarch64-fuchsia`: Targets the Fuchsia
+  platform of your choice
+* `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from
+  the SDK
+* `-Lnative ${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia kernel
+  libraries from the SDK
+
+Putting it all together:
+
+```sh
+# Configure these for the Fuchsia target of your choice
+TARGET_ARCH="<x86_64-fuchsia|aarch64-fuchsia>"
+ARCH="<x64|aarch64>"
 
+rustc \
+    --target ${TARGET_ARCH} \
+    -Lnative=${SDK_PATH}/arch/${ARCH}/lib \
+    -Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib \
+    --out-dir bin src/hello_fuchsia.rs
+```
+
+**Current directory structure**
+```txt
+hello_fuchsia/
+┣━ src/
+┃   ┗━ hello_fuchsia.rs
+┗━ bin/
+   ┗━ hello_fuchsia
+```
+
+## Creating a Fuchsia package
+
+Before moving on, double check your directory structure:
+
+**Current directory structure**
+```txt
+hello_fuchsia/
+┣━ src/                     (if using rustc)
+┃   ┗━ hello_fuchsia.rs     ...
+┣━ bin/                     ...
+┃  ┗━ hello_fuchsia         ...
+┣━ src/                     (if using cargo)
+┃  ┗━ main.rs               ...
+┗━ target/                  ...
+   ┗━ x86_64-fuchsia/       ...
+      ┗━ debug/             ...
+         ┗━ hello_fuchsia   ...
+```
+
+With our Rust binary built, we can move to creating a Fuchsia package.
 On Fuchsia, a package is the unit of distribution for software. We'll need to
 create a new package directory where we will place files like our finished
-binary and any data it may need. The working directory will have this layout:
+binary and any data it may need.
+
+To start, make the `pkg`, and `pkg/meta` directories:
 
+```sh
+mkdir pkg
+mkdir pkg/meta
+```
+
+**Current directory structure**
 ```txt
-hello_fuchsia.rs
-hello_fuchsia.cml
-package
-┣━ bin
-┃  ┗━ hello_fuchsia
-┣━ meta
-┃  ┣━ package
-┃  ┗━ hello_fuchsia.cm
-┗━ hello_fuchsia.manifest
+hello_fuchsia/
+┗━ pkg/
+   ┗━ meta/
 ```
 
-Make the `package`, `package/bin`, and `package/meta` directories and create the
-following files inside:
+Now, create the following files inside:
 
-**`package/meta/package`**
+**`pkg/meta/package`**
 ```json
 {
   "name": "hello_fuchsia",
@@ -130,13 +330,22 @@ following files inside:
 The `package` file describes our package's name and version number. Every
 package must contain one.
 
-**`package/hello_fuchsia.manifest`**
+**`pkg/hello_fuchsia.manifest` if using cargo**
+```txt
+bin/hello_fuchsia=target/x86_64-fuchsia/debug/hello_fuchsia
+lib/ld.so.1=<SDK_PATH>/arch/x64/sysroot/dist/lib/ld.so.1
+lib/libfdio.so=<SDK_PATH>/arch/x64/dist/libfdio.so
+meta/package=pkg/meta/package
+meta/hello_fuchsia.cm=pkg/meta/hello_fuchsia.cm
+```
+
+**`pkg/hello_fuchsia.manifest` if using rustc**
 ```txt
-bin/hello_fuchsia=package/bin/hello_fuchsia
+bin/hello_fuchsia=bin/hello_fuchsia
 lib/ld.so.1=<SDK_PATH>/arch/x64/sysroot/dist/lib/ld.so.1
 lib/libfdio.so=<SDK_PATH>/arch/x64/dist/libfdio.so
-meta/package=package/meta/package
-meta/hello_fuchsia.cm=package/meta/hello_fuchsia.cm
+meta/package=pkg/meta/package
+meta/hello_fuchsia.cm=pkg/meta/hello_fuchsia.cm
 ```
 
 *Note: Relative manifest paths are resolved starting from the working directory
@@ -144,42 +353,26 @@ of `pm`. Make sure to fill out `<SDK_PATH>` with the path to the downloaded
 SDK.*
 
 The `.manifest` file will be used to describe the contents of the package by
-relating their location when installed to their location on the file system. You
-can use this to make a package pull files from other places, but for this
-example we'll just be placing everything in the `package` directory.
-
-### Compiling a binary
-
-Using your freshly compiled `rustc`, you can compile a binary for Fuchsia using
-the following options:
+relating their location when installed to their location on the file system. The
+`bin/hello_fuchsia=` entry will be different depending on how your Rust binary
+was built, so choose accordingly.
 
-* `--target x86_64-fuchsia`/`--target aarch64-fuchsia`: Targets the Fuchsia
-  platform of your choice
-* `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from
-  the SDK
-* `-Lnative ${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia kernel
-  libraries from the SDK
-
-Putting it all together:
-
-```sh
-# Configure these for the Fuchsia target of your choice
-TARGET_ARCH="<x86_64-fuchsia|aarch64-fuchsia>"
-ARCH="<x64|aarch64>"
-
-rustc --target ${TARGET_ARCH} -Lnative=${SDK_PATH}/arch/${ARCH}/lib -Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib -o package/bin/hello_fuchsia hello_fuchsia.rs
+**Current directory structure**
+```txt
+hello_fuchsia/
+┗━ pkg/
+   ┣━ meta/
+   ┃  ┗━ package
+   ┗━ hello_fuchsia.manifest
 ```
 
-### Bulding a component
+### Creating a Fuchsia component
 
-On Fuchsia, components require a component manifest written in Fuchia's markup
+On Fuchsia, components require a component manifest written in Fuchsia's markup
 language called CML. The Fuchsia devsite contains an [overview of CML] and a
 [reference for the file format]. Here's a basic one that can run our single binary:
 
-[overview of CML]: https://fuchsia.dev/fuchsia-src/concepts/components/v2/component_manifests
-[reference for the file format]: https://fuchsia.dev/reference/cml
-
-**`hello_fuchsia.cml`**
+**`pkg/hello_fuchsia.cml`**
 ```txt
 {
     include: [ "syslog/client.shard.cml" ],
@@ -190,43 +383,153 @@ language called CML. The Fuchsia devsite contains an [overview of CML] and a
 }
 ```
 
+**Current directory structure**
+```txt
+hello_fuchsia/
+┗━ pkg/
+   ┣━ meta/
+   ┃  ┗━ package
+   ┣━ hello_fuchsia.manifest
+   ┗━ hello_fuchsia.cml
+```
+
 Now we can compile that CML into a component manifest:
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/cmc compile hello_fuchsia.cml --includepath ${SDK_PATH}/pkg -o package/meta/hello_fuchsia.cm
+${SDK_PATH}/tools/${ARCH}/cmc compile \
+    pkg/hello_fuchsia.cml \
+    --includepath ${SDK_PATH}/pkg \
+    -o pkg/meta/hello_fuchsia.cm
 ```
 
-`--includepath` tells the compiler where to look for `include`s from our CML.
-In our case, we're only using `syslog/client.shard.cml`.
+*Note: `--includepath` tells the compiler where to look for `include`s from our CML.
+In our case, we're only using `syslog/client.shard.cml`.*
+
+**Current directory structure**
+```txt
+hello_fuchsia/
+┗━ pkg/
+   ┣━ meta/
+   ┃  ┣━ package
+   ┃  ┗━ hello_fuchsia.cm
+   ┣━ hello_fuchsia.manifest
+   ┗━ hello_fuchsia.cml
+```
 
-### Building and publishing a package
+### Building a Fuchsia package
 
-Next, we'll build our package as defined by our manifest:
+Next, we'll build a package manifest as defined by our manifest:
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/pm -o hello_fuchsia -m package/hello_fuchsia.manifest build -output-package-manifest hello_fuchsia_manifest
+${SDK_PATH}/tools/${ARCH}/pm \
+    -o pkg/hello_fuchsia_manifest \
+    -m pkg/hello_fuchsia.manifest \
+    build \
+    -output-package-manifest pkg/hello_fuchsia_package_manifest
 ```
 
-This will produce `hello_fuchsia_manifest` which is a package manifest we can
-publish directly to a repository. We can set up that repository with:
+This will produce `pkg/hello_fuchsia_manifest/` which is a package manifest we can
+publish directly to a repository.
+
+**Current directory structure**
+```txt
+hello_fuchsia/
+┗━ pkg/
+   ┣━ meta/
+   ┃  ┣━ package
+   ┃  ┗━ hello_fuchsia.cm
+   ┣━ hello_fuchsia_manifest/
+   ┃  ┗━ ...
+   ┣━ hello_fuchsia.manifest
+   ┣━ hello_fuchsia.cml
+   ┗━ hello_fuchsia_package_manifest
+```
+
+We are now ready to publish the package.
+
+## Publishing a Fuchsia package
+
+With our package and component manifests setup,
+we can now publish our package. The first step will
+be to create a Fuchsia package repository to publish
+to.
+
+### Creating a Fuchsia package repository
+
+We can set up our repository with:
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/pm newrepo -repo repo
+${SDK_PATH}/tools/${ARCH}/pm newrepo \
+    -repo pkg/repo
 ```
 
-And then publish our new package to that repository with:
+**Current directory structure**
+```txt
+hello_fuchsia/
+┗━ pkg/
+   ┣━ meta/
+   ┃  ┣━ package
+   ┃  ┗━ hello_fuchsia.cm
+   ┣━ hello_fuchsia_manifest/
+   ┃  ┗━ ...
+   ┣━ repo/
+   ┃  ┗━ ...
+   ┣━ hello_fuchsia.manifest
+   ┣━ hello_fuchsia.cml
+   ┗━ hello_fuchsia_package_manifest
+```
+
+## Publishing Fuchsia package to repository
+
+We can publish our new package to that repository with:
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/pm publish -repo repo -lp -f <(echo "hello_fuchsia_manifest")
+${SDK_PATH}/tools/${ARCH}/pm publish \
+    -repo pkg/repo \
+    -lp -f <(echo "pkg/hello_fuchsia_package_manifest")
 ```
 
-Then we can add it to `ffx`'s package server as `hello-fuchsia` using:
+Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using:
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm repo -r hello-fuchsia
+${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \
+    pkg/repo \
+    -r hello-fuchsia
+```
+
+## Running a Fuchsia component on an emulator
+
+At this point, we are ready to run our Fuchsia
+component. For reference, our final directory
+structure will look like:
+
+**Final directory structure**
+```txt
+hello_fuchsia/
+┣━ src/                     (if using rustc)
+┃   ┗━ hello_fuchsia.rs     ...
+┣━ bin/                     ...
+┃  ┗━ hello_fuchsia         ...
+┣━ src/                     (if using cargo)
+┃  ┗━ main.rs               ...
+┣━ target/                  ...
+┃  ┗━ x86_64-fuchsia/       ...
+┃     ┗━ debug/             ...
+┃        ┗━ hello_fuchsia   ...
+┗━ pkg/
+   ┣━ meta/
+   ┃  ┣━ package
+   ┃  ┗━ hello_fuchsia.cm
+   ┣━ hello_fuchsia_manifest/
+   ┃  ┗━ ...
+   ┣━ repo/
+   ┃  ┗━ ...
+   ┣━ hello_fuchsia.manifest
+   ┣━ hello_fuchsia.cml
+   ┗━ hello_fuchsia_package_manifest
 ```
 
-### Starting the emulator
+### Starting the Fuchsia emulator
 
 Start a Fuchsia emulator in a new terminal using:
 
@@ -235,50 +538,83 @@ ${SDK_PATH}/tools/${ARCH}/ffx product-bundle get workstation_eng.qemu-${ARCH}
 ${SDK_PATH}/tools/${ARCH}/ffx emu start workstation_eng.qemu-${ARCH} --headless
 ```
 
-Once the emulator is running, start a package repository server to serve our
-package to the emulator:
+### Watching emulator logs
+
+Once the emulator is running, open a separate terminal to watch the emulator logs:
 
+**In separate terminal**
 ```sh
-${SDK_PATH}/tools/${ARCH}/ffx repository server start
+${SDK_PATH}/tools/${ARCH}/ffx log \
+    --since now
 ```
 
-Once the repository server is up and running, register our repository:
+### Serving a Fuchsia package
+
+Now, start a package repository server to serve our
+package to the emulator:
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/ffx target repository register --repository hello-fuchsia
+${SDK_PATH}/tools/${ARCH}/ffx repository server start
 ```
 
-And watch the logs from the emulator in a separate terminal:
+Once the repository server is up and running, register it with the target Fuchsia system running in the emulator:
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/ffx log --since now
+${SDK_PATH}/tools/${ARCH}/ffx target repository register \
+    --repository hello-fuchsia
 ```
 
+### Running a Fuchsia component
+
 Finally, run the component:
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/ffx component run fuchsia-pkg://hello-fuchsia/hello_fuchsia#meta/hello_fuchsia.cm
+${SDK_PATH}/tools/${ARCH}/ffx component run \
+    fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm
 ```
 
 On reruns of the component, the `--recreate` argument may also need to be
 passed.
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/ffx component run --recreate fuchsia-pkg://hello-fuchsia/hello_fuchsia#meta/hello_fuchsia.cm
+${SDK_PATH}/tools/${ARCH}/ffx component run \
+    --recreate \
+    fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm
+```
+
+## `.gitignore` extensions
+
+Optionally, we can create/extend our `.gitignore` file to ignore files and
+directories that are not helpful to track:
+
+```txt
+pkg/repo
+pkg/meta/hello_fuchsia.cm
+pkg/hello_fuchsia_manifest
+pkg/hello_fuchsia_package_manifest
 ```
 
 ## Testing
 
 ### Running unit tests
 
-Tests can be run in the same way as a regular binary, simply by passing `--test`
-to the `rustc` invocation and then repackaging and rerunning. The test harness
-will run the applicable unit tests.
+Tests can be run in the same way as a regular binary.
+
+* If using `cargo`, you can simply pass `test --no-run`
+to the `cargo` invocation and then repackage and rerun the Fuchsia package. From our previous example,
+this would look like `cargo test --target x86_64-fuchsia --no-run`, and moving the executable
+binary path found from the line `Executable unittests src/main.rs (target/x86_64-fuchsia/debug/deps/hello_fuchsia-<HASH>)`
+into `pkg/hello_fuchsia.manifest`.
+
+* If using the compiled `rustc`, you can simply pass `--test`
+to the `rustc` invocation and then repackage and rerun the Fuchsia package.
+
+The test harness will run the applicable unit tests.
 
 Often when testing, you may want to pass additional command line arguments to
 your binary. Additional arguments can be set in the component manifest:
 
-**`hello_fuchsia.cml`**
+**`pkg/hello_fuchsia.cml`**
 ```txt
 {
     include: [ "syslog/client.shard.cml" ],
@@ -293,11 +629,20 @@ your binary. Additional arguments can be set in the component manifest:
 This will pass the argument `it_works` to the binary, filtering the tests to
 only those tests that match the pattern. There are many more configuration
 options available in CML including environment variables. More documentation is
-available on the [Fuchsia devsite](https://fuchsia.dev/reference/cml).
+available on the [Fuchsia devsite].
 
 ### Running the compiler test suite
 
 Running the Rust test suite on Fuchsia is [not currently supported], but work is
 underway to enable it.
 
+[Fuchsia team]: https://team-api.infra.rust-lang.org/v1/teams/fuchsia.json
+[Fuchsia]: https://fuchsia.dev/
+[source tree]: https://fuchsia.dev/fuchsia-src/get-started/learn/build
+[rustup]: https://rustup.rs/
+[cargo]: https://doc.rust-lang.org/cargo/
+[Fuchsia SDK]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core
+[overview of CML]: https://fuchsia.dev/fuchsia-src/concepts/components/v2/component_manifests
+[reference for the file format]: https://fuchsia.dev/reference/cml
+[Fuchsia devsite]: https://fuchsia.dev/reference/cml
 [not currently supported]: https://fxbug.dev/105393
index d325ba3346ab137361a1505112a8d7a7cb130ea6..b18a125f3b095e75e755cfb46a9b83b968f8a250 100644 (file)
@@ -87,7 +87,7 @@ Rust programs can be built for that target:
 rustc --target m68k-unknown-linux-gnu your-code.rs
 ```
 
-Very simple progams can be run using the `qemu-m68k-static` program:
+Very simple programs can be run using the `qemu-m68k-static` program:
 
 ```text
 $ qemu-m68k-static your-code
index b2ac776eada487fe5e2d548d00feb3c5672c2811..4ce80157dbf9c04762024da82394fda3814532ad 100644 (file)
@@ -12,6 +12,8 @@ The target names follow this format: `$ARCH-unknown-openbsd`, where `$ARCH` spec
 |--------------------------------|-------------|------------------|
 | `aarch64-unknown-openbsd`      | libc++      | [64-bit ARM systems](https://www.openbsd.org/arm64.html)  |
 | `i686-unknown-openbsd`         | libc++      | [Standard PC and clones based on the Intel i386 architecture and compatible processors](https://www.openbsd.org/i386.html) |
+| `powerpc64-unknown-openbsd`    | libc++      | [IBM POWER-based PowerNV systems](https://www.openbsd.org/powerpc64.html) |
+| `riscv64gc-unknown-openbsd`    | libc++      | [64-bit RISC-V systems](https://www.openbsd.org/riscv64.html) |
 | `sparc64-unknown-openbsd`      | estdc++     | [Sun UltraSPARC and Fujitsu SPARC64 systems](https://www.openbsd.org/sparc64.html) |
 | `x86_64-unknown-openbsd`       | libc++      | [AMD64-based systems](https://www.openbsd.org/amd64.html) |
 
index 721c234c6e60ad01e38df9087f970d20bac3b021..fb0cea05d4405f1a43447723c3dad2deb9b56c1c 100644 (file)
@@ -25,7 +25,7 @@ Like with any other Windows target created binaries are in PE format.
 
 ## Building the target
 
-For cross-compilation I recommend using [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) toolchain, one change that seems necessary beside configuring corss compilers is disabling experimental `m86k` target. Otherwise LLVM build fails with `multiple definition ...` errors.
+For cross-compilation I recommend using [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) toolchain, one change that seems necessary beside configuring cross compilers is disabling experimental `m86k` target. Otherwise LLVM build fails with `multiple definition ...` errors.
 Native bootstrapping builds require rather fragile hacks until host artifacts are available so I won't describe them here.
 
 ## Building Rust programs
index 8f90d9c7453d0a81e479f4ed8eb473cc5e028a4c..295dec0f0e488aeee419db6e29e380c5d534fb42 100644 (file)
@@ -133,7 +133,7 @@ There are 3 common ways to compile native C code for UEFI targets:
 - Use native Windows targets. This means compiling your C code for the Windows
   platform as if it was the UEFI platform. This works for static libraries, but
   needs adjustments when linking into an UEFI executable. You can, however,
-  link such static libraries seemlessly into rust code compiled for UEFI
+  link such static libraries seamlessly into rust code compiled for UEFI
   targets. Be wary of any includes that are not specifically suitable for UEFI
   targets (especially the C standard library includes are not always
   compatible). Freestanding compilations are recommended to avoid
index 021b904debd8f6b8d3b3bd2c30b5390cfb39917d..6932e6a5764bc416e160f0aa8e2c1d8b438629db 100644 (file)
@@ -30,7 +30,7 @@ is 8-bytes large as well as pointers. The tradeoff, though, is that the maximum
 memory size is now the full 64-bit address space instead of the 4GB as limited
 by the 32-bit address space for `wasm32-unknown-unknown`.
 
-This target is not a stable target. The [memory64] WebAssembly proposal is stil
+This target is not a stable target. The [memory64] WebAssembly proposal is still
 in-progress and not standardized. This means that there are not many engines
 which implement the `memory64` feature and if they do they're likely behind a
 flag, for example:
index bfa92e7d32a8eaf1851275a680043049cdc71fff..321992f7b0d75882b1521e9e75273810a719a119 100644 (file)
@@ -143,7 +143,7 @@ fn do_features() {}
 
 #[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in names()
                                  // and because no value checking was enable for "has_feathers"
-                                 // no warning is emited for the value "zapping"
+                                 // no warning is emitted for the value "zapping"
 fn do_zapping() {}
 
 #[cfg(has_mumble_frotz)]    // This is UNEXPECTED because names checking is enable and
index 977d258529f8c41a5b1f48895f955dfbe35efb3a..3890a12b7e684a92c8883581a8cef32aed652503 100644 (file)
@@ -8,7 +8,7 @@ This flag will rewrite absolute paths under the current working directory,
 replacing the current working directory prefix with a specified value.
 
 The given value may be absolute or relative, or empty. This switch takes
-precidence over `--remap-path-prefix` in case they would both match a given
+precedence over `--remap-path-prefix` in case they would both match a given
 path.
 
 This flag helps to produce deterministic output, by removing the current working
index 7f7549aaf5a9685109034ff2d389ba4343b5215b..b33405f18e90bcc2c92672cdaecfdc0df869a78b 100644 (file)
@@ -9,17 +9,17 @@ The tracking issues for this feature are:
 
 This feature allows for use of one of following sanitizers:
 
-* [AddressSanitizer][clang-asan] a fast memory error detector.
-* [ControlFlowIntegrity][clang-cfi] LLVM Control Flow Integrity (CFI) provides
+* [AddressSanitizer](#addresssanitizer) a fast memory error detector.
+* [ControlFlowIntegrity](#controlflowintegrity) LLVM Control Flow Integrity (CFI) provides
   forward-edge control flow protection.
-* [HWAddressSanitizer][clang-hwasan] a memory error detector similar to
+* [HWAddressSanitizer](#hwaddresssanitizer) a memory error detector similar to
   AddressSanitizer, but based on partial hardware assistance.
-* [LeakSanitizer][clang-lsan] a run-time memory leak detector.
-* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
-* [MemTagSanitizer][clang-memtag] fast memory error detector based on
+* [LeakSanitizer](#leaksanitizer) a run-time memory leak detector.
+* [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads.
+* [MemTagSanitizer](#memtagsanitizer) fast memory error detector based on
   Armv8.5-A Memory Tagging Extension.
-* [ShadowCallStack][clang-scs] provides backward-edge control flow protection.
-* [ThreadSanitizer][clang-tsan] a fast data race detector.
+* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection.
+* [ThreadSanitizer](#threadsanitizer) a fast data race detector.
 
 To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
 `-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
@@ -58,6 +58,8 @@ AddressSanitizer works with non-instrumented code although it will impede its
 ability to detect some bugs.  It is not expected to produce false positive
 reports.
 
+See the [Clang AddressSanitizer documentation][clang-asan] for more details.
+
 ## Examples
 
 Stack buffer overflow:
@@ -204,6 +206,8 @@ tracking issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
 
 LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto).
 
+See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details.
+
 ## Example
 
 ```text
@@ -430,6 +434,8 @@ HWAddressSanitizer requires `tagged-globals` target feature to instrument
 globals. To enable this target feature compile with `-C
 target-feature=+tagged-globals`
 
+See the [Clang HWAddressSanitizer documentation][clang-hwasan] for more details.
+
 ## Example
 
 Heap buffer overflow:
@@ -507,6 +513,8 @@ LeakSanitizer is supported on the following targets:
 * `x86_64-apple-darwin`
 * `x86_64-unknown-linux-gnu`
 
+See the [Clang LeakSanitizer documentation][clang-lsan] for more details.
+
 # MemorySanitizer
 
 MemorySanitizer is detector of uninitialized reads.
@@ -521,6 +529,8 @@ MemorySanitizer requires all program code to be instrumented. C/C++ dependencies
 need to be recompiled using Clang with `-fsanitize=memory` option. Failing to
 achieve that will result in false positive reports.
 
+See the [Clang MemorySanitizer documentation][clang-msan] for more details.
+
 ## Example
 
 Detecting the use of uninitialized memory. The `-Zbuild-std` flag rebuilds and
@@ -569,7 +579,7 @@ MemTagSanitizer is supported on the following targets:
 MemTagSanitizer requires hardware support and the `mte` target feature.
 To enable this target feature compile with `-C target-feature="+mte"`.
 
-More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html).
+See the [LLVM MemTagSanitizer documentation][llvm-memtag] for more details.
 
 # ShadowCallStack
 
@@ -581,7 +591,9 @@ ShadowCallStack can be enabled with `-Zsanitizer=shadow-call-stack` option and i
 
 * `aarch64-linux-android`
 
-A runtime must be provided by the application or operating system. See the [LLVM documentation][clang-scs] for further details.
+A runtime must be provided by the application or operating system.
+
+See the [Clang ShadowCallStack documentation][clang-scs] for more details.
 
 # ThreadSanitizer
 
@@ -604,6 +616,8 @@ can lead to false positive reports.
 ThreadSanitizer does not support atomic fences `std::sync::atomic::fence`,
 nor synchronization performed using inline assembly code.
 
+See the [Clang ThreadSanitizer documentation][clang-tsan] for more details.
+
 ## Example
 
 ```rust
@@ -673,6 +687,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
 * [HWAddressSanitizer in Clang][clang-hwasan]
 * [LeakSanitizer in Clang][clang-lsan]
 * [MemorySanitizer in Clang][clang-msan]
+* [MemTagSanitizer in LLVM][llvm-memtag]
 * [ThreadSanitizer in Clang][clang-tsan]
 
 [clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
@@ -682,3 +697,4 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
 [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
 [clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html
 [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
+[llvm-memtag]: https://llvm.org/docs/MemTagSanitizer.html
diff --git a/src/doc/unstable-book/src/language-features/unix-sigpipe.md b/src/doc/unstable-book/src/language-features/unix-sigpipe.md
new file mode 100644 (file)
index 0000000..aa39b6e
--- /dev/null
@@ -0,0 +1,54 @@
+# `unix_sigpipe`
+
+The tracking issue for this feature is: [#97889]
+
+[#97889]: https://github.com/rust-lang/rust/issues/97889
+
+---
+
+The `#[unix_sigpipe = "..."]` attribute on `fn main()` can be used to specify how libstd shall setup `SIGPIPE` on Unix platforms before invoking `fn main()`. This attribute is ignored on non-Unix targets. There are three variants:
+* `#[unix_sigpipe = "inherit"]`
+* `#[unix_sigpipe = "sig_dfl"]`
+* `#[unix_sigpipe = "sig_ign"]`
+
+## `#[unix_sigpipe = "inherit"]`
+
+Leave `SIGPIPE` untouched before entering `fn main()`. Unless the parent process has changed the default `SIGPIPE` handler from `SIG_DFL` to something else, this will behave the same as `#[unix_sigpipe = "sig_dfl"]`.
+
+## `#[unix_sigpipe = "sig_dfl"]`
+
+Set the `SIGPIPE` handler to `SIG_DFL`. This will result in your program getting killed if it tries to write to a closed pipe. This is normally what you want if your program produces textual output.
+
+### Example
+
+```rust,no_run
+#![feature(unix_sigpipe)]
+#[unix_sigpipe = "sig_dfl"]
+fn main() { loop { println!("hello world"); } }
+```
+
+```bash
+% ./main | head -n 1
+hello world
+```
+
+## `#[unix_sigpipe = "sig_ign"]`
+
+Set the `SIGPIPE` handler to `SIG_IGN` before invoking `fn main()`. This will result in `ErrorKind::BrokenPipe` errors if you program tries to write to a closed pipe. This is normally what you want if you for example write socket servers, socket clients, or pipe peers.
+
+This is what libstd has done by default since 2014. Omitting `#[unix_sigpipe = "..."]` is the same as having `#[unix_sigpipe = "sig_ign"]`.
+
+### Example
+
+```rust,no_run
+#![feature(unix_sigpipe)]
+#[unix_sigpipe = "sig_ign"]
+fn main() { loop { println!("hello world"); } }
+```
+
+```bash
+% ./main | head -n 1
+hello world
+thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)', library/std/src/io/stdio.rs:1016:9
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+```
index ce06a79a21c3f58a770606027708e84b6552afa0..025f320e3a103e0497722fcd0f0b59887aea18c8 100644 (file)
@@ -187,3 +187,9 @@ while work_list:
             check_generic_bound(bound)
         if item["inner"]["default"]:
             check_type(item["inner"]["default"])
+    elif item["kind"] == "import":
+        if item["inner"]["id"]:
+            inner_id = item["inner"]["id"]
+            assert valid_id(inner_id)
+            if inner_id in crate["index"] and inner_id not in visited:
+                work_list.add(inner_id)
index 1c34255919434528778692442631789887f6ba58..2617378ba5fd2d5cec6186e005fedb2b9841ae5a 100755 (executable)
@@ -15,7 +15,7 @@
 # Improvements to this script are greatly appreciated!
 
 if [[ $# != 2 ]]; then
-    echo "expected 2 arguments, recieved $#"
+    echo "expected 2 arguments, received $#"
     echo "example usage: './src/etc/cpu-usage-over-time-plot.sh \
 7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c \
 x86_64-gnu'"
index baf95627c702820ea56bac0fea38841e73383ed6..c97fb4b805473625201e5c46b5ab339ceb10ab64 100644 (file)
@@ -386,7 +386,7 @@ def check_tree_attr(tree, path, attr, pat, regexp):
     return ret
 
 
-# Returns the number of occurences matching the regex (`regexp`) and the text (`pat`).
+# Returns the number of occurrences matching the regex (`regexp`) and the text (`pat`).
 def check_tree_text(tree, path, pat, regexp, stop_at_first):
     path = normalize_xpath(path)
     match_count = 0
index 5f5b48bc1c0b43ff235a91779e173ac3d05e2090..be7de3ebaf5712979fc6976b8a2edd4b1693d8e4 100755 (executable)
@@ -10,7 +10,7 @@ set -Eeuo pipefail
 # https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570
 unset GIT_DIR
 ROOT_DIR="$(git rev-parse --show-toplevel)"
-COMMAND="$ROOT_DIR/x.py test tidy --bless"
+COMMAND="$ROOT_DIR/x.py test tidy"
 
 if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
   COMMAND="python $COMMAND"
index cbdfea89efb8ade3f11bd2265037e01731c99652..7bc35c7d5516f16e537aa809197f831c26c8e6ab 100644 (file)
@@ -10,18 +10,19 @@ path = "lib.rs"
 arrayvec = { version = "0.7", default-features = false }
 askama = { version = "0.11", default-features = false, features = ["config"] }
 atty = "0.2"
-pulldown-cmark = { version = "0.9.2", default-features = false }
+itertools = "0.10.1"
 minifier = "0.2.2"
-serde = { version = "1.0", features = ["derive"] }
+once_cell = "1.10.0"
+pulldown-cmark = { version = "0.9.2", default-features = false }
+regex = "1"
+rustdoc-json-types = { path = "../rustdoc-json-types" }
 serde_json = "1.0"
+serde = { version = "1.0", features = ["derive"] }
 smallvec = "1.8.1"
 tempfile = "3"
-itertools = "0.10.1"
-regex = "1"
-rustdoc-json-types = { path = "../rustdoc-json-types" }
+thin-vec = "0.2.8"
 tracing = "0.1"
 tracing-tree = "0.2.0"
-once_cell = "1.10.0"
 
 [dependencies.tracing-subscriber]
 version = "0.3.3"
index 756e4f3b127e1f93b6d78c2eb35aab0f0da41ca8..175472797cb4622d599dd7dfaa222177a30f1c3b 100644 (file)
@@ -123,7 +123,7 @@ fn generate_for_trait(
             kind: Box::new(ImplItem(Box::new(Impl {
                 unsafety: hir::Unsafety::Normal,
                 generics: new_generics,
-                trait_: Some(clean_trait_ref_with_bindings(self.cx, trait_ref, &[])),
+                trait_: Some(clean_trait_ref_with_bindings(self.cx, trait_ref, ThinVec::new())),
                 for_: clean_middle_ty(ty, self.cx, None),
                 items: Vec::new(),
                 polarity,
index da15c3c2b1fabe2dd2ebf888fc2d7bb737077cdf..cc734389e070b29e5fc6c87455ad9fb204dba490 100644 (file)
@@ -115,7 +115,7 @@ pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
                             ),
                             // FIXME(eddyb) compute both `trait_` and `for_` from
                             // the post-inference `trait_ref`, as it's more accurate.
-                            trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref.0, &[])),
+                            trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref.0, ThinVec::new())),
                             for_: clean_middle_ty(ty.0, cx, None),
                             items: cx.tcx
                                 .associated_items(impl_def_id)
index 31b805f2ed7edf919a82ff6d41b064158010b6c6..c8aa51c3a49a3913e91067a674bf2ddacb3017c8 100644 (file)
@@ -3,9 +3,10 @@
 use std::iter::once;
 use std::sync::Arc;
 
+use thin_vec::ThinVec;
+
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::thin_vec::ThinVec;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -459,7 +460,7 @@ pub(crate) fn build_impl(
         ),
     };
     let polarity = tcx.impl_polarity(did);
-    let trait_ = associated_trait.map(|t| clean_trait_ref_with_bindings(cx, t, &[]));
+    let trait_ = associated_trait.map(|t| clean_trait_ref_with_bindings(cx, t, ThinVec::new()));
     if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
         super::build_deref_target_impls(cx, &trait_items, ret);
     }
index 420159b5a6751cb3eebce2e70fa85e878b5bf4cf..ebf6c55ee35df7ce96acd8617308df1b77681726 100644 (file)
@@ -33,7 +33,8 @@
 use std::collections::BTreeMap;
 use std::default::Default;
 use std::hash::Hash;
-use std::{mem, vec};
+use std::mem;
+use thin_vec::ThinVec;
 
 use crate::core::{self, DocContext, ImplTraitParam};
 use crate::formats::item_type::ItemType;
@@ -125,7 +126,7 @@ fn clean_generic_bound<'tcx>(
                 bug!("clean: parenthesized `GenericBound::LangItemTrait`");
             };
 
-            let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
+            let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, bindings);
             GenericBound::TraitBound(
                 PolyTrait { trait_, generic_params: vec![] },
                 hir::TraitBoundModifier::None,
@@ -147,14 +148,14 @@ fn clean_generic_bound<'tcx>(
 pub(crate) fn clean_trait_ref_with_bindings<'tcx>(
     cx: &mut DocContext<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
-    bindings: &[TypeBinding],
+    bindings: ThinVec<TypeBinding>,
 ) -> Path {
     let kind = cx.tcx.def_kind(trait_ref.def_id).into();
     if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
         span_bug!(cx.tcx.def_span(trait_ref.def_id), "`TraitRef` had unexpected kind {:?}", kind);
     }
     inline::record_extern_fqn(cx, trait_ref.def_id, kind);
-    let path = external_path(cx, trait_ref.def_id, true, bindings.to_vec(), trait_ref.substs);
+    let path = external_path(cx, trait_ref.def_id, true, bindings, trait_ref.substs);
 
     debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
 
@@ -164,7 +165,7 @@ pub(crate) fn clean_trait_ref_with_bindings<'tcx>(
 fn clean_poly_trait_ref_with_bindings<'tcx>(
     cx: &mut DocContext<'tcx>,
     poly_trait_ref: ty::PolyTraitRef<'tcx>,
-    bindings: &[TypeBinding],
+    bindings: ThinVec<TypeBinding>,
 ) -> GenericBound {
     let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
 
@@ -192,7 +193,7 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
 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)
+        rl::Region::EarlyBound(node_id)
         | rl::Region::LateBound(_, _, node_id)
         | rl::Region::Free(_, node_id),
     ) = def
@@ -327,7 +328,7 @@ fn clean_poly_trait_predicate<'tcx>(
     let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref);
     Some(WherePredicate::BoundPredicate {
         ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
-        bounds: vec![clean_poly_trait_ref_with_bindings(cx, poly_trait_ref, &[])],
+        bounds: vec![clean_poly_trait_ref_with_bindings(cx, poly_trait_ref, ThinVec::new())],
         bound_params: Vec::new(),
     })
 }
@@ -402,7 +403,7 @@ fn clean_projection<'tcx>(
     def_id: Option<DefId>,
 ) -> Type {
     let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
-    let trait_ = clean_trait_ref_with_bindings(cx, lifted.trait_ref(cx.tcx), &[]);
+    let trait_ = clean_trait_ref_with_bindings(cx, lifted.trait_ref(cx.tcx), ThinVec::new());
     let self_type = clean_middle_ty(ty.self_ty(), cx, None);
     let self_def_id = if let Some(def_id) = def_id {
         cx.tcx.opt_parent(def_id).or(Some(def_id))
@@ -886,7 +887,10 @@ fn clean_function<'tcx>(
         // NOTE: generics must be cleaned before args
         let generics = clean_generics(generics, cx);
         let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id);
-        let decl = clean_fn_decl_with_args(cx, sig.decl, args);
+        let mut decl = clean_fn_decl_with_args(cx, sig.decl, args);
+        if sig.header.is_async() {
+            decl.output = decl.sugared_async_return_type();
+        }
         (generics, decl)
     });
     Box::new(Function { decl, generics })
@@ -1588,12 +1592,12 @@ pub(crate) fn clean_middle_ty<'tcx>(
                 AdtKind::Enum => ItemType::Enum,
             };
             inline::record_extern_fqn(cx, did, kind);
-            let path = external_path(cx, did, false, vec![], substs);
+            let path = external_path(cx, did, false, ThinVec::new(), substs);
             Type::Path { path }
         }
         ty::Foreign(did) => {
             inline::record_extern_fqn(cx, did, ItemType::ForeignType);
-            let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
+            let path = external_path(cx, did, false, ThinVec::new(), InternalSubsts::empty());
             Type::Path { path }
         }
         ty::Dynamic(obj, ref reg) => {
@@ -1617,7 +1621,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
             let mut bounds = dids
                 .map(|did| {
                     let empty = cx.tcx.intern_substs(&[]);
-                    let path = external_path(cx, did, false, vec![], empty);
+                    let path = external_path(cx, did, false, ThinVec::new(), empty);
                     inline::record_extern_fqn(cx, did, ItemType::Trait);
                     PolyTrait { trait_: path, generic_params: Vec::new() }
                 })
@@ -1693,7 +1697,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
                         }
                     }
 
-                    let bindings: Vec<_> = bounds
+                    let bindings: ThinVec<_> = bounds
                         .iter()
                         .filter_map(|bound| {
                             if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder()
@@ -1714,7 +1718,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
                         })
                         .collect();
 
-                    Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings))
+                    Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
                 })
                 .collect::<Vec<_>>();
             bounds.extend(regions);
@@ -1845,12 +1849,8 @@ fn clean_generic_args<'tcx>(
             })
             .collect::<Vec<_>>()
             .into();
-        let bindings = generic_args
-            .bindings
-            .iter()
-            .map(|x| clean_type_binding(x, cx))
-            .collect::<Vec<_>>()
-            .into();
+        let bindings =
+            generic_args.bindings.iter().map(|x| clean_type_binding(x, cx)).collect::<ThinVec<_>>();
         GenericArgs::AngleBracketed { args, bindings }
     }
 }
index 909a47d07b1666f92ecf4f44e7478066b3655b09..2808b400a0b531fbfa462e53b565feb42e1f88f3 100644 (file)
@@ -8,6 +8,7 @@
 use std::{cmp, fmt, iter};
 
 use arrayvec::ArrayVec;
+use thin_vec::ThinVec;
 
 use rustc_ast::attr;
 use rustc_ast::util::comments::beautify_doc_string;
@@ -15,7 +16,6 @@
 use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
 use rustc_const_eval::const_eval::is_unstable_const_fn;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::thin_vec::ThinVec;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
@@ -1303,7 +1303,7 @@ impl GenericBound {
     pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
         let did = cx.tcx.require_lang_item(LangItem::Sized, None);
         let empty = cx.tcx.intern_substs(&[]);
-        let path = external_path(cx, did, false, vec![], empty);
+        let path = external_path(cx, did, false, ThinVec::new(), empty);
         inline::record_extern_fqn(cx, did, ItemType::Trait);
         GenericBound::TraitBound(
             PolyTrait { trait_: path, generic_params: Vec::new() },
index 718cbbd2b83742bf4e97e7d5ce93710e1ea906fe..ac9ab33961676c4b4bc90a387ceccc4240055402 100644 (file)
@@ -12,7 +12,6 @@
 
 use rustc_ast as ast;
 use rustc_ast::tokenstream::TokenTree;
-use rustc_data_structures::thin_vec::ThinVec;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
@@ -23,6 +22,7 @@
 use rustc_span::symbol::{kw, sym, Symbol};
 use std::fmt::Write as _;
 use std::mem;
+use thin_vec::ThinVec;
 
 #[cfg(test)]
 mod tests;
@@ -102,7 +102,7 @@ fn external_generic_args<'tcx>(
     cx: &mut DocContext<'tcx>,
     did: DefId,
     has_self: bool,
-    bindings: Vec<TypeBinding>,
+    bindings: ThinVec<TypeBinding>,
     substs: SubstsRef<'tcx>,
 ) -> GenericArgs {
     let args = substs_to_args(cx, substs, has_self);
@@ -112,7 +112,7 @@ fn external_generic_args<'tcx>(
             // The trait's first substitution is the one after self, if there is one.
             match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() {
                 ty::Tuple(tys) => tys.iter().map(|t| clean_middle_ty(t, cx, None)).collect::<Vec<_>>().into(),
-                _ => return GenericArgs::AngleBracketed { args: args.into(), bindings: bindings.into() },
+                _ => return GenericArgs::AngleBracketed { args: args.into(), bindings },
             };
         let output = None;
         // FIXME(#20299) return type comes from a projection now
@@ -130,7 +130,7 @@ pub(super) fn external_path<'tcx>(
     cx: &mut DocContext<'tcx>,
     did: DefId,
     has_self: bool,
-    bindings: Vec<TypeBinding>,
+    bindings: ThinVec<TypeBinding>,
     substs: SubstsRef<'tcx>,
 ) -> Path {
     let def_kind = cx.tcx.def_kind(did);
index b023792e95a58e4292478c2db0eab95a010eec27..be10a5c101f7ffa3e5ad5c9aa028f40201a07d45 100644 (file)
@@ -349,8 +349,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
         let where_preds = comma_sep(where_predicates, false);
         let clause = if f.alternate() {
             if ending == Ending::Newline {
-                // add a space so stripping <br> tags and breaking spaces still renders properly
-                format!(" where{where_preds}, ")
+                format!(" where{where_preds},")
             } else {
                 format!(" where{where_preds}")
             }
@@ -364,20 +363,16 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
 
             if ending == Ending::Newline {
                 let mut clause = "&nbsp;".repeat(indent.saturating_sub(1));
-                // add a space so stripping <br> tags and breaking spaces still renders properly
-                write!(
-                    clause,
-                    " <span class=\"where fmt-newline\">where{where_preds},&nbsp;</span>"
-                )?;
+                write!(clause, "<span class=\"where fmt-newline\">where{where_preds},</span>")?;
                 clause
             } else {
                 // insert a <br> tag after a single space but before multiple spaces at the start
                 if indent == 0 {
-                    format!(" <br><span class=\"where\">where{where_preds}</span>")
+                    format!("<br><span class=\"where\">where{where_preds}</span>")
                 } else {
                     let mut clause = br_with_padding;
                     clause.truncate(clause.len() - 5 * "&nbsp;".len());
-                    write!(clause, " <span class=\"where\">where{where_preds}</span>")?;
+                    write!(clause, "<span class=\"where\">where{where_preds}</span>")?;
                     clause
                 }
             }
@@ -1310,22 +1305,19 @@ pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
     ///   <br>Used to determine line-wrapping.
     /// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is
     ///   necessary.
-    /// * `asyncness`: Whether the function is async or not.
     pub(crate) fn full_print<'a, 'tcx: 'a>(
         &'a self,
         header_len: usize,
         indent: usize,
-        asyncness: hir::IsAsync,
         cx: &'a Context<'tcx>,
     ) -> impl fmt::Display + 'a + Captures<'tcx> {
-        display_fn(move |f| self.inner_full_print(header_len, indent, asyncness, f, cx))
+        display_fn(move |f| self.inner_full_print(header_len, indent, f, cx))
     }
 
     fn inner_full_print(
         &self,
         header_len: usize,
         indent: usize,
-        asyncness: hir::IsAsync,
         f: &mut fmt::Formatter<'_>,
         cx: &Context<'_>,
     ) -> fmt::Result {
@@ -1390,15 +1382,9 @@ fn inner_full_print(
             args_plain.push_str(", ...");
         }
 
-        let arrow_plain;
-        let arrow = if let hir::IsAsync::Async = asyncness {
-            let output = self.sugared_async_return_type();
-            arrow_plain = format!("{:#}", output.print(cx));
-            if f.alternate() { arrow_plain.clone() } else { format!("{}", output.print(cx)) }
-        } else {
-            arrow_plain = format!("{:#}", self.output.print(cx));
-            if f.alternate() { arrow_plain.clone() } else { format!("{}", self.output.print(cx)) }
-        };
+        let arrow_plain = format!("{:#}", self.output.print(cx));
+        let arrow =
+            if f.alternate() { arrow_plain.clone() } else { format!("{}", self.output.print(cx)) };
 
         let declaration_len = header_len + args_plain.len() + arrow_plain.len();
         let output = if declaration_len > 80 {
index 4a12d74ddef5a5844dd89255ed451eee1f43e7af..bb8e46af76286d9b74a22e54e868eb464094ed41 100644 (file)
@@ -450,7 +450,7 @@ impl<'a> PeekIter<'a> {
     fn new(iter: TokenIter<'a>) -> Self {
         Self { stored: VecDeque::new(), peek_pos: 0, iter }
     }
-    /// Returns the next item after the current one. It doesn't interfer with `peek_next` output.
+    /// Returns the next item after the current one. It doesn't interfere with `peek_next` output.
     fn peek(&mut self) -> Option<&(TokenKind, &'a str)> {
         if self.stored.is_empty() {
             if let Some(next) = self.iter.next() {
@@ -459,7 +459,7 @@ fn peek(&mut self) -> Option<&(TokenKind, &'a str)> {
         }
         self.stored.front()
     }
-    /// Returns the next item after the last one peeked. It doesn't interfer with `peek` output.
+    /// Returns the next item after the last one peeked. It doesn't interfere with `peek` output.
     fn peek_next(&mut self) -> Option<&(TokenKind, &'a str)> {
         self.peek_pos += 1;
         if self.peek_pos - 1 < self.stored.len() {
index 6272f47f460cac99f3ed07e57a4cce06f29a38c4..7577c71962388ebc2617ebebd3b722d0ff55af10 100644 (file)
@@ -613,10 +613,10 @@ fn short_item_info(
 
 // Render the list of items inside one of the sections "Trait Implementations",
 // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
-fn render_impls(
+pub(crate) fn render_impls(
     cx: &mut Context<'_>,
     w: &mut Buffer,
-    impls: &[&&Impl],
+    impls: &[&Impl],
     containing_item: &clean::Item,
     toggle_open_by_default: bool,
 ) {
@@ -821,7 +821,7 @@ fn assoc_method(
         href = href,
         name = name,
         generics = g.print(cx),
-        decl = d.full_print(header_len, indent, header.asyncness, cx),
+        decl = d.full_print(header_len, indent, cx),
         notable_traits = notable_traits_decl(d, cx),
         where_clause = print_where_clause(g, cx, indent, end_newline),
     )
@@ -1025,6 +1025,47 @@ fn anchor(&self, id: &'a str) -> Self {
     }
 }
 
+fn write_impl_section_heading(w: &mut Buffer, title: &str, id: &str) {
+    write!(
+        w,
+        "<h2 id=\"{id}\" class=\"small-section-header\">\
+            {title}\
+            <a href=\"#{id}\" class=\"anchor\"></a>\
+         </h2>"
+    );
+}
+
+pub(crate) fn render_all_impls(
+    w: &mut Buffer,
+    cx: &mut Context<'_>,
+    containing_item: &clean::Item,
+    concrete: &[&Impl],
+    synthetic: &[&Impl],
+    blanket_impl: &[&Impl],
+) {
+    let mut impls = Buffer::empty_from(w);
+    render_impls(cx, &mut impls, concrete, containing_item, true);
+    let impls = impls.into_inner();
+    if !impls.is_empty() {
+        write_impl_section_heading(w, "Trait Implementations", "trait-implementations");
+        write!(w, "<div id=\"trait-implementations-list\">{}</div>", impls);
+    }
+
+    if !synthetic.is_empty() {
+        write_impl_section_heading(w, "Auto Trait Implementations", "synthetic-implementations");
+        w.write_str("<div id=\"synthetic-implementations-list\">");
+        render_impls(cx, w, synthetic, containing_item, false);
+        w.write_str("</div>");
+    }
+
+    if !blanket_impl.is_empty() {
+        write_impl_section_heading(w, "Blanket Implementations", "blanket-implementations");
+        w.write_str("<div id=\"blanket-implementations-list\">");
+        render_impls(cx, w, blanket_impl, containing_item, false);
+        w.write_str("</div>");
+    }
+}
+
 fn render_assoc_items(
     w: &mut Buffer,
     cx: &mut Context<'_>,
@@ -1054,12 +1095,7 @@ fn render_assoc_items_inner(
         let mut tmp_buf = Buffer::empty_from(w);
         let (render_mode, id) = match what {
             AssocItemRender::All => {
-                tmp_buf.write_str(
-                    "<h2 id=\"implementations\" class=\"small-section-header\">\
-                         Implementations\
-                         <a href=\"#implementations\" class=\"anchor\"></a>\
-                     </h2>",
-                );
+                write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations");
                 (RenderMode::Normal, "implementations-list".to_owned())
             }
             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
@@ -1068,15 +1104,14 @@ fn render_assoc_items_inner(
                 if let Some(def_id) = type_.def_id(cx.cache()) {
                     cx.deref_id_map.insert(def_id, id.clone());
                 }
-                write!(
-                    tmp_buf,
-                    "<h2 id=\"{id}\" class=\"small-section-header\">\
-                         <span>Methods from {trait_}&lt;Target = {type_}&gt;</span>\
-                         <a href=\"#{id}\" class=\"anchor\"></a>\
-                     </h2>",
-                    id = id,
-                    trait_ = trait_.print(cx),
-                    type_ = type_.print(cx),
+                write_impl_section_heading(
+                    &mut tmp_buf,
+                    &format!(
+                        "<span>Methods from {trait_}&lt;Target = {type_}&gt;</span>",
+                        trait_ = trait_.print(cx),
+                        type_ = type_.print(cx),
+                    ),
+                    &id,
                 );
                 (RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id))
             }
@@ -1123,49 +1158,12 @@ fn render_assoc_items_inner(
             return;
         }
 
-        let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
-            traits.iter().partition(|t| t.inner_impl().kind.is_auto());
-        let (blanket_impl, concrete): (Vec<&&Impl>, _) =
+        let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
+            traits.into_iter().partition(|t| t.inner_impl().kind.is_auto());
+        let (blanket_impl, concrete): (Vec<&Impl>, _) =
             concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
 
-        let mut impls = Buffer::empty_from(w);
-        render_impls(cx, &mut impls, &concrete, containing_item, true);
-        let impls = impls.into_inner();
-        if !impls.is_empty() {
-            write!(
-                w,
-                "<h2 id=\"trait-implementations\" class=\"small-section-header\">\
-                     Trait Implementations\
-                     <a href=\"#trait-implementations\" class=\"anchor\"></a>\
-                 </h2>\
-                 <div id=\"trait-implementations-list\">{}</div>",
-                impls
-            );
-        }
-
-        if !synthetic.is_empty() {
-            w.write_str(
-                "<h2 id=\"synthetic-implementations\" class=\"small-section-header\">\
-                     Auto Trait Implementations\
-                     <a href=\"#synthetic-implementations\" class=\"anchor\"></a>\
-                 </h2>\
-                 <div id=\"synthetic-implementations-list\">",
-            );
-            render_impls(cx, w, &synthetic, containing_item, false);
-            w.write_str("</div>");
-        }
-
-        if !blanket_impl.is_empty() {
-            w.write_str(
-                "<h2 id=\"blanket-implementations\" class=\"small-section-header\">\
-                     Blanket Implementations\
-                     <a href=\"#blanket-implementations\" class=\"anchor\"></a>\
-                 </h2>\
-                 <div id=\"blanket-implementations-list\">",
-            );
-            render_impls(cx, w, &blanket_impl, containing_item, false);
-            w.write_str("</div>");
-        }
+        render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl);
     }
 }
 
@@ -1739,8 +1737,8 @@ pub(crate) fn render_impl_summary(
     // in documentation pages for trait with automatic implementations like "Send" and "Sync".
     aliases: &[String],
 ) {
-    let id =
-        cx.derive_id(get_id_for_impl(&i.inner_impl().for_, i.inner_impl().trait_.as_ref(), cx));
+    let inner_impl = i.inner_impl();
+    let id = cx.derive_id(get_id_for_impl(&inner_impl.for_, inner_impl.trait_.as_ref(), cx));
     let aliases = if aliases.is_empty() {
         String::new()
     } else {
@@ -1752,9 +1750,9 @@ pub(crate) fn render_impl_summary(
     write!(w, "<h3 class=\"code-header in-band\">");
 
     if let Some(use_absolute) = use_absolute {
-        write!(w, "{}", i.inner_impl().print(use_absolute, cx));
+        write!(w, "{}", inner_impl.print(use_absolute, cx));
         if show_def_docs {
-            for it in &i.inner_impl().items {
+            for it in &inner_impl.items {
                 if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
                     w.write_str("<span class=\"where fmt-newline\">  ");
                     assoc_type(
@@ -1772,11 +1770,11 @@ pub(crate) fn render_impl_summary(
             }
         }
     } else {
-        write!(w, "{}", i.inner_impl().print(false, cx));
+        write!(w, "{}", inner_impl.print(false, cx));
     }
     write!(w, "</h3>");
 
-    let is_trait = i.inner_impl().trait_.is_some();
+    let is_trait = inner_impl.trait_.is_some();
     if is_trait {
         if let Some(portability) = portability(&i.impl_item, Some(parent)) {
             write!(w, "<span class=\"item-info\">{}</span>", portability);
@@ -1970,6 +1968,70 @@ fn small_url_encode(s: String) -> String {
     }
 }
 
+pub(crate) fn sidebar_render_assoc_items(
+    cx: &Context<'_>,
+    out: &mut Buffer,
+    id_map: &mut IdMap,
+    concrete: Vec<&Impl>,
+    synthetic: Vec<&Impl>,
+    blanket_impl: Vec<&Impl>,
+) {
+    let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| {
+        let mut links = FxHashSet::default();
+
+        let mut ret = impls
+            .iter()
+            .filter_map(|it| {
+                let trait_ = it.inner_impl().trait_.as_ref()?;
+                let encoded =
+                    id_map.derive(get_id_for_impl(&it.inner_impl().for_, Some(trait_), cx));
+
+                let i_display = format!("{:#}", trait_.print(cx));
+                let out = Escape(&i_display);
+                let prefix = match it.inner_impl().polarity {
+                    ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
+                    ty::ImplPolarity::Negative => "!",
+                };
+                let generated = format!("<a href=\"#{}\">{}{}</a>", encoded, prefix, out);
+                if links.insert(generated.clone()) { Some(generated) } else { None }
+            })
+            .collect::<Vec<String>>();
+        ret.sort();
+        ret
+    };
+
+    let concrete_format = format_impls(concrete, id_map);
+    let synthetic_format = format_impls(synthetic, id_map);
+    let blanket_format = format_impls(blanket_impl, id_map);
+
+    if !concrete_format.is_empty() {
+        print_sidebar_block(
+            out,
+            "trait-implementations",
+            "Trait Implementations",
+            concrete_format.iter(),
+        );
+    }
+
+    if !synthetic_format.is_empty() {
+        print_sidebar_block(
+            out,
+            "synthetic-implementations",
+            "Auto Trait Implementations",
+            synthetic_format.iter(),
+        );
+    }
+
+    if !blanket_format.is_empty() {
+        print_sidebar_block(
+            out,
+            "blanket-implementations",
+            "Blanket Implementations",
+            blanket_format.iter(),
+        );
+    }
+}
+
 fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
     let did = it.item_id.expect_def_id();
     let cache = cx.cache();
@@ -2018,65 +2080,12 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
                 sidebar_deref_methods(cx, out, impl_, v, &mut derefs, &mut used_links);
             }
 
-            let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| {
-                let mut links = FxHashSet::default();
-
-                let mut ret = impls
-                    .iter()
-                    .filter_map(|it| {
-                        let trait_ = it.inner_impl().trait_.as_ref()?;
-                        let encoded =
-                            id_map.derive(get_id_for_impl(&it.inner_impl().for_, Some(trait_), cx));
-
-                        let i_display = format!("{:#}", trait_.print(cx));
-                        let out = Escape(&i_display);
-                        let prefix = match it.inner_impl().polarity {
-                            ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
-                            ty::ImplPolarity::Negative => "!",
-                        };
-                        let generated = format!("<a href=\"#{}\">{}{}</a>", encoded, prefix, out);
-                        if links.insert(generated.clone()) { Some(generated) } else { None }
-                    })
-                    .collect::<Vec<String>>();
-                ret.sort();
-                ret
-            };
-
             let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
                 v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_auto());
             let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) =
                 concrete.into_iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_blanket());
 
-            let concrete_format = format_impls(concrete, &mut id_map);
-            let synthetic_format = format_impls(synthetic, &mut id_map);
-            let blanket_format = format_impls(blanket_impl, &mut id_map);
-
-            if !concrete_format.is_empty() {
-                print_sidebar_block(
-                    out,
-                    "trait-implementations",
-                    "Trait Implementations",
-                    concrete_format.iter(),
-                );
-            }
-
-            if !synthetic_format.is_empty() {
-                print_sidebar_block(
-                    out,
-                    "synthetic-implementations",
-                    "Auto Trait Implementations",
-                    synthetic_format.iter(),
-                );
-            }
-
-            if !blanket_format.is_empty() {
-                print_sidebar_block(
-                    out,
-                    "blanket-implementations",
-                    "Blanket Implementations",
-                    blanket_format.iter(),
-                );
-            }
+            sidebar_render_assoc_items(cx, out, &mut id_map, concrete, synthetic, blanket_impl);
         }
     }
 }
@@ -2346,9 +2355,54 @@ fn print_sidebar_section(
     buf.push_str("</section>")
 }
 
+/// Returns the list of implementations for the primitive reference type, filtering out any
+/// implementations that are on concrete or partially generic types, only keeping implementations
+/// of the form `impl<T> Trait for &T`.
+pub(crate) fn get_filtered_impls_for_reference<'a>(
+    shared: &'a Rc<SharedContext<'_>>,
+    it: &clean::Item,
+) -> (Vec<&'a Impl>, Vec<&'a Impl>, Vec<&'a Impl>) {
+    let def_id = it.item_id.expect_def_id();
+    // If the reference primitive is somehow not defined, exit early.
+    let Some(v) = shared.cache.impls.get(&def_id) else { return (Vec::new(), Vec::new(), Vec::new()) };
+    // Since there is no "direct implementation" on the reference primitive type, we filter out
+    // every implementation which isn't a trait implementation.
+    let traits: Vec<_> = v.iter().filter(|i| i.inner_impl().trait_.is_some()).collect();
+    let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
+        traits.into_iter().partition(|t| t.inner_impl().kind.is_auto());
+
+    let (blanket_impl, concrete): (Vec<&Impl>, _) =
+        concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
+    // Now we keep only references over full generic types.
+    let concrete: Vec<_> = concrete
+        .into_iter()
+        .filter(|t| match t.inner_impl().for_ {
+            clean::Type::BorrowedRef { ref type_, .. } => type_.is_full_generic(),
+            _ => false,
+        })
+        .collect();
+
+    (concrete, synthetic, blanket_impl)
+}
+
 fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
     let mut sidebar = Buffer::new();
-    sidebar_assoc_items(cx, &mut sidebar, it);
+
+    if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
+        sidebar_assoc_items(cx, &mut sidebar, it);
+    } else {
+        let shared = Rc::clone(&cx.shared);
+        let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&shared, it);
+
+        sidebar_render_assoc_items(
+            cx,
+            &mut sidebar,
+            &mut IdMap::new(),
+            concrete,
+            synthetic,
+            blanket_impl,
+        );
+    }
 
     if !sidebar.is_empty() {
         write!(buf, "<section>{}</section>", sidebar.into_inner());
index 710064a37d0415e1cac3ff91d11b767c4defc195..d63d4c2d159bab355547cfca026cbbb61e4b52a3 100644 (file)
 use std::rc::Rc;
 
 use super::{
-    collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_section,
-    notable_traits_decl, render_assoc_item, render_assoc_items, render_attributes_in_code,
-    render_attributes_in_pre, render_impl, render_rightside, render_stability_since_raw,
-    AssocItemLink, Context, ImplRenderingParameters,
+    collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
+    item_ty_to_section, notable_traits_decl, render_all_impls, render_assoc_item,
+    render_assoc_items, render_attributes_in_code, render_attributes_in_pre, render_impl,
+    render_rightside, render_stability_since_raw, AssocItemLink, Context, ImplRenderingParameters,
 };
 use crate::clean;
 use crate::config::ModuleSorting;
@@ -530,7 +530,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
                 name = name,
                 generics = f.generics.print(cx),
                 where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
-                decl = f.decl.full_print(header_len, 0, header.asyncness, cx),
+                decl = f.decl.full_print(header_len, 0, cx),
                 notable_traits = notable_traits_decl(&f.decl, cx),
             );
         });
@@ -1371,8 +1371,18 @@ fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &c
 }
 
 fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
+    let def_id = it.item_id.expect_def_id();
     document(w, cx, it, None, HeadingOffset::H2);
-    render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
+    if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
+        render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
+    } else {
+        // We handle the "reference" primitive type on its own because we only want to list
+        // implementations on generic types.
+        let shared = Rc::clone(&cx.shared);
+        let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&shared, it);
+
+        render_all_impls(w, cx, it, &concrete, &synthetic, &blanket_impl);
+    }
 }
 
 fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
index deed6eaf0cb6b73623d6ab957f7d9a0d5851ce3f..fc8fde3c8ecdd89261752379fabc66b84b50a7bf 100644 (file)
@@ -207,7 +207,6 @@ h1, h2, h3, h4, h5, h6,
 a.source,
 .search-input,
 .search-results .result-name,
-.content table td:first-child > a,
 .item-left > a,
 .out-of-band,
 span.since,
@@ -216,7 +215,6 @@ details.rustdoc-toggle > summary::before,
 div.impl-items > div:not(.docblock):not(.item-info),
 .content ul.crate a.crate,
 a.srclink,
-#main-content > .since,
 #help-button > button,
 details.rustdoc-toggle.top-doc > summary,
 details.rustdoc-toggle.top-doc > summary::before,
@@ -710,7 +708,7 @@ pre, .rustdoc.source .example-wrap {
        top: inherit;
 }
 
-.content table:not(.table-display) {
+.content table {
        border-spacing: 0 5px;
 }
 .content td { vertical-align: top; }
@@ -759,20 +757,6 @@ pre, .rustdoc.source .example-wrap {
        margin-bottom: 15px;
 }
 
-.content .docblock > .impl-items {
-       margin-left: 20px;
-       margin-top: -34px;
-}
-.content .docblock >.impl-items .table-display {
-       margin: 0;
-}
-.content .docblock >.impl-items table td {
-       padding: 0;
-}
-.content .docblock > .impl-items .table-display {
-       border: none;
-}
-
 .item-info {
        display: block;
 }
@@ -1003,6 +987,9 @@ so that we can apply CSS-filters to change the arrow color in themes */
        width: 100%;
        background-color: var(--button-background-color);
 }
+.search-input:focus {
+       border-color: var(--search-input-focused-border-color);
+}
 
 .search-results {
        display: none;
@@ -1183,6 +1170,12 @@ so that we can apply CSS-filters to change the arrow color in themes */
        float: right;
 }
 
+.rightside:not(a),
+.out-of-band {
+       color: var(--right-side-color);
+}
+
+
 .impl-items .srclink, .impl .srclink, .methods .srclink {
        /* Override header settings otherwise it's too bold */
        font-weight: normal;
@@ -1221,6 +1214,7 @@ a.test-arrow:hover {
 
 .code-attribute {
        font-weight: 300;
+       color: var(--code-attribute-color);
 }
 
 .item-spacer {
@@ -1257,12 +1251,6 @@ h3.variant {
        margin-left: 24px;
 }
 
-.toggle-label {
-       display: inline-block;
-       margin-left: 4px;
-       margin-top: 3px;
-}
-
 :target > code, :target > .code-header {
        opacity: 1;
 }
@@ -1500,6 +1488,16 @@ pre.rust {
        background-color: var(--button-background-color);
 }
 
+#copy-path {
+       color: var(--copy-path-button-color);
+}
+#copy-path > img {
+       filter: var(--copy-path-img-filter);
+}
+#copy-path:hover > img {
+       filter: var(--copy-path-img-hover-filter);
+}
+
 @keyframes rotating {
        from {
                transform: rotate(0deg);
@@ -1563,33 +1561,6 @@ kbd {
        width: 100%;
 }
 
-.table-display {
-       width: 100%;
-       border: 0;
-       border-collapse: collapse;
-       border-spacing: 0;
-       font-size: 1rem;
-}
-
-.table-display tr td:first-child {
-       padding-right: 0;
-}
-
-.table-display tr td:last-child {
-       float: right;
-}
-.table-display .out-of-band {
-       position: relative;
-       font-size: 1.125rem;
-       display: block;
-}
-
-.table-display td:hover .anchor {
-       display: block;
-       top: 2px;
-       left: -5px;
-}
-
 #main-content > ul {
        padding-left: 10px;
 }
@@ -1650,6 +1621,12 @@ details.rustdoc-toggle > summary::before {
        opacity: .5;
 }
 
+details.rustdoc-toggle > summary.hideme > span,
+details.rustdoc-toggle > summary::before,
+.more-examples-toggle summary, .more-examples-toggle .hide-more {
+       color: var(--toggles-color);
+}
+
 /* Screen readers see the text version at the end the line.
        Visual readers see the icon at the start of the line, but small and transparent. */
 details.rustdoc-toggle > summary::after {
@@ -2081,7 +2058,7 @@ in storage.js plus the media query with (min-width: 701px)
                height: 73px;
        }
 
-       #main-content > table:not(.table-display) td {
+       #main-content > table td {
                word-break: break-word;
                width: 50%;
        }
index 1efa67a44b5a0b394d7eb673c4c7d8d6a43cadd1..be359a8e72d25d250631a2f651dfb343454b9f04 100644 (file)
@@ -16,6 +16,13 @@ Original by Dempfi (https://github.com/dempfi/ayu)
        --headings-border-bottom-color: #5c6773;
        --border-color: #5c6773;
        --button-background-color: #141920;
+       --right-side-color: grey;
+       --code-attribute-color: #999;
+       --toggles-color: #999;
+       --search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */
+       --copy-path-button-color: #fff;
+       --copy-path-img-filter: invert(70%);
+       --copy-path-img-hover-filter: invert(100%);
 }
 
 .slider {
@@ -83,12 +90,13 @@ pre, .rustdoc.source .example-wrap {
 }
 
 .search-results a:hover {
-       background-color: #777;
+       color: #fff !important;
+       background-color: #3c3c3c;
 }
 
 .search-results a:focus {
-       color: #000 !important;
-       background-color: #c6afb3;
+       color: #fff !important;
+       background-color: #3c3c3c;
 }
 .search-results a {
        color: #0096cf;
@@ -157,11 +165,6 @@ body.source .example-wrap pre.rust a {
        background: #333;
 }
 
-details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
-       color: #999;
-}
-
 details.rustdoc-toggle > summary::before {
        filter: invert(100%);
 }
@@ -196,11 +199,6 @@ details.rustdoc-toggle > summary::before {
        background: none;
 }
 
-.rightside:not(a),
-.out-of-band {
-       color: grey;
-}
-
 .result-name .primitive > i, .result-name .keyword > i {
        color: #788797;
 }
@@ -241,11 +239,6 @@ a.test-arrow:hover {
        color: #c5c5c5;
 }
 
-.toggle-label,
-.code-attribute {
-       color: #999;
-}
-
 :target {
        background: rgba(255, 236, 164, 0.06);
        border-right: 3px solid rgba(255, 180, 76, 0.85);
@@ -341,7 +334,6 @@ individually rather than as a group) */
 /* FIXME: these rules should be at the bottom of the file but currently must be
 above the `@media (max-width: 700px)` rules due to a bug in the css checker */
 /* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */
-.search-input:focus {}
 .content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,
 .block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro {}
 .content span.struct,.content a.struct,.block a.current.struct {}
@@ -428,16 +420,6 @@ kbd {
        filter: invert(100);
 }
 
-#copy-path {
-       color: #fff;
-}
-#copy-path > img {
-       filter: invert(70%);
-}
-#copy-path:hover > img {
-       filter: invert(100%);
-}
-
 #settings-menu > a:hover, #settings-menu > a:focus,
 #help-button > button:hover, #help-button > button:focus {
        border-color: #e0e0e0;
@@ -471,9 +453,6 @@ kbd {
        border-color: white;
        color: white;
 }
-.more-examples-toggle summary, .more-examples-toggle .hide-more {
-       color: #999;
-}
 .scraped-example .example-wrap .rust span.highlight {
        background: rgb(91, 59, 1);
 }
index d5cd47c3e19d5f00c5c4245c7bd1195e4ea937a3..f633abe94e5af075b6b14973faadc2b88ab71623 100644 (file)
        --headings-border-bottom-color: #d2d2d2;
        --border-color: #e0e0e0;
        --button-background-color: #f0f0f0;
+       --right-side-color: grey;
+       --code-attribute-color: #999;
+       --toggles-color: #999;
+       --search-input-focused-border-color: #008dfd;
+       --copy-path-button-color: #999;
+       --copy-path-img-filter: invert(50%);
+       --copy-path-img-hover-filter: invert(65%);
 }
 
 .slider {
@@ -129,18 +136,12 @@ body.source .example-wrap pre.rust a {
        background: #333;
 }
 
-details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
-       color: #999;
-}
-
 details.rustdoc-toggle > summary::before {
        filter: invert(100%);
 }
 
 .search-input {
        color: #111;
-       border-color: #f0f0f0;
 }
 
 #crate-search-div::after {
@@ -154,10 +155,6 @@ details.rustdoc-toggle > summary::before {
        filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);
 }
 
-.search-input:focus {
-       border-color: #008dfd;
-}
-
 .stab { background: #314559; }
 
 .stab.portability > code {
@@ -165,11 +162,6 @@ details.rustdoc-toggle > summary::before {
        background: none;
 }
 
-.rightside:not(a),
-.out-of-band {
-       color: grey;
-}
-
 .line-numbers :target { background-color: transparent; }
 
 /* Code highlighting */
@@ -197,11 +189,6 @@ a.test-arrow:hover{
        background-color: #4e8bca;
 }
 
-.toggle-label,
-.code-attribute {
-       color: #999;
-}
-
 :target {
        background-color: #494a3d;
        border-right: 3px solid #bb7410;
@@ -302,16 +289,6 @@ kbd {
        border-color: #ffb900;
 }
 
-#copy-path {
-       color: #999;
-}
-#copy-path > img {
-       filter: invert(50%);
-}
-#copy-path:hover > img {
-       filter: invert(65%);
-}
-
 .search-results .result-name span.alias {
        color: #fff;
 }
@@ -335,9 +312,6 @@ kbd {
        border-color: white;
        color: white;
 }
-.more-examples-toggle summary, .more-examples-toggle .hide-more {
-       color: #999;
-}
 .scraped-example .example-wrap .rust span.highlight {
        background: rgb(91, 59, 1);
 }
index cff70268144f35852468925b80424e7c1fdcc47d..875bb79302560f4b1754ab6a5c78470123abf6cb 100644 (file)
        --headings-border-bottom-color: #ddd;
        --border-color: #e0e0e0;
        --button-background-color: #fff;
+       --right-side-color: grey;
+       --code-attribute-color: #999;
+       --toggles-color: #999;
+       --search-input-focused-border-color: #66afe9;
+       --copy-path-button-color: #999;
+       --copy-path-img-filter: invert(50%);
+       --copy-path-img-hover-filter: invert(35%);
 }
 
 .slider {
@@ -125,11 +132,6 @@ body.source .example-wrap pre.rust a {
        background: #eee;
 }
 
-details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
-       color: #999;
-}
-
 #crate-search-div::after {
        /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
        filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);
@@ -141,18 +143,9 @@ details.rustdoc-toggle > summary::before {
        filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);
 }
 
-.search-input:focus {
-       border-color: #66afe9;
-}
-
 .stab { background: #FFF5D6; border-color: #FFC600; }
 .stab.portability > code { background: none; }
 
-.rightside:not(a),
-.out-of-band {
-       color: grey;
-}
-
 .line-numbers :target { background-color: transparent; }
 
 /* Code highlighting */
@@ -182,11 +175,6 @@ a.test-arrow:hover{
        background-color: #4e8bca;
 }
 
-.toggle-label,
-.code-attribute {
-       color: #999;
-}
-
 :target {
        background: #FDFFD3;
        border-right: 3px solid #AD7C37;
@@ -282,16 +270,6 @@ kbd {
        border-color: #717171;
 }
 
-#copy-path {
-       color: #999;
-}
-#copy-path > img {
-       filter: invert(50%);
-}
-#copy-path:hover > img {
-       filter: invert(35%);
-}
-
 .search-results .result-name span.alias {
        color: #000;
 }
@@ -314,9 +292,6 @@ kbd {
        border-color: black;
        color: black;
 }
-.more-examples-toggle summary, .more-examples-toggle .hide-more {
-       color: #999;
-}
 .scraped-example .example-wrap .rust span.highlight {
        background: #fcffd6;
 }
index c4e8b6f5f8449d103513ac647a2ba0aae06883df..20b9eb1c27e92cb046a2f55757e3c64e3e99ffd2 100644 (file)
@@ -46,10 +46,14 @@ pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
             clean::KeywordItem => return None,
             clean::StrippedItem(ref inner) => {
                 match &**inner {
-                    // We document non-empty stripped modules as with `Module::is_stripped` set to
+                    // We document stripped modules as with `Module::is_stripped` set to
                     // `true`, to prevent contained items from being orphaned for downstream users,
                     // as JSON does no inlining.
-                    clean::ModuleItem(m) if !m.items.is_empty() => from_clean_item(item, self.tcx),
+                    clean::ModuleItem(_)
+                        if self.imported_items.contains(&item_id.expect_def_id()) =>
+                    {
+                        from_clean_item(item, self.tcx)
+                    }
                     _ => return None,
                 }
             }
diff --git a/src/librustdoc/json/import_finder.rs b/src/librustdoc/json/import_finder.rs
new file mode 100644 (file)
index 0000000..c5c687d
--- /dev/null
@@ -0,0 +1,38 @@
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def_id::DefId;
+
+use crate::{
+    clean::{self, Import, ImportSource, Item},
+    fold::DocFolder,
+};
+
+/// Get the id's of all items that are `pub use`d in the crate.
+///
+/// We need this to know if a stripped module is `pub use mod::*`, to decide
+/// if it needs to be kept in the index, despite being stripped.
+///
+/// See [#100973](https://github.com/rust-lang/rust/issues/100973) and
+/// [#101103](https://github.com/rust-lang/rust/issues/101103) for times when
+/// this information is needed.
+pub(crate) fn get_imports(krate: clean::Crate) -> (clean::Crate, FxHashSet<DefId>) {
+    let mut finder = ImportFinder { imported: FxHashSet::default() };
+    let krate = finder.fold_crate(krate);
+    (krate, finder.imported)
+}
+
+struct ImportFinder {
+    imported: FxHashSet<DefId>,
+}
+
+impl DocFolder for ImportFinder {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        match *i.kind {
+            clean::ImportItem(Import { source: ImportSource { did: Some(did), .. }, .. }) => {
+                self.imported.insert(did);
+                Some(i)
+            }
+
+            _ => Some(self.fold_item_recur(i)),
+        }
+    }
+}
index b78f8f2b4f1092620b07bfa1f5e25ac259a0b3d7..6a1409c739424cf3c8533bb4fc925f2134c8b739 100644 (file)
@@ -5,6 +5,7 @@
 //! docs for usage and details.
 
 mod conversions;
+mod import_finder;
 
 use std::cell::RefCell;
 use std::fs::{create_dir_all, File};
@@ -12,7 +13,7 @@
 use std::path::PathBuf;
 use std::rc::Rc;
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
@@ -39,6 +40,7 @@ pub(crate) struct JsonRenderer<'tcx> {
     /// The directory where the blob will be written to.
     out_path: PathBuf,
     cache: Rc<Cache>,
+    imported_items: FxHashSet<DefId>,
 }
 
 impl<'tcx> JsonRenderer<'tcx> {
@@ -159,12 +161,16 @@ fn init(
         tcx: TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error> {
         debug!("Initializing json renderer");
+
+        let (krate, imported_items) = import_finder::get_imports(krate);
+
         Ok((
             JsonRenderer {
                 tcx,
                 index: Rc::new(RefCell::new(FxHashMap::default())),
                 out_path: options.output,
                 cache: Rc::new(cache),
+                imported_items,
             },
             krate,
         ))
index 8aede1e77a27497d8112101ededd6f4a0c95ce69..92380d124292d0a8a3a107fa52a626172163b10d 100644 (file)
@@ -8,6 +8,7 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(drain_filter)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(test)]
 #![feature(never_type)]
index 7d7a63c53847a501ed20f29b785715d60144789f..c27f0ce18c1414d027453b4e8d2799105c980cfa 100644 (file)
@@ -477,7 +477,7 @@ fn resolve<'path>(
             // If there's no `::`, it's not an associated item.
             // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
             .ok_or_else(|| {
-                debug!("found no `::`, assumming {} was correctly not in scope", item_name);
+                debug!("found no `::`, assuming {} was correctly not in scope", item_name);
                 UnresolvedPath {
                     item_id,
                     module_id,
@@ -750,7 +750,7 @@ fn resolve_associated_trait_item<'a>(
 ///
 /// This is just a wrapper around [`TyCtxt::impl_item_implementor_ids()`] and
 /// [`TyCtxt::associated_item()`] (with some helpful logging added).
-#[instrument(level = "debug", skip(tcx))]
+#[instrument(level = "debug", skip(tcx), ret)]
 fn trait_assoc_to_impl_assoc_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_id: DefId,
@@ -760,9 +760,7 @@ fn trait_assoc_to_impl_assoc_item<'tcx>(
     debug!(?trait_to_impl_assoc_map);
     let impl_assoc_id = *trait_to_impl_assoc_map.get(&trait_assoc_id)?;
     debug!(?impl_assoc_id);
-    let impl_assoc = tcx.associated_item(impl_assoc_id);
-    debug!(?impl_assoc);
-    Some(impl_assoc)
+    Some(tcx.associated_item(impl_assoc_id))
 }
 
 /// Given a type, return all trait impls in scope in `module` for that type.
@@ -1256,7 +1254,7 @@ fn resolve_with_disambiguator_cached(
         &mut self,
         key: ResolutionInfo,
         diag: DiagnosticInfo<'_>,
-        // If errors are cached then they are only reported on first ocurrence
+        // If errors are cached then they are only reported on first occurrence
         // which we want in some cases but not in others.
         cache_errors: bool,
     ) -> Option<(Res, Option<UrlFragment>)> {
index 2b12d118bca0e3968e0598e68a2a7a008fcb2599..765f7c61bd392dc433d5e2e5aa2c55ea95828992 100644 (file)
@@ -3,7 +3,7 @@
 
 use crate::clean::cfg::Cfg;
 use crate::clean::inline::{load_attrs, merge_attrs};
-use crate::clean::{Crate, Item};
+use crate::clean::{Crate, Item, ItemKind};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::passes::Pass;
@@ -26,30 +26,50 @@ struct CfgPropagator<'a, 'tcx> {
     cx: &'a mut DocContext<'tcx>,
 }
 
-impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> {
-    fn fold_item(&mut self, mut item: Item) -> Option<Item> {
-        let old_parent_cfg = self.parent_cfg.clone();
+impl<'a, 'tcx> CfgPropagator<'a, 'tcx> {
+    // Some items need to merge their attributes with their parents' otherwise a few of them
+    // (mostly `cfg` ones) will be missing.
+    fn merge_with_parent_attributes(&mut self, item: &mut Item) {
+        let check_parent = match &*item.kind {
+            // impl blocks can be in different modules with different cfg and we need to get them
+            // as well.
+            ItemKind::ImplItem(_) => false,
+            kind if kind.is_non_assoc() => true,
+            _ => return,
+        };
 
-        if item.kind.is_non_assoc() &&
-            let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) {
-            let hir = self.cx.tcx.hir();
-            let hir_id = hir.local_def_id_to_hir_id(def_id);
+        let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local())
+            else { return };
+
+        let hir = self.cx.tcx.hir();
+        let hir_id = hir.local_def_id_to_hir_id(def_id);
+
+        if check_parent {
             let expected_parent = hir.get_parent_item(hir_id);
+            // If parents are different, it means that `item` is a reexport and we need
+            // to compute the actual `cfg` by iterating through its "real" parents.
+            if self.parent == Some(expected_parent) {
+                return;
+            }
+        }
 
-            // If parents are different, it means that `item` is a reexport and we need to compute
-            // the actual `cfg` by iterating through its "real" parents.
-            if self.parent != Some(expected_parent) {
-                let mut attrs = Vec::new();
-                for (parent_hir_id, _) in hir.parent_iter(hir_id) {
-                    if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) {
-                        attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id()));
-                    }
-                }
-                let (_, cfg) =
-                    merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));
-                item.cfg = cfg;
+        let mut attrs = Vec::new();
+        for (parent_hir_id, _) in hir.parent_iter(hir_id) {
+            if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) {
+                attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id()));
             }
         }
+        let (_, cfg) = merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));
+        item.cfg = cfg;
+    }
+}
+
+impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> {
+    fn fold_item(&mut self, mut item: Item) -> Option<Item> {
+        let old_parent_cfg = self.parent_cfg.clone();
+
+        self.merge_with_parent_attributes(&mut item);
+
         let new_cfg = match (self.parent_cfg.take(), item.cfg.take()) {
             (None, None) => None,
             (Some(rc), None) | (None, Some(rc)) => Some(rc),
index 83ed3752a824cd541aa608be7c46fb97b1d234c3..a9d768f0149d6280d561806d47bb3d038f50e414 100644 (file)
@@ -91,7 +91,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             clean::ExternCrateItem { .. } => {}
             clean::ImportItem(ref imp) => {
                 // Because json doesn't inline imports from private modules, we need to mark
-                // the imported item as retained so it's impls won't be stripped.i
+                // the imported item as retained so it's impls won't be stripped.
                 //
                 // FIXME: Is it necessary to check for json output here: See
                 // https://github.com/rust-lang/rust/pull/100325#discussion_r941495215
index 36bb348ae58132a5936397df4ff1b771b7707985..c4891a9858bfe17b6c42cf8315058c5608bb4442 100644 (file)
     "tool is executed."
   ],
   "compiler": {
-    "date": "2022-08-09",
+    "date": "2022-08-19",
     "version": "beta"
   },
   "rustfmt": {
-    "date": "2022-08-09",
+    "date": "2022-08-20",
     "version": "nightly"
   },
   "checksums_sha256": {
-    "dist/2022-08-09/cargo-beta-aarch64-apple-darwin.tar.gz": "5d9f0ee2de50a18124fd506f493cbdf6cb6385944d32aca1aca9dcdf15bdef4d",
-    "dist/2022-08-09/cargo-beta-aarch64-apple-darwin.tar.xz": "683e8546ab86d98ec84204cdcdd2192d19a98c42c13bf0c69697865641238001",
-    "dist/2022-08-09/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "fb2a95793d79e04201dcb38fb5ccdb86f1c74503b181a0b3fce0f332e3380bec",
-    "dist/2022-08-09/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "5b1b826315990487dc0afe561fecd7f937d82bc8d2898742592349c9993cb3c8",
-    "dist/2022-08-09/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "23d20d9078154f6f03b3b056607b804ce3e049dfe4d949ccf430556c2f8e79b1",
-    "dist/2022-08-09/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "d7a9283bf838c1182e6cc8904b6b464cd9c1dd342078b2447309797868aec7ff",
-    "dist/2022-08-09/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "fb82a87e759d5ab3536a8edba682793653f51c15d8f27a874ecbff11c991b1fc",
-    "dist/2022-08-09/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "21de23c600646a3d5a9421761c0411d7e173876278548c42d6a8794abfc5d3d2",
-    "dist/2022-08-09/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "d931162577c04807b093d6cedcca989315b15b48f153c790f8ee2ce3edf479dd",
-    "dist/2022-08-09/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "797752acf6d0b5814ff1c6e7dd5e54fec0716677c4a11f03143c6e769ed34b1f",
-    "dist/2022-08-09/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "f080f5f486cbfbd09206cca7b70cb051da5e5a68914227a58ee81ecb5ed19c48",
-    "dist/2022-08-09/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "79964e35d780df520ace77ec8035652571709620ba49f14ac7bc59008fd712f8",
-    "dist/2022-08-09/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "339b969dcf283d0cedd0ffea09d534994c5bf588977ecfde61ce87e64090f70d",
-    "dist/2022-08-09/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "601b6b0f58652434d888320851867b9188cb5a99b5f18358b0d7376dd98d4a0a",
-    "dist/2022-08-09/cargo-beta-i686-pc-windows-gnu.tar.gz": "1c9944d71ff7ed9cd40be1df8fc828e7faa4f5496d917dc6ccc94a1b31839a12",
-    "dist/2022-08-09/cargo-beta-i686-pc-windows-gnu.tar.xz": "4e3fc72b845b821e3aa1193250a10d494592f3e0917c7716b5bd963d0ad08b73",
-    "dist/2022-08-09/cargo-beta-i686-pc-windows-msvc.tar.gz": "80559b267ab936cb08a7ef51087e63b61a215df64fa9f5254809705fa31ea3a6",
-    "dist/2022-08-09/cargo-beta-i686-pc-windows-msvc.tar.xz": "aee6122d25a0bf7e083b45e622858acf34be3e17a1f9964a2f0d9fc7dfdbe164",
-    "dist/2022-08-09/cargo-beta-i686-unknown-linux-gnu.tar.gz": "5e1f2c32adbdde68b7135d1e4c358076f5dd872c935ac1bbdcbfda0ff43e061f",
-    "dist/2022-08-09/cargo-beta-i686-unknown-linux-gnu.tar.xz": "f0e6acd5158430866ad0bed435a7e0dbd9f35130b4805b990050b3d9751b4416",
-    "dist/2022-08-09/cargo-beta-mips-unknown-linux-gnu.tar.gz": "99b71c9001b65408f42e65cf481a905bc30f77edc96401691fb9b122a20009fb",
-    "dist/2022-08-09/cargo-beta-mips-unknown-linux-gnu.tar.xz": "08d1f3824354af35fb90d6563a7a51775ff9574a9ffe0c87e897e377be778598",
-    "dist/2022-08-09/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "7dd3dc44fd37af40e587dba68d973b9d2cf40a939a97605a6adee5ba0f589215",
-    "dist/2022-08-09/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "2f638fc21bb6e11fd59ff07d66a1012d3336d6dbd5b73b2c42461f84415e333d",
-    "dist/2022-08-09/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "ade7f1ba6f19382980b0a6cbe3e8035932a60c898f7141782921d22398b1cf03",
-    "dist/2022-08-09/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "2fe5d3b4102320fb1e36198e8d6e43d201986a2c58e4ad45fc2acb23865cf09f",
-    "dist/2022-08-09/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "c99aa42005094a65bbeb41deb3499a2fd46032296f6509fd1bf108f7d4cbdd04",
-    "dist/2022-08-09/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "7c65e8e6d76cab786f628e4ca02b6af47f6c2c4a36123ee7b8fc059309ce6039",
-    "dist/2022-08-09/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "b7b98621ef835f6108c0d1ec60c88d66b462a3daf62ddfc796d31f4e09f7baca",
-    "dist/2022-08-09/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "f85473a1d6b33d9b865a6532ea444415c7cfaa3f76af39d637619ffdddd0c00b",
-    "dist/2022-08-09/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "e783ea66457a0aff31489cd42f549a2c9c33cbb2ca0aa253575a59c9de7f73f4",
-    "dist/2022-08-09/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "d90a02cb425320fb5a5b163d87ec03726159994af31b32954c91b1cb9eb3ebf4",
-    "dist/2022-08-09/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "ff1fda58f7bdb9df563172388f66f787a60f75bdd169ef8d2c791b27bbd8c6ce",
-    "dist/2022-08-09/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "df740d61415bf15c62f9656932370e08fea5a289ac25bec78a626e771d24ab7f",
-    "dist/2022-08-09/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "019dfff6fef8c7714dd19c64a5bb408b2b5063367ec1aa8a72960316aa880834",
-    "dist/2022-08-09/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "f8d025d2943b76d665500c9c72aab18a63ecd137e07c10d1463f1905b4274573",
-    "dist/2022-08-09/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "c379f3c122a9df41b66f13ca3dcb79feb9ae68798c9704dac3018d85ec96d895",
-    "dist/2022-08-09/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "69bd9bd12f4386c831aaa8e1fac8edf1a0e618d1f6e0e4bcb7be16f1eeb08d81",
-    "dist/2022-08-09/cargo-beta-x86_64-apple-darwin.tar.gz": "d74acf4f57681527af3a2c469e916bd9dc1ecdb591e16657757db493984de07a",
-    "dist/2022-08-09/cargo-beta-x86_64-apple-darwin.tar.xz": "00201568ce4b95c6618389ec86e00677a27435276dd1bec16fea44b87a2dce4b",
-    "dist/2022-08-09/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "3d049963cdda9755e524443a04b0b9c5566cb0e58dc61e13779484d92c3e0f69",
-    "dist/2022-08-09/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "c8f0c13771e010ed85002ee10e44ad7c0b21ce2ddd105c9b90fbe1896d0687f0",
-    "dist/2022-08-09/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "796d9da5a59c984a5a78afcfce762134e3a72e52525d0150ebe4bb29d207bd00",
-    "dist/2022-08-09/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "1ec2764428d4df9355380444158aaa2947c4fe00708e7a30bc6978433621d120",
-    "dist/2022-08-09/cargo-beta-x86_64-unknown-freebsd.tar.gz": "14643490b1259120b14a7be84942bfd324fdf03dcf473f33f7ae2466fb99f60b",
-    "dist/2022-08-09/cargo-beta-x86_64-unknown-freebsd.tar.xz": "3af267ab65b3c61b0184f8fb5b5cc5fb61688f9b668654986f30d3a794d9a1a6",
-    "dist/2022-08-09/cargo-beta-x86_64-unknown-illumos.tar.gz": "5b84826e0e68b6f9769ef7d00b4b1225cb1a4dde1b41f5b6021feb34e7376c63",
-    "dist/2022-08-09/cargo-beta-x86_64-unknown-illumos.tar.xz": "a1dde17fd13bfb626acd0ae65d88c440a3172e1fdb20aeefda3a205bad71d703",
-    "dist/2022-08-09/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "fedfd6a7b8156de19ed2d6b8f354affc4120fe311874e6563b9620634a5d962b",
-    "dist/2022-08-09/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "8701ba8c8fcf21623a690d3b7c00d50fc9949035af5aee092ff1239bed4a9784",
-    "dist/2022-08-09/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "beac64aa92687f975b3a0d5265d7c79ef3962c1d0f0e196296f67bf8e2b803d0",
-    "dist/2022-08-09/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "8b50c03102cfdf5ffff5fa7b51b0a4d159e24671be5430c77c07256e54a4fd12",
-    "dist/2022-08-09/cargo-beta-x86_64-unknown-netbsd.tar.gz": "dde29de6d56f02f5cdf35b96287e404ceed85372c3c671ee54972255369470fe",
-    "dist/2022-08-09/cargo-beta-x86_64-unknown-netbsd.tar.xz": "7e4d07676c4b33af0303436442dc763623784ed20293ed262780267b01843949",
-    "dist/2022-08-09/rust-std-beta-aarch64-apple-darwin.tar.gz": "63526962ddd66cd6b60f5bb348861caab7a78c7d80515baf4397cab857258d71",
-    "dist/2022-08-09/rust-std-beta-aarch64-apple-darwin.tar.xz": "64ba52408086b6c7e3578e2ded98528fd63466ec8d7f86045b55a575e0ca780b",
-    "dist/2022-08-09/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "261109cb02193cfa113697c9d769fcd4d4e265b01dbb4ca0bfa0e0d62f64c71e",
-    "dist/2022-08-09/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "7f2182b749a8980c2e7b4f31e5a8c72b8a9df8dd2552cda29d061e2236acc589",
-    "dist/2022-08-09/rust-std-beta-aarch64-apple-ios.tar.gz": "5abe9df533e7bfd62586483f20a1911be5eede5da6114b53b2a000c110e35768",
-    "dist/2022-08-09/rust-std-beta-aarch64-apple-ios.tar.xz": "2898b8ad95c6a67c2c296c4698acd043cadcb3a2b0449fb7515bfeb48db69a70",
-    "dist/2022-08-09/rust-std-beta-aarch64-fuchsia.tar.gz": "9f86fcd871ddef0fb86cdfb0084d1bf6fa150bb7cb4dfe3fcade13b75beea5a6",
-    "dist/2022-08-09/rust-std-beta-aarch64-fuchsia.tar.xz": "4aa91e4f7f3589085c2da45de78a16c48cfe9dd47541928db87ee964c3406b53",
-    "dist/2022-08-09/rust-std-beta-aarch64-linux-android.tar.gz": "910f4c1ad41d74306e7fdae43c8d04e7fc47724ae84b9276f2d264fbdf2b70f1",
-    "dist/2022-08-09/rust-std-beta-aarch64-linux-android.tar.xz": "cd60ac333fd684cb730c134cf5a037718254afb9aa65528b2463d76a138f07f7",
-    "dist/2022-08-09/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "39740739479c12203c9b6ae7c72f0e542c92750e08b2ca66c5e96355f1eea61f",
-    "dist/2022-08-09/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "1c7fb416b404c401f34d4461c61c95ffbaa5b50d8c95d090485aabe12cc78a0c",
-    "dist/2022-08-09/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "8cd2b395607ba16cac4a4fb85f1c5ccf9626849a8e11dc66e911053a6cd1df1b",
-    "dist/2022-08-09/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "c7ef35d4bb2ab6b8ad762349821b6e076851bd5b51dddb7a3b1678b78e21cb42",
-    "dist/2022-08-09/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "6410dc79e6e00eca4e483b438ef8a314a55ea6857c618efd50a32a2f95195df8",
-    "dist/2022-08-09/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "4d674cbb7d417944a1aaaa23e8c654ac9276529fed3639c75421e1de1e7bfcc2",
-    "dist/2022-08-09/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "1719104655a62e8300df06fb4636543532821c0ac43dcf90435d5fbbf39c12c1",
-    "dist/2022-08-09/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "bf3c12dae8fee831402f9700295d9a6718d6a6046a7e5a0d0748c3f2e3d82224",
-    "dist/2022-08-09/rust-std-beta-aarch64-unknown-none.tar.gz": "727621bd08ad0e879a79635fb00c187de6d23e0291143b494d3965cacb35d358",
-    "dist/2022-08-09/rust-std-beta-aarch64-unknown-none.tar.xz": "6b152098c76b2a3367dad676e4c3d328e5d5c89c95504b041e1997e5d141404a",
-    "dist/2022-08-09/rust-std-beta-arm-linux-androideabi.tar.gz": "c78d9c97e742ef1777679743765de5d475dffe62ea9b60efe2025eb91ba7ba5c",
-    "dist/2022-08-09/rust-std-beta-arm-linux-androideabi.tar.xz": "1029382048bce0b8e556b87008821f8b4c5c92e30b340c9a8086e32a8ca7f105",
-    "dist/2022-08-09/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "d4b8bb607968ca49d840c1835fc56e92006dd186c7ed71663a23b7495fa392e9",
-    "dist/2022-08-09/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "562dcbfb8ddd31e64939844055c3dbd87a4c04065ad34dbe3a2d87136c0bb4b4",
-    "dist/2022-08-09/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "1d8e8d87ce8f1ee5e8cb946c8b7a92e6f4a56ddd6b3afd1c646e4d5cdb703608",
-    "dist/2022-08-09/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "ce8edce3a2976694a8ca0cff0b296b331f64e0afa6b5cb107bf03e2aff5949c1",
-    "dist/2022-08-09/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "d57aff420435c76ff8bfaaaa8d94bce62d96299a2a0158b67b9fe914695cc188",
-    "dist/2022-08-09/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "7eecf0facd3f2dd236e5f731eaf3fbc51b46d1a039f762f5bb42aabd0ab21c00",
-    "dist/2022-08-09/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "6b6341eeca9a48e1c15b03501428ebdd2f591f4196c50d988408a1c591152fb0",
-    "dist/2022-08-09/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "019e36e7c8855ef9d1277d4f5388862412c6d49e7f16d6808d3a6f69c60e5030",
-    "dist/2022-08-09/rust-std-beta-armebv7r-none-eabi.tar.gz": "41b1cfbcfd16061d52413e0bf2503756ffbe819b4ef2d81f8570e477e0b5893b",
-    "dist/2022-08-09/rust-std-beta-armebv7r-none-eabi.tar.xz": "209828e95d236ee218a10f468b12d64e4f4bb773a0cbfc247e6f54c2aacdc8a5",
-    "dist/2022-08-09/rust-std-beta-armebv7r-none-eabihf.tar.gz": "762a5764e926cb081062040cc4f43f8653eab007ac9cb8600751c0f364f17639",
-    "dist/2022-08-09/rust-std-beta-armebv7r-none-eabihf.tar.xz": "eb9b66ad16ff5c7427112ed5cf73498a02694b7b3af37220e3160bb6a16eca1c",
-    "dist/2022-08-09/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "369b3afe600692f552f7d0bdd310c7b254f8745948e5a4ffff7c5fccf0873ce4",
-    "dist/2022-08-09/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "2cdeb7b58e979bec71aa0a67a95ede5b55ab6ac295b24b08c67e651c4a76b13a",
-    "dist/2022-08-09/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "1a31c291792ba44053c9701d8e665c62155cb319b371359c7f0f9b5b81269f6b",
-    "dist/2022-08-09/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "54b17f4959cff54daf926f33dad8141663366856f691f4ca1015fedf36720022",
-    "dist/2022-08-09/rust-std-beta-armv7-linux-androideabi.tar.gz": "77ca2251056b76db72b9e8795dfc1b9583544f35dd067435128b2336b33aa892",
-    "dist/2022-08-09/rust-std-beta-armv7-linux-androideabi.tar.xz": "888b80410a8f9f1f85ec379c4e5490fc18bfb3f7e4954fa66f9b9c27ea92d121",
-    "dist/2022-08-09/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "3b8132040574da39cafbf48cc1e2535ab1c52c51ac2968aaf167911bb4bab648",
-    "dist/2022-08-09/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "915acd9a715cb25db4e899315afbb2b97ad34aee52a7f4536b4e684295e93e8b",
-    "dist/2022-08-09/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "9a1e59513f6812f631fa4926ea794b05524e58cd4d36a55b7a4e286b2e7bd506",
-    "dist/2022-08-09/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "017892f81ce10323b76dd32347d5ba921003177fd95e5d4b4972ad4e84e699c8",
-    "dist/2022-08-09/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "3a7b2f2c4d06135a9ff3931a1a9c0f4431bb3a31763501bbad1dbfb85849e681",
-    "dist/2022-08-09/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "6226c7228337739435cd7194fe3c233250fb2eb8df4dd16c9ef637b2d91c1807",
-    "dist/2022-08-09/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "48b626650f72a7e3885ea2aabbb8c520b079ebda0f798f685392501f1ef7fd79",
-    "dist/2022-08-09/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "627a0be5e0059cc07a4bfd99a0f70e009367c7be6ea45eb4ac0f8554680309e4",
-    "dist/2022-08-09/rust-std-beta-armv7a-none-eabi.tar.gz": "2489ef3102a8b0ba9885c092309a2e7deaf65721c934a83259fa7f7698440638",
-    "dist/2022-08-09/rust-std-beta-armv7a-none-eabi.tar.xz": "0e43df943f9550e374ba9334a0bd68f3bd107dc68ee8012f92357aaa0bf3851e",
-    "dist/2022-08-09/rust-std-beta-armv7r-none-eabi.tar.gz": "edb09fe24634386fe335685bbced045cd7448d1aad520f1cbaa4f0d38f3d38a1",
-    "dist/2022-08-09/rust-std-beta-armv7r-none-eabi.tar.xz": "2b170a322d07da39e949047871dd28444feaf49d09c901fbdd4015f00e456415",
-    "dist/2022-08-09/rust-std-beta-armv7r-none-eabihf.tar.gz": "82a69f097820c70c0fdc9b5f22b5378ab1d70d3d35bfec0ebab8b30ad7903178",
-    "dist/2022-08-09/rust-std-beta-armv7r-none-eabihf.tar.xz": "0301f9984effc3b186531aacb182e65fb57519c5ebd80f445c7346db27dfcc39",
-    "dist/2022-08-09/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "47bc8975498b6f6afdce3ef7d2d8d4b239b6219f5e4bae9841a82587e1279415",
-    "dist/2022-08-09/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "0806ef9782068d292106f3fce8b7bf879931fb89efc5e832d85f82bbffa99489",
-    "dist/2022-08-09/rust-std-beta-i586-pc-windows-msvc.tar.gz": "fb11022f5410c508936617b337d8940d82431544f77366ba6dbc3da81172bd21",
-    "dist/2022-08-09/rust-std-beta-i586-pc-windows-msvc.tar.xz": "326bc6a7dfe216b03222b187ed424ca6b83325f9a91e0b873d9294c713040a37",
-    "dist/2022-08-09/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "0a608449de9eca7fbb421263fee19d22a3950f68dee80ca343c8704b2a9fcefb",
-    "dist/2022-08-09/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "ca980e9d255d4444a329983565eb15807a26c0cdb48bfe763f9fdee061d8a9e4",
-    "dist/2022-08-09/rust-std-beta-i586-unknown-linux-musl.tar.gz": "db8c6517bb71bf49470b87cc1c9bd180c0421475bad04917be988c0933620db6",
-    "dist/2022-08-09/rust-std-beta-i586-unknown-linux-musl.tar.xz": "2feccd2d2ec54e25ac36ec2b9ff823887d353c9ca1106a29f8ca0f33f2e5d08a",
-    "dist/2022-08-09/rust-std-beta-i686-linux-android.tar.gz": "0ce00226f5aa2165d043108650e7444e165ae80c985c62f953b46fd680946b5a",
-    "dist/2022-08-09/rust-std-beta-i686-linux-android.tar.xz": "e591b8ae11fa7b6b8907d598e159c8795e4c3ff9c2c55e65773c29e488f64550",
-    "dist/2022-08-09/rust-std-beta-i686-pc-windows-gnu.tar.gz": "51fa05e5fb2d0d310b97c9e255ea3bc5ecb185093013406588cc96fddba18788",
-    "dist/2022-08-09/rust-std-beta-i686-pc-windows-gnu.tar.xz": "64d87c682eb1a2e0b8abd393358e1880016803bb7da699f2d239ad2d59e0eb0c",
-    "dist/2022-08-09/rust-std-beta-i686-pc-windows-msvc.tar.gz": "e3c2df5572996ade55a9af5b5b54a84fc0ff2edfcad164f57852ab0d3695d938",
-    "dist/2022-08-09/rust-std-beta-i686-pc-windows-msvc.tar.xz": "2991215756373d253ffd27a8f650613a5f2bb636adf263b664741772c594241a",
-    "dist/2022-08-09/rust-std-beta-i686-unknown-freebsd.tar.gz": "bf82e2e7734304f12d3ed5db591ece38a1078b575d92aab8f45328d087cf56ba",
-    "dist/2022-08-09/rust-std-beta-i686-unknown-freebsd.tar.xz": "73a3b79fe72e835a8b7dfdaba6a1b9c5ee8dde25534fcc520b0ee80a7853b31a",
-    "dist/2022-08-09/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "74e23ff14e240e935f630e19467bbc9e1b02e9962313dc74f8c444c96bcbfb2e",
-    "dist/2022-08-09/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "987003e5b23308f31f613a5a133466cd045c05a5998ab29e4d3d8ef15a8342d9",
-    "dist/2022-08-09/rust-std-beta-i686-unknown-linux-musl.tar.gz": "1c76bac0701c3f9352f4439d2daecb219c08964c6a48ceb212520b4a8e532e02",
-    "dist/2022-08-09/rust-std-beta-i686-unknown-linux-musl.tar.xz": "7007e60d8ba5e9e40f6aefa248b4881057a9b9a73aa9e7ff0c67a36de7748be3",
-    "dist/2022-08-09/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "0f6ca4637da137235a3e9315691f1b5c0afc2f853a855458ad6d10ea59ef8579",
-    "dist/2022-08-09/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "778557cf1c57ada5c1a64ecd58db3a49e8f874217664d53a8be0cfb89b031980",
-    "dist/2022-08-09/rust-std-beta-mips-unknown-linux-musl.tar.gz": "cbe799d70ca9a24645187d61198c40d495aeed8ef037570ed3cad95b898f6c82",
-    "dist/2022-08-09/rust-std-beta-mips-unknown-linux-musl.tar.xz": "ab37bff0f1c90a6adb9d603041d5fbe7c94dccfa05a6171145c41335350d02a9",
-    "dist/2022-08-09/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "3e5aa74f970a70614751d258b7958696457b03c3f8c6eb2b8e61f3395d9f9169",
-    "dist/2022-08-09/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "e32f82fa27968b9f9cc0bad083daae95cc21bc7f56b6fed8e57de39200398248",
-    "dist/2022-08-09/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "29247f72e5d5563dbfaff65876cd1181943c57121e27a979c11005734825de4f",
-    "dist/2022-08-09/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "1835664e58cd35261f7387be0746bfd821a8d8108ef8f26dc68db1b4886cc6b6",
-    "dist/2022-08-09/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "eb6826841be8177bead8edf3d06892219fe7e898e541d2a76539e49c7cf2caa7",
-    "dist/2022-08-09/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "25c2801f324985094cf3aa9aa56d88e2c73bcd1f7849fdbfd11032fb9d853bc9",
-    "dist/2022-08-09/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "573f981b5e197ef337812fb3bcc4ee513121067968d3d33e369426ec51cfdb8e",
-    "dist/2022-08-09/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "da6d57cff4999bec0e4249c0b1f1048eae925e793149c60f044b257f306d26bf",
-    "dist/2022-08-09/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "8637387cb7f722457e7cdbb6c75eb70fdb913a5543adb1e4dd81d7316f0d2520",
-    "dist/2022-08-09/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "539a0a66e06fe7b49e40b2615c3d04611236746419bf03f5439b14cc37f3344e",
-    "dist/2022-08-09/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "458734ed82bb7e3feb1d831ea6224cd4eeabfbcb06599181d025660298ef7bbe",
-    "dist/2022-08-09/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "64f0ce96ae9a99daa300d49d087837c7c619e4bdb38f41664d79844c84254c32",
-    "dist/2022-08-09/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "937c3b1481aeab47b45dcb8dc45c12f856a771615c3b6e56b04e10b4f8075d1d",
-    "dist/2022-08-09/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "05094bfba7b7fe1fe66f0643ed60079c675d739613e27cb64ca8a61b5faadcd0",
-    "dist/2022-08-09/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "d15c897c52bc02a241e9756c62b48c126d651d498a72a3cc70521e6a395bce7c",
-    "dist/2022-08-09/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "2182c3300e6cf5f7fba5a687235c34fa9e799beef2edbb07206205ede50964ad",
-    "dist/2022-08-09/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "cba214c9827f639f6c88de0bb28f81c58e81f1263b10ccb4fda5c84ad23ea036",
-    "dist/2022-08-09/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "f7f9bb0d56ebd4b80db0560d6f71b25028c97b99f79eb7ef89255d46ca4df22e",
-    "dist/2022-08-09/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "b190a078b408d184766831664df1a2d472a134909ad00f195fb84d522d360a56",
-    "dist/2022-08-09/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "31bcf275272e3a46618110219f61eefd5fdd2c11a75f7ff612fea012dbc3c4b5",
-    "dist/2022-08-09/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "eadde81672eda5af55c8f2eff6729ad134dd484ac16aef4fa0e402e0164f30df",
-    "dist/2022-08-09/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "2a5d69f4ec463377e2f9eca3a70647680d1ed09bef4f9a7b839d1d08eed989ca",
-    "dist/2022-08-09/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "89b9b9149461362d54b64b2cbdec317674266a9061fc0d46b438f664e003ac83",
-    "dist/2022-08-09/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "3c56a23f2fda148e442318bb5a21d895a5b61cc698db5ea9a1ff3c2740887fc4",
-    "dist/2022-08-09/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "94f9f155ce07f09ca12814b745cce5d6dfc731cc59c95fcd5b1831f60d9c04fb",
-    "dist/2022-08-09/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "b9f76d28c4e057d9b7eada2076c4358d6876aed1c32f65dfa50dc3e3c1970d79",
-    "dist/2022-08-09/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "e664018f445157229a0c07406d3fc4e7a19cb53722fc3838fcee1bbd3a3a00cf",
-    "dist/2022-08-09/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "8d48a304ba7ca9470ed5f88076f6c50477f6b3a1afe303aab772638df8978c32",
-    "dist/2022-08-09/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "347072268911f3a03223bd494cd2d14cfe4c553fc35e9d36571b54995e04d9aa",
-    "dist/2022-08-09/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "100d5a1e75b7c302f03eba8eb26c5c023e1b396cd44d7798f2902bf8f40ec48b",
-    "dist/2022-08-09/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "f5d91e04ac7980aa5253e0c90e7e312e42b5fa7de03f35f61fe11ab207894f50",
-    "dist/2022-08-09/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "0d83e81a8c48f9cc3e62442e51aee769cef4cc618a2661506a5fb9120163be25",
-    "dist/2022-08-09/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "96d983517839cbd1d64adfff4b3b0241ceed99573579f041d136be39aa2b7995",
-    "dist/2022-08-09/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "0eb2c70b7eeb3f754ffea3716e41dc3efae49e98d77ca1843541587dddd6b880",
-    "dist/2022-08-09/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "91fa2a025c04e41a7b9a7eb6b4cda351b93fc53801f97042ae0e76bd871d92e9",
-    "dist/2022-08-09/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "8ad9da4410688824d5adc6cb8ed42f76bb8a35d41bee62b5f7b44e0d6bd346bb",
-    "dist/2022-08-09/rust-std-beta-sparcv9-sun-solaris.tar.gz": "cb3a28d68f432a3357b6a971f046b5ea37fdad5d4aaa4aea7cc997356d487b75",
-    "dist/2022-08-09/rust-std-beta-sparcv9-sun-solaris.tar.xz": "746fb859655ed6b4379fce8937fff998952cb81297412091844b0e277ec65a23",
-    "dist/2022-08-09/rust-std-beta-thumbv6m-none-eabi.tar.gz": "8bab8c46c7e873d0fa0a7078675fa7a54a90e5342f8b58419e0dd434e9942b67",
-    "dist/2022-08-09/rust-std-beta-thumbv6m-none-eabi.tar.xz": "954b5c32e5515e09b77bcaa3a7c4e139905a4f3d1801b492069c027a8311bc6b",
-    "dist/2022-08-09/rust-std-beta-thumbv7em-none-eabi.tar.gz": "9eb56471c38528c2b80dea81d94e5368f68a977745a1e02449f3eae353ca405f",
-    "dist/2022-08-09/rust-std-beta-thumbv7em-none-eabi.tar.xz": "0334379d0e8c3ef9680837b1dfc96788da4836a91e42d71446461ece7217ab78",
-    "dist/2022-08-09/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "0c65cc553ca2730d020fd8a97b90ebfe2b3c0fc2755b137df55955a3d1c7908f",
-    "dist/2022-08-09/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "625a109a589fae6e2fb64376e3fec4bb39ca19217ad6d312df524129868f343b",
-    "dist/2022-08-09/rust-std-beta-thumbv7m-none-eabi.tar.gz": "e0002c917055c85b613297da21427fc3b6c5f55ee120921ee8bae9b99afec2b6",
-    "dist/2022-08-09/rust-std-beta-thumbv7m-none-eabi.tar.xz": "74cc0f5b245b483b62c9a9e8bd642069af5205ecc59fd0b7464ab1fd6f4f3f7e",
-    "dist/2022-08-09/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "98c09985ea2d56fcc8c219c46d355310b65fd4f7c6920df2e7ec5355848ba83d",
-    "dist/2022-08-09/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "5122e60b031458c4606905a3df5d64b7bac54bcf883c18ba53443aa76fc5c1cf",
-    "dist/2022-08-09/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "6ab96971e69a073a5789c3eaaa460a7f5d6a3a5df8ac5125344744dde8476706",
-    "dist/2022-08-09/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "be874a256076dd2869d6d5780c5b4e8c850e52a62b5d10087d7c1aca32b0b831",
-    "dist/2022-08-09/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "c37ab11b56d3ac41b8eeadbed09ae5e78467c8945cecb49c218fe91a284e43c0",
-    "dist/2022-08-09/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "dfa4d1dcfb32d4001b2b9f00a829afd699065dcc6538598eaa27d684a01facac",
-    "dist/2022-08-09/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "31931cdb16a9a81bf7fc779c8aef6890c1f35130ba1c323d8b548a5dd5494346",
-    "dist/2022-08-09/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "0aeb4ff0e9b139e3b5550103c6429cb3cb4b455335514b07491e22fa63719169",
-    "dist/2022-08-09/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "ba7077816ba6f1b6b386b0245249e10a1482b82eaec711561f912a1975482817",
-    "dist/2022-08-09/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "6a49c1907e0ce91a3650aeeb61f6674c39936b67366fa4bb197fc612e9ae5a49",
-    "dist/2022-08-09/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "0e268083c1935be97e3a96ca94b824c84877970a65c2e581f3e71d7364264dff",
-    "dist/2022-08-09/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "27510dbb922d9cc0ee669f3854ffeb1ca28c105b3284e3ba523abcb9cfc10055",
-    "dist/2022-08-09/rust-std-beta-wasm32-unknown-unknown.tar.gz": "6d2f49e7e75ca2e3873dd1530d4bc3eedcebf3b2db6b1e193c0d57d7daa681a3",
-    "dist/2022-08-09/rust-std-beta-wasm32-unknown-unknown.tar.xz": "5508d36c7ae20176af2c10a0c974d5162202e3914e79468b9541c3e1b585612a",
-    "dist/2022-08-09/rust-std-beta-wasm32-wasi.tar.gz": "721726c4b073b27df9abc9e47a2b82eb48ca12a44c87363ae57a632d26619fc9",
-    "dist/2022-08-09/rust-std-beta-wasm32-wasi.tar.xz": "320ae842da96d4ba3147ca338e91306ed602250320df5163a01748491599ade3",
-    "dist/2022-08-09/rust-std-beta-x86_64-apple-darwin.tar.gz": "2dd9b9defe95357d7af5ae81428be814efe9923c308a4c2f3a370b16d912707f",
-    "dist/2022-08-09/rust-std-beta-x86_64-apple-darwin.tar.xz": "17ea6b22feb7fef1211c319a3d9d0f7bcdd8cd215d3ddffc523a83cfeb8331a6",
-    "dist/2022-08-09/rust-std-beta-x86_64-apple-ios.tar.gz": "df3618fb0b30d89d567d238d4e744d8cff81ca07cef701876b4471a98768c810",
-    "dist/2022-08-09/rust-std-beta-x86_64-apple-ios.tar.xz": "60932e2848af4a25699e7d300833f0b8e10bc8dc201d4ac9dcda417f86413cb8",
-    "dist/2022-08-09/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "57db93d53efad36639645baf0cdfa47b4b70664e22a1eac3f08a5abedc0834ac",
-    "dist/2022-08-09/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "cea91317cf86ec301730a2ef8a1c68213b6a4921c105bab228e9bd8620641f2b",
-    "dist/2022-08-09/rust-std-beta-x86_64-fuchsia.tar.gz": "7b961a55c6616b02aa91a25eb9e2521bd50ac881120975ea3af92543adfdd8b5",
-    "dist/2022-08-09/rust-std-beta-x86_64-fuchsia.tar.xz": "3ce7314f2c8f3a00430a6686fa267a5b4a8ef20b28023b765aa326f0151d2521",
-    "dist/2022-08-09/rust-std-beta-x86_64-linux-android.tar.gz": "37d538db9ab3cad73c4cdfb0b3836f124a6a2e47dbd1f6aa54167451057ced2f",
-    "dist/2022-08-09/rust-std-beta-x86_64-linux-android.tar.xz": "600ea7bc318580195d3b4e681c5f374075ec40272641050f0fd6296da4a9d383",
-    "dist/2022-08-09/rust-std-beta-x86_64-pc-solaris.tar.gz": "7d389f2d2632068cde7e8f72e685a888462897f4d5aa98034060472443cb89ff",
-    "dist/2022-08-09/rust-std-beta-x86_64-pc-solaris.tar.xz": "60a6532403d902d71883169c2001d6b279f882bee4444bb8107e742e4cfa3ecc",
-    "dist/2022-08-09/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "76c93994bc6eaa7596ee91dd24f51685ab659533835d441352f88b89a0991236",
-    "dist/2022-08-09/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "fdba628daf4b04afc1ec1d8ac4b9460ffe0a230feaf61dd7b621e2ec02b09a2b",
-    "dist/2022-08-09/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "4ee478c238ec38ec4977fa8a1689aa28b7a2b0173549da92f1b2e1a2f6772aee",
-    "dist/2022-08-09/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "c732f3054a4a67f25242ba9acb5bfbc945e3ac62a2b0de5b7ede0990313984b5",
-    "dist/2022-08-09/rust-std-beta-x86_64-sun-solaris.tar.gz": "47a4e8d8cc03e402e480ce5f24326de7094622fe339e4441df7f6a6271a8775c",
-    "dist/2022-08-09/rust-std-beta-x86_64-sun-solaris.tar.xz": "260c93c4dafb20d476a965e2681751e38be15bfb96d32b10730e44a1d4da6079",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "9d7c63a2ced8041b21459192a0176665ad93324c3774f3028b411eacafd9bfe8",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "276235e7efd773273ffe281cfe5119a9fd361f04ddb1f3ed060d0abb983ff55d",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-illumos.tar.gz": "00ee12a1d47b1d00403e8f2d083a0dbfc8bbbf86ba973b08fbf4c59333f70052",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-illumos.tar.xz": "e11ffdd664228acb94e8e92ae919f7c3bf354083a1ca586be4fa65b7abac17eb",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "d58aedd100cf952c52b8364731b1ecc05567c4d6be4899d36f210ff619b934dd",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "28021e5a4ff36813f76f6aeb063fefaf58310d65993557df2128ff5b9eeb4f75",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "ef5ed09b2bd6b9c1772aeb66444dd821176b4aefb27e657db5bbd24f09d9c104",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "c41edbd8ec4266555b7824594eef470ca6d7695675cf13303dcca6b248d0b692",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "575e5b74248f2503de16294d10e6fec2f6bacac9082ffd73e0395ac2669aefda",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "4b0f56d6a004c6ebdf325ece1d8006795ffb404ea4f1e958a1425ba9edb28b18",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "9e39545494934be7f91675de58907b7b71fe383c535b55799add8c5706371dcb",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "3807db4641082a329edbd08654f40f769e44d139edc99be0b559c8c00c27adbf",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-none.tar.gz": "4eeddd2654e6a84ef5ad5a6f90d88dab043ca087f884e640c945a4565c6b20e2",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-none.tar.xz": "656e1ff5941fe4699ac16d6c1cdd715fca3a7980b4159644b856af08d8b47918",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-redox.tar.gz": "0e0d5de37c86d6a0684b627f16dd6adebbd2ab4776f4a3fb6a386b3ebe9cdbb2",
-    "dist/2022-08-09/rust-std-beta-x86_64-unknown-redox.tar.xz": "dc79147efac5730201980035d1ae377cda5a18bb446647e1bc8375c5d645b1c9",
-    "dist/2022-08-09/rustc-beta-aarch64-apple-darwin.tar.gz": "a3916d7a71d422a0118363228bfcca4a72abd08a6fe6c6d3b4888b87846a1bbf",
-    "dist/2022-08-09/rustc-beta-aarch64-apple-darwin.tar.xz": "f18d8918c9c1ff55cc513fffa309d72b9aeb853f92dfa66e34fb151a2c374269",
-    "dist/2022-08-09/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "ba008d21693e01291e3016773f728c98040903eaa6a71abda23f8043eb9348b6",
-    "dist/2022-08-09/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "1333977a0a147bd5f05eef63ca859b8e78ddc51bed2202616ce5fda5a9203080",
-    "dist/2022-08-09/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "78e40c65e40a287e9ee2d9178f84c8ff7277c2a5beff67555185d79fee1af44b",
-    "dist/2022-08-09/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "ce24270b141952b3fb67c0f43896416dd77be66ed3b311857bff8b07121e1de9",
-    "dist/2022-08-09/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "6557c13f5014acda10349a99e24749224b4f86e55b6499e35f05b5e583a1fed3",
-    "dist/2022-08-09/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "d4b1b814bfa277f895ef4a6c8963ce482965fbdf83ba0661b11db8df39ef301c",
-    "dist/2022-08-09/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "3fd9fdfe30333a0a99cf8e9fe754cb1b8f8734b5d1ab47aaf9490d8eaf3b29b8",
-    "dist/2022-08-09/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "a736efa35fab54ebf36aebf5c7f5b6d4f0ec1f7b0e5b8b3acf2720d97b0c7d93",
-    "dist/2022-08-09/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "5b824f9aa8a77f8a21d8cf68751924739e65d599c0fe561ea9383b8de4132315",
-    "dist/2022-08-09/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "9996ad84db143044b454483cc24c6ad5c333edd7988ab4ef221237d37891e26d",
-    "dist/2022-08-09/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6fcbf77721d4d5c51fe5c580f0ff8ac7347d6c49895da33a3eca19e505cc752d",
-    "dist/2022-08-09/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "3b4e566667ee1b2e9fdb5ac6cde4aa3ddf9c9739e7e64e519f2204db2048bd20",
-    "dist/2022-08-09/rustc-beta-i686-pc-windows-gnu.tar.gz": "cc4f775b79c3ad51bf6ff558267100e05c6fa12ac378d69cc0b0affc37b541a9",
-    "dist/2022-08-09/rustc-beta-i686-pc-windows-gnu.tar.xz": "b646befe7d3ad1b0a30c9eb4e14a6e401f1346e11f88145ee17043de2b6f4df0",
-    "dist/2022-08-09/rustc-beta-i686-pc-windows-msvc.tar.gz": "9b4847beb5faf417bc24b4b963f40c8c8dce55b73658eacb10d2d1c968c676b5",
-    "dist/2022-08-09/rustc-beta-i686-pc-windows-msvc.tar.xz": "6b57826d56686f481d2a20e90994a2af6cb9886c063b1dc08c3bb181ce248a69",
-    "dist/2022-08-09/rustc-beta-i686-unknown-linux-gnu.tar.gz": "ea34b82db9cc6d079a67df542036c83e8661d435d15802976676671cb2b27c24",
-    "dist/2022-08-09/rustc-beta-i686-unknown-linux-gnu.tar.xz": "d679a401e807b12fa8fd3686d3ac09374d3c8d660c6f0a571efc7c9217a05f09",
-    "dist/2022-08-09/rustc-beta-mips-unknown-linux-gnu.tar.gz": "cb3c3638460f3d71c94ca10ab9684ebdbb25f886b8604e62e8412361be56e579",
-    "dist/2022-08-09/rustc-beta-mips-unknown-linux-gnu.tar.xz": "0665c0e3b2ac28648c2a0ac49670181a737ae30fc74add44a2ee612b1d74dd24",
-    "dist/2022-08-09/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "0acc722d22b787adbe16549edbf28debdd4d84633701f8bb7514d5911d6ff124",
-    "dist/2022-08-09/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "441d5ca203afbd5bc4af16431c31d3c76e05edbe45ad37aea4d1f90ca4afecee",
-    "dist/2022-08-09/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "437c52c97b0a8edd1165b957b768e7c9f7c3d79023626fdcb97538899f424592",
-    "dist/2022-08-09/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "9812034d2fe8bb583dfe57a792639a6ac7ab912682ad7383db975efd5f0cd281",
-    "dist/2022-08-09/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "5d39fe2005a50e40505b18210af700ed8fd439d018fe8723c13221c7683defad",
-    "dist/2022-08-09/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "da77cb500618d57682ef4d601e1c8492d9d5412a1833757ffa95d00b0aab790f",
-    "dist/2022-08-09/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "5e4559e41c12f1248cec5f4cb40c196e5d6520bffcc043a40759e7a7668ee0b7",
-    "dist/2022-08-09/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "41c527f4dbf76275f26f7486b48613fba57171b82275ae29ad90bbe684497ce8",
-    "dist/2022-08-09/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "410f2768e5b69f03ebed37923e0c0bb54d4b297bcbef98d82529216a1dfa4c6f",
-    "dist/2022-08-09/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "7f0d0ff4a797120c1a31d33cecd4abd4bd69ec6ff97351291267423f27f7f3f1",
-    "dist/2022-08-09/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "2fa446a7f79d254350b7e9828a36fd415f6931494bdec8bf8f26e0c13636849f",
-    "dist/2022-08-09/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "8572718b7ca5aef0de8227550816dbbd7b41fcc2ab6b0624a50096fa387503ce",
-    "dist/2022-08-09/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "7d82792f2526c6e6522c5255dd350e09f838551f743f760634b875eb22b48b0e",
-    "dist/2022-08-09/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "99f4ff1b50ce3b644b12bc0da84910f376c9187adede0222dc8a1e242e347263",
-    "dist/2022-08-09/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "81f32e172bc635028fe048d2194f1d49c4f31b4daadf8690931cd3a15a9e06d1",
-    "dist/2022-08-09/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "c50258bda8d09646bef493463d66be02d8e7155122e2b7eafe9bc5bd11cbe6b9",
-    "dist/2022-08-09/rustc-beta-x86_64-apple-darwin.tar.gz": "fa2d6a74109c087f13fbbf00171252fcd9079b9978028ee6df4fb2d18c27a39e",
-    "dist/2022-08-09/rustc-beta-x86_64-apple-darwin.tar.xz": "630b218549ee04a8bc5a8a29616d5d8c1d866804cedb2fc3861cc2e354382c5e",
-    "dist/2022-08-09/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "633b22f9c9a93f6cbed7a53fb466ea0bf5895f6fa9c3a22a5883951cedbd606b",
-    "dist/2022-08-09/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "d109d67480ab01ab1e176b5c904df5053fbb54baaf422d4f5019a28dd122e149",
-    "dist/2022-08-09/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "627635dcd8515ed029515e1621b8411e1a3a6ede4058d2cf581c8d669b96dd5f",
-    "dist/2022-08-09/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "6f98febabe7229c566c86728dcf773849c97f29bc0f43ea4f5ffb4e81f163b18",
-    "dist/2022-08-09/rustc-beta-x86_64-unknown-freebsd.tar.gz": "a4b4dcd9dd1128df37d761efaa669ebb35841af0847b5bb5bcf38295ca47db6d",
-    "dist/2022-08-09/rustc-beta-x86_64-unknown-freebsd.tar.xz": "cd28418166eaa754102b469414d0fcfe6785096855e50a2b895c5903e528d8c2",
-    "dist/2022-08-09/rustc-beta-x86_64-unknown-illumos.tar.gz": "168cf42f579132b44ac35a214328f518ab201d6fb9d88d645899fdd88e1d5e34",
-    "dist/2022-08-09/rustc-beta-x86_64-unknown-illumos.tar.xz": "7792763eda89f90a878b09dd99ea9af94d6db0c36bb9570e9b1a05d8dc2f1e47",
-    "dist/2022-08-09/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "ec79355625df63a29487253925f5213442f8606f2fd6fca7a94f8db57220f802",
-    "dist/2022-08-09/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "b7df0b00cfc3bee9a1a906441726ae009aa7dfbfe22e16bc9127ec4df11cd1a7",
-    "dist/2022-08-09/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "372a7c389366e543f3477f2854271c7a74042abf51c37f2d5ce1450f4cd3bfd3",
-    "dist/2022-08-09/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "11243da1c7642ee7ece1b43de1e59b4c45fa8ecf0c9d632d6f1db4772e4479a6",
-    "dist/2022-08-09/rustc-beta-x86_64-unknown-netbsd.tar.gz": "808a451394f4a023ef28420d7dc29e2de92618e5a563055798ec2307e0ca062f",
-    "dist/2022-08-09/rustc-beta-x86_64-unknown-netbsd.tar.xz": "55b447374eb361b2ea1de87080bac3a0cc4fbd233e916e53e5424d6b9ed0dc48",
-    "dist/2022-08-09/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "bbbfd82986d5fafa76f06b87b08cfda800dbc87a1adaed3587f570336a648c3f",
-    "dist/2022-08-09/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "69a99ec973a3603c3d84361d407fbe9c79af0a284a48f5578fb6f46affe751b1",
-    "dist/2022-08-09/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "4a886c744cd6b5f4fe0ec2a3b87730e9a4f7a66c9d4fb0c6411be32014e9e5f0",
-    "dist/2022-08-09/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "095ff2687c8dd48decf47c2b65ce84579bc753de0732877cb092b4ccb9df4f92",
-    "dist/2022-08-09/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "3533a40f72ee318f04448f005e0a811add2e97285e158f63758f76b4424ebe46",
-    "dist/2022-08-09/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "85a4f34d889bf52b65b93066bd1bd6a91092ed49cf6443f476bd60fb36b1cb6d",
-    "dist/2022-08-09/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "11c4bb5a071d555cda8b685e340727eb588f7a830cd4fc22937e44e68b3d7ee4",
-    "dist/2022-08-09/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "b7c9628299f155530d5a2831a4ffe8d398d2cd222952815006eb19d6ff92a846",
-    "dist/2022-08-09/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "04ce1aec5cd9c7ba644954d8ec6ba4c851de1c964b64b0d63965cd2043e7d590",
-    "dist/2022-08-09/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "08635b48b6a7585dbeb7e53f5aac172404e8dfbdf8c165e281064737f073a013",
-    "dist/2022-08-09/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "852ea71bee89cbf9c9fd1d9abb02a88695732d51b106d3de78c36f371663341e",
-    "dist/2022-08-09/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "499ded5cd2689626186c3a51af671991ec67ea0eb16bfa30097a764c6718405a",
-    "dist/2022-08-09/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "eff28bbdd1d3dc44fb4504b24856dc8c550f1311ce56a1614acf2b7409a1c5e2",
-    "dist/2022-08-09/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "b621a87a5257c280b0610fa90abd288264ee01238669d61030ae057e87eb8e47",
-    "dist/2022-08-09/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "9307f1feb9c06f57930cd0009aa7b740f1c9e1515212bd7e2ae81149ea0f571d",
-    "dist/2022-08-09/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "fea653c9e14d305ed217f9c984742c066ea7f7d2fb6d316a13586afc820fca8a",
-    "dist/2022-08-09/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "8e600a6ad04dff36fe9b1846592faa693b1a036f58d136a522d6ca86f9d76be1",
-    "dist/2022-08-09/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "52b45791540bc754a82a7349ca4c5ce194afd28e6c857b61f0ff7e87f10f1253",
-    "dist/2022-08-09/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "964847cfa824c66db554ec20a7e623f4ea50e4cef2439b6813592bcdc31a94ce",
-    "dist/2022-08-09/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "71b89b63be5a44e12d0303e71e3e14b0b770aaac5bcf2879e17526b27e568c6d",
-    "dist/2022-08-09/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "aac0b10cfcb07c64de04fea33d9cf8d691f307e3aefaa9582a8ba3e1fd54aa35",
-    "dist/2022-08-09/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "e3688bc8ef82fff7685cc95fc1ec708a5d76d288cccbd42c37e5c83184f6a52e",
-    "dist/2022-08-09/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "aa89a2dbfe0c6020139d8be52be126a01af9691eaf73fa94c94f9ae75d09d619",
-    "dist/2022-08-09/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "1e7e5f11f829b06f4d8ae5b6d38f13e055ff1fda5b1481e33e40e2a336c7852a",
-    "dist/2022-08-09/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "e43b8009179139c1bd15f3e947a8bc7357e57833959f9fd18fde1d75a742bede",
-    "dist/2022-08-09/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "5bf84aa3ad0badbf0c60d31f686498801d9a23dc0324062128cd7690f9c69234",
-    "dist/2022-08-09/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "b3816072c441ee9e2b8da5cc6a8ed022795b7176d4ac604d97b0d213f89522ac",
-    "dist/2022-08-09/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "d7c6b668f4a2c128ab845e010deb7c9c3e374aaf167244395cdad6c746f73420",
-    "dist/2022-08-09/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "91c36676f8b9093976d7e30ac39f2c477f8442771a3e9c49f41610a0b8688cbe",
-    "dist/2022-08-09/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "86bc5289beee0abf87bfc57a09d6504bfe58675871f4e7559b7f9e1b748e8dc6",
-    "dist/2022-08-09/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "12a1716934b48c2cf716a56c66f95852a70bc74b65c2e44a542b9c2ebf1be5ec",
-    "dist/2022-08-09/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "591ac7d4acd0036d532c91fa3f64a7789881224dd5496b1fe3564c79fd5f0254",
-    "dist/2022-08-09/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "b558c9463e5b8380e133a7a64bc95994d8625fa0097f8b41fb39c93367704698",
-    "dist/2022-08-09/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "d28bbc411779d19279fec251e9378b3923c4b3a8c651d375e139732dd6daaaad",
-    "dist/2022-08-09/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "af9644ab1e369495a4e35fbd111946c679e597c8c1f8342d3a92bad0cad30ffc",
-    "dist/2022-08-09/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "c2acdb98f2c2565cbaf57557cbd99038fb066a09b5602ff3d3bbcb58388b4501",
-    "dist/2022-08-09/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "eddd4a32740ba700c095568bff791e959d6b8ab0a47b5e98a317ea56cc754751",
-    "dist/2022-08-09/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "021bba582076650b577d78fda0b6d9374b17e623d2f3ddb0322f9960874ac269",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "355c877020b386f0297765f8ae1b1e3fa126c9e9b537f8923d275bd31cbdba33",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "809d3314e1b69efb5544fa6daa6719907e09edfd7e0c2cf483ad89a3d508b98d",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "def326ede8106aa440b57698a027fffe024158351879d17f9bba0e58c3788662",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "86684f3c6ba66216c5c9cb203eb9fce96e0239a345df912a2071bc9aa83cc9da",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "2d658db4849089e86af76eb4d7986d605da644af6f6ad43429931f775b5bb094",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "ec14c63680836e5303450d3bfda7b6ca5b163ec01cdaf1e3f2d7b6c584c4c6a1",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "39542f4fd6261b864c59494958071dacd32703fd870286ec5fceaf3664d3e5a4",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "a02061c8bcdd23a8b3f21c4f776e900536fcd44019a495fdec159fd9b4282700",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "15fe16aca96080380c6ebf109522f60134dbaad610d3841e07ac5059ee920edc",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "43d562bce508ccc40afdc3f1ec85b6f0e29b1bad1661a758d07e57cb97d63407",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "80659ef19b274724eb3becb90ca03ea6cb6eb1ff9ff6989073df6e1e52c0d406",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "392e98288ea2ef6602dff922c9bef4fcb17acdcefbb4bca050ede73aeee669e8",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "1eccdcb7cdb96ffb5a5261d4190e4bd1f92e5cf61e92e556ed6baf42e9c316ab",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "9526d26c9fef619cf429437d45c5a79e89a894b22f88635d7995639f1f9696b6",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "486b79d19fff869275f973b274b3cddf02693ba444a79a2e100c6ba79be5d493",
-    "dist/2022-08-09/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "1378376c8b16aa269034cd99b2efb8d8a0fe77e9526338d652b6d6e9aff2ac0c"
+    "dist/2022-08-19/cargo-beta-aarch64-apple-darwin.tar.gz": "79196736248e8e0f76a5d365a45fda39d5bdd815f0f2a8e4341acba31b183a22",
+    "dist/2022-08-19/cargo-beta-aarch64-apple-darwin.tar.xz": "2cad3b28e9ee50c01d031b9c0086f40ccc16845ff2496e91fb1adebc8560b1ec",
+    "dist/2022-08-19/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "c725c27d06a4201df716f50509651cf071708fc0860e2d482a8dcc7dc69011bc",
+    "dist/2022-08-19/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "f5e1c07a8043d5e94c0450e896069262f825fa534c7688465fb0e50424b052ab",
+    "dist/2022-08-19/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "4f07b76c98206ade5b18a89af56004adae0abd51be1c295f6725b6b24bd2dfa1",
+    "dist/2022-08-19/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "9ef70808f78032f2d2f60c529dd43354752df510e7eb9d7db09abc34898a0243",
+    "dist/2022-08-19/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "8c3fa219aad16a2c7a2858844bc3e9b39d2382907b5a145a21d88001d082b510",
+    "dist/2022-08-19/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "60f18159e805894e5504d84999a33396cb27d32d2827ee6b903ed9efab5ae3e7",
+    "dist/2022-08-19/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "66ae9ea36d30e5e027e452b5e4e76e7deaa0d5f7c601b781c02559a99e5a888b",
+    "dist/2022-08-19/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "61c00674f1a33234f0622e7f2b770d641b8202d1e79ce231ad372c0c5e8a0cb2",
+    "dist/2022-08-19/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "298e096659bf1a3903073f3c59bec22f763a2a8f8a9ee91f94589b8e9361bbc1",
+    "dist/2022-08-19/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "dc57c0aea0ae45d781d9a000a36b9df66532b5434024cc6c4d99d8007a0bef8f",
+    "dist/2022-08-19/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "cd21f821f8e6ff9e0b0c3d3e841192fb81a6fecb6ebffd09fa880ac07c9fe677",
+    "dist/2022-08-19/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "8757bc726950c5e8507ad0d9ae518504a9467e8cfabe590b458714be3b6fc1bf",
+    "dist/2022-08-19/cargo-beta-i686-pc-windows-gnu.tar.gz": "4c3c891c19ab8990a892fc98ee5e1546b5a8626ebd769b1b6c26cfcc636f12b4",
+    "dist/2022-08-19/cargo-beta-i686-pc-windows-gnu.tar.xz": "2da6fa16707edccedc3fb37782ae2cbee1330cc89e646a16fbb288c07fe2502d",
+    "dist/2022-08-19/cargo-beta-i686-pc-windows-msvc.tar.gz": "76c4f8be3abfff215a9a565e378fe8e5853b164e2c1ea5f91c4791851457840b",
+    "dist/2022-08-19/cargo-beta-i686-pc-windows-msvc.tar.xz": "8f49f0ca8542ca72bfc05f4928a97ccc9e825a3b7f00dc7fadc58ba184169d07",
+    "dist/2022-08-19/cargo-beta-i686-unknown-linux-gnu.tar.gz": "51b48101522af0cae055e01d025ca657fd7284fb4e3cf81839774fdef97d6c21",
+    "dist/2022-08-19/cargo-beta-i686-unknown-linux-gnu.tar.xz": "63e34d3e51a99eac167f7567002026f63b830defcff364b3029d8819ccd4abb5",
+    "dist/2022-08-19/cargo-beta-mips-unknown-linux-gnu.tar.gz": "2888d73ea48e9ca5ffb6f2db7d1ce665413229d38454e625cad4d4d9e2111feb",
+    "dist/2022-08-19/cargo-beta-mips-unknown-linux-gnu.tar.xz": "cc361abd32f693e2b0d44d718c9d14cf4f4e9333eb965a888013abc1abf2e81d",
+    "dist/2022-08-19/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "7c180166f2ab5c91ed218d2f9fa2ad552e47818a268347bf5be48cad36f14858",
+    "dist/2022-08-19/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "1e5895d5ccd86c5fe13362d8763e9a75ec46909e7c4840dcc84286aa7bf4b367",
+    "dist/2022-08-19/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "6890940f4e02979b6bb8496faf7e71d75c317be563b35c44fdaebdfe11b62cd1",
+    "dist/2022-08-19/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "37bf3bed41ed98d1517d5e925ca22ca39c6d51ab1e65b2e7fd9e8f082364d258",
+    "dist/2022-08-19/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "aaaef89dd7ef0cf07a400cecdd70851be23d066b0522d2e89f94358ea196ebeb",
+    "dist/2022-08-19/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "17c883e6c59a892a4eceee482f27eef60a020f417e06e9c1282992fc085b6106",
+    "dist/2022-08-19/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "722efeb58b8d6802ecc52bfc686b4a1a24fd7b9494e93ed7cb8e4ac974e5c161",
+    "dist/2022-08-19/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "26b3572b77ff7faaf40c06204852683408fda2aa4256167611ac1d0c177789de",
+    "dist/2022-08-19/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "93c504cbade48dc07b4e839d85fa6f477f28ab140c894e8f9acec6477f21e7db",
+    "dist/2022-08-19/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "72354c21c154868a9b1c420047cf2a9eb5aaae20e93dde41f8283ad6e441a744",
+    "dist/2022-08-19/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "ba4c589975b4ca7ae10c98d07c02bae50b7c5d0bcaded77f1ccfefbf555d4116",
+    "dist/2022-08-19/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "fe9e8e7cbb9a1b00871e11b54ae3f64bc35dc4cc80ca49e59b4d8daf5fbdeea4",
+    "dist/2022-08-19/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "287e7a014a6d8e650124c71c87bbd9655785564f4ee1f179a9226ce371e8d78c",
+    "dist/2022-08-19/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "4e35f5a198bbcc06842569e2fda1985e77794425f2e85f1948d7a7664125099b",
+    "dist/2022-08-19/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "05e091a433009843f0dcc295b5b53b46ba2f55a37f7057c777a9cd92c094cba3",
+    "dist/2022-08-19/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "54202c092c265bff6be7f598ce1f6e96a84a5ba4c354d9bbd4986475cf0b809d",
+    "dist/2022-08-19/cargo-beta-x86_64-apple-darwin.tar.gz": "0ae9a6dde1693d33ff774f435bba3e18b67e2d8ce757df5e26ac3b757733cb29",
+    "dist/2022-08-19/cargo-beta-x86_64-apple-darwin.tar.xz": "d67c4c748443be773016d27a74e859428b404a7fb06e651b1fdbc205ea08c03b",
+    "dist/2022-08-19/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "fd617b76eb4d9d951ca9757a31fe92c8cfeb76b093e09262728c7737aa9d2970",
+    "dist/2022-08-19/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "14f263241b90e91fc40a75361e4b8de23165cf8b7c973bc7016a9bf337381ec0",
+    "dist/2022-08-19/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "c5440958cc976526109ef17b4883e27394d6ce087d90653956371837de5a7f8f",
+    "dist/2022-08-19/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "8e3c28a0e593651b530bed0fb5216ca8f04ebc54e98b8cb83cfae3ea13c1c8a1",
+    "dist/2022-08-19/cargo-beta-x86_64-unknown-freebsd.tar.gz": "c80991b59c39129fce5f775c5f1b530592d04060bfee7f7a7a443da698efc50f",
+    "dist/2022-08-19/cargo-beta-x86_64-unknown-freebsd.tar.xz": "81fe7a26762f503c04000f954986c25be1acbaa6687389b70a48e4230901fdfe",
+    "dist/2022-08-19/cargo-beta-x86_64-unknown-illumos.tar.gz": "8b08d6c4c41c3ab05ea3310d44943a3453254c96df92b5f25cc888c4fb7d31fe",
+    "dist/2022-08-19/cargo-beta-x86_64-unknown-illumos.tar.xz": "eb4705ba79bc9b7d2a3969748d966c7faf305ab196bd002856fe5a0499c11989",
+    "dist/2022-08-19/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "b0f14a0bfa064b4511dc34a71039af3c69b006b51906f9087bc7929014b9db76",
+    "dist/2022-08-19/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "3d8cdbc3679550a374e29b4a363b30048e2d65d3d4b9c9dbaeb0a907606afee3",
+    "dist/2022-08-19/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "2f564886b29fece08e8ccf4fdaf6035b5819d03fc963ce46cd6225a79e2d4da0",
+    "dist/2022-08-19/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "78f7ed8eb7e8d147113472f6402688e0127a41a1a26679c19c9e558bf39e8df7",
+    "dist/2022-08-19/cargo-beta-x86_64-unknown-netbsd.tar.gz": "3edff35d00c5af406b72db5e2ee33340c05d24a4bdf4658f172b7d74994825ff",
+    "dist/2022-08-19/cargo-beta-x86_64-unknown-netbsd.tar.xz": "96b290796ea1781fb5a69838f969591b70e5e193efeab85f4e7c45dfb2c698f2",
+    "dist/2022-08-19/rust-std-beta-aarch64-apple-darwin.tar.gz": "c7b09f59bdd2cf91a9aaf771257a474655ed5905f5455f9a3b47bb832d1f124c",
+    "dist/2022-08-19/rust-std-beta-aarch64-apple-darwin.tar.xz": "b82c8c4a454f59218b22eb04a346b78215c10269c001e28395080abefaa9e6f4",
+    "dist/2022-08-19/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "cbccc251b16f41383845d5d1d6196f33d2769df7455f308c096e0af46b43d14c",
+    "dist/2022-08-19/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "99be53158e3ee2b467d75d26d461e7aa4330301c6dba74c048331b16e09188c5",
+    "dist/2022-08-19/rust-std-beta-aarch64-apple-ios.tar.gz": "bf94ccc4bc6a4c171cd60d7a62c34d32e09b242a7029b69feef6159cf4c22fee",
+    "dist/2022-08-19/rust-std-beta-aarch64-apple-ios.tar.xz": "6a9a910573ea80de9618c7bf46e21e93341db652e4d82bee06e73544b92805f4",
+    "dist/2022-08-19/rust-std-beta-aarch64-fuchsia.tar.gz": "27693e376c29e561844e43ef21d006942e44263076ab4144643827b671ea3339",
+    "dist/2022-08-19/rust-std-beta-aarch64-fuchsia.tar.xz": "81d00752188815a7747f89ba76610d91d276459543e6c4362f1f86ecacc28f2d",
+    "dist/2022-08-19/rust-std-beta-aarch64-linux-android.tar.gz": "6f076bd4565d9af83003e1165e24fb912eca0adaf40a40f1d87956ff8dff535a",
+    "dist/2022-08-19/rust-std-beta-aarch64-linux-android.tar.xz": "a0f528910137d9b7e0e6dd371dad181f7d48d270e8ae289d8b7996440bef101b",
+    "dist/2022-08-19/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "6ac6afb78d0c3e55cffc6cc52bba51259fe83aac35075cebdb6940ad3d147b60",
+    "dist/2022-08-19/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "f1043c1fa0d0d75f8001d854967f2ec8be6def5845662505048742e6472ebb87",
+    "dist/2022-08-19/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "d3390a8cb0617551cdce7bb9348fc39a304c877bf5c5ce02ec9cdf636a69571d",
+    "dist/2022-08-19/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "81da17399275e43ec9b15983faa9828df2a8dbc72ea15d16671d0c31d4d0795c",
+    "dist/2022-08-19/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "3deca6def0ebb3476898e1ee7368592a034867d73948e51f24ad92445c6275b6",
+    "dist/2022-08-19/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "23bc4165841199f110293a627735624a2a37bc6d92019e9cb1533e006933f9d5",
+    "dist/2022-08-19/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "3360ea38f8d8bc84f2419b4ca90bfca7a9709a6fbec2ba209fe335090a534c0e",
+    "dist/2022-08-19/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "ce7643548eb6f797b7823795e27b748aaa09cd02baffaeee44bdc3c00ed796e3",
+    "dist/2022-08-19/rust-std-beta-aarch64-unknown-none.tar.gz": "5f6cd59b283ac76709e7c76c89f352e92b6818b1606b585332f36ba3c4b6a87b",
+    "dist/2022-08-19/rust-std-beta-aarch64-unknown-none.tar.xz": "60d00cacbd24576b0b247f2b12d6a63e9451912d874385b50165a312da080762",
+    "dist/2022-08-19/rust-std-beta-arm-linux-androideabi.tar.gz": "15494aade74e5e29bb0d881d243da37d3b929bd98baab7c6b0345e0a6a0ed803",
+    "dist/2022-08-19/rust-std-beta-arm-linux-androideabi.tar.xz": "d62cdfc5d0a41749ea90d6cabaa77f4f45630061a04dd3be9611cd5f0ea868d5",
+    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "40e532cd37262e7280a7c0bdd54808815adba533a911bd46a1d9b76d0446b958",
+    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "bb08d0ca767f257fb13f6a946e7c725dc877055f94d324128eab521d43cc552b",
+    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "2f22a08cee234574c48e5022e0c5b1641c2ad01fad69537b03eb9f247e7877dd",
+    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "8cb10237d87a4fcf2100b5aec0623ab04c2f1d976a0f30a1a89357cb41ce6d4e",
+    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "811c691d678f08627758bba341e3ac06a2d465da78d819c49de494e0602073e6",
+    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "50063b02901983e3ce37e98e57e664521cb5c99ab9a1015bb949a53dfda9b49c",
+    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "2ca7a740767463e432b22b846f81ab9983751279b65b4488d07202b77e378afc",
+    "dist/2022-08-19/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "8b56365bd261fb6a4c2984b51dce14d8e2c996667ba4af866153042855043916",
+    "dist/2022-08-19/rust-std-beta-armebv7r-none-eabi.tar.gz": "83ece7e0db0e1ddd44b104d52def00ce06fea37dd8c90b1c0a840d0561a76d54",
+    "dist/2022-08-19/rust-std-beta-armebv7r-none-eabi.tar.xz": "e3a343fa5f35372ace7f23e6775c8c01b9803fca9e1b686d3db695c2f754db5b",
+    "dist/2022-08-19/rust-std-beta-armebv7r-none-eabihf.tar.gz": "874dec1039af060488f34be26ba54615a12ee4cb64f3a871932936e4e736fd76",
+    "dist/2022-08-19/rust-std-beta-armebv7r-none-eabihf.tar.xz": "cdc6b9a375a40847ee4938f3609f8c49f3368394b46fa9dccf1b5b16468852f7",
+    "dist/2022-08-19/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "28e72dd4c24716224b663d341d6f784f2b0deebbf52721709fb396240e327854",
+    "dist/2022-08-19/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "5c8cf5b47b567b8bc41c3ce831f34d076396179d050bf982e1949bef74a2b2fb",
+    "dist/2022-08-19/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "dcfd76d646b17521f5a7daf94a0617a731d914612368ff112345a03a2a5b5939",
+    "dist/2022-08-19/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "7d43dfef571dc4c2e883bdf92e05dd3465b9233c30f34bf282b57826339e9e96",
+    "dist/2022-08-19/rust-std-beta-armv7-linux-androideabi.tar.gz": "4bb1f0110629b7af1fbe09a6eb8387de9aa800a95053ef7177bba30a2d1b430c",
+    "dist/2022-08-19/rust-std-beta-armv7-linux-androideabi.tar.xz": "55f97c5a16e8d65dcfa13adf989039ffcafc5a4a09aec92083d00d7e2786def9",
+    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "e7fb4da36908d6cc0c13a93ec3f4b01ea1b2c515213005479da45712614c0a69",
+    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "c727568116de82658335c3be93d51a7e2850cc2824b9818a166594649dd5b3ce",
+    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "1a186dab35dba7fcf4982e717a1ac6d1d846b87e50e6815ac0f9b2c40e44f4d2",
+    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "7f5d3c66c57ba75d3c91328f3ceccddeeebdc08f015e762e26af770a968ab14d",
+    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "c0108882d6f80cb82a9fa016adfdca2478b4966c72c6d6d240c94c56fa668166",
+    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "4f30e1114c7c4ca187f9a2e4b2ffdd4fa66cd2346534c80ff5a7278a846f2c8c",
+    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "a69c55803776f8ccfc1685181209463ebbbd82252ba2cd47387d6ce8f8f09afb",
+    "dist/2022-08-19/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "c12d6e9f9cec1aee0dcad3ac95a33dea0522a0e00c88e1d1e5ea4a0d98119128",
+    "dist/2022-08-19/rust-std-beta-armv7a-none-eabi.tar.gz": "91cb7d15d30bea14c3f7b9ad19ccc3cf58b69abf8ff7ec2ebaf1ed60cab4940d",
+    "dist/2022-08-19/rust-std-beta-armv7a-none-eabi.tar.xz": "887aad7c712055aca460a840bb1f5b69caf4fe11a458032df73038af94285abe",
+    "dist/2022-08-19/rust-std-beta-armv7r-none-eabi.tar.gz": "54a4f38e30039211e0199bc25733572d24dd5ad9eb6fec524146c1dc08b745d4",
+    "dist/2022-08-19/rust-std-beta-armv7r-none-eabi.tar.xz": "0b6b366e0380df3513f36eac4341d5562520eff0fc995280179c6424fcc4f5db",
+    "dist/2022-08-19/rust-std-beta-armv7r-none-eabihf.tar.gz": "76f33e20c3800f2a7cc53db4552a44b5269aa8678c7f3de970071ed0f3c66dfe",
+    "dist/2022-08-19/rust-std-beta-armv7r-none-eabihf.tar.xz": "e71d8e8a2144cd4ca220cb25218aaeca7d0ba776ef10d2adebd8745bc1fdf988",
+    "dist/2022-08-19/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "50ba543bcfe3d1ca5d5606e7ea656968f70930ce074fb0110e65658e9cab9810",
+    "dist/2022-08-19/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "b2498657da8c27464213afbbad1ff95db637236a9e0f88d2c9bf0c6940a0c583",
+    "dist/2022-08-19/rust-std-beta-i586-pc-windows-msvc.tar.gz": "8275136f11ddad506a9569d3e6d1ad4b48688a1e7e498e22566ff3453675ff4b",
+    "dist/2022-08-19/rust-std-beta-i586-pc-windows-msvc.tar.xz": "8c5fae3775152a3dd3d1bc47e1ab1861efa60b51f8087fb2a63da0eb45185a79",
+    "dist/2022-08-19/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "628a29ee30489dc9bb6877a2aaccb4f5de05a5a58ef154be875643ce393776d4",
+    "dist/2022-08-19/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "ff4f7ade08cb2337d20fbaa8a6e74f662b805cb2bf142a584e10b4aae66139a9",
+    "dist/2022-08-19/rust-std-beta-i586-unknown-linux-musl.tar.gz": "3f7859c372943096d3f6a258561584cee28adb9cfeff5b98036dd7cab74dab7d",
+    "dist/2022-08-19/rust-std-beta-i586-unknown-linux-musl.tar.xz": "40323fdb61ae453d42525ea13c41b5dedd322d859f9993315a798a87634ee386",
+    "dist/2022-08-19/rust-std-beta-i686-linux-android.tar.gz": "b103802c800524bc1dc6f3d996ad47d2c03fe03b236588f8a9de3fc763ba2eff",
+    "dist/2022-08-19/rust-std-beta-i686-linux-android.tar.xz": "ecb631362408d708e63093a0bec0b735b1cdc6bb7c0509ab5852e572f796812e",
+    "dist/2022-08-19/rust-std-beta-i686-pc-windows-gnu.tar.gz": "3b7af769cb25b75fc5a657e4f3dd489e6745df2d383c5e78cc033fb46345d72e",
+    "dist/2022-08-19/rust-std-beta-i686-pc-windows-gnu.tar.xz": "f1a65b9607cd153e421f27891b5ebcdc1e4a1571613ecead7402d8794eff3330",
+    "dist/2022-08-19/rust-std-beta-i686-pc-windows-msvc.tar.gz": "e5214f670f981c7b95e690c8487323dc2a564d34f5ad4f589d2862ee11225b83",
+    "dist/2022-08-19/rust-std-beta-i686-pc-windows-msvc.tar.xz": "efe17356f42fa47949151ebfdb75ee10d14cc5a279eb4361c79f36c5c322d9cb",
+    "dist/2022-08-19/rust-std-beta-i686-unknown-freebsd.tar.gz": "35a3dcfd6df77ac71cd01bec57814d9153d1358409cab11e206b98e86e14c701",
+    "dist/2022-08-19/rust-std-beta-i686-unknown-freebsd.tar.xz": "4dbeea93b2aa61076de0c84c2d5833474eec7adb66a96e90372b074e6c7790c7",
+    "dist/2022-08-19/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "e07c47100a8719e54176bb2465ae62d1156a4264695739039b901c6ad16e5bd9",
+    "dist/2022-08-19/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "2dab5f2fbc8c5900b0b4f35ffde00d0e6777c823b67a4632fddd19a3c3b5e20f",
+    "dist/2022-08-19/rust-std-beta-i686-unknown-linux-musl.tar.gz": "8b8131f8644c4cbf13003266dcfd5ff82f7b72aa8fdd14a27ff8281821ea6a5f",
+    "dist/2022-08-19/rust-std-beta-i686-unknown-linux-musl.tar.xz": "b47f1cd70533ab2a59a8ee8c218e7d94406a552df5d23061f9cea714301d973b",
+    "dist/2022-08-19/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "415d22301e698a355fbc1a32181b02a72b7ff36fe1779460d6f380fde1608500",
+    "dist/2022-08-19/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "2f3524f5908f0570b843304dc11eb8d1f7285eab7cda18581043321f65e2a1dd",
+    "dist/2022-08-19/rust-std-beta-mips-unknown-linux-musl.tar.gz": "6f25a53edc32d423752557cb65daf64f9e3a622ba5a6fdf3f07f95024b2348b6",
+    "dist/2022-08-19/rust-std-beta-mips-unknown-linux-musl.tar.xz": "a6223971aa5679e3db6df2afbdd31db05b58563347d01ae8682f37236ef2c402",
+    "dist/2022-08-19/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "756c7cd706d57fb766c0e255c9a10146f4d8c2bef0118196706f268a5b1ac65e",
+    "dist/2022-08-19/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "b54706a7faa146e4144e7c66d0f19289bebb155bc0adfaba3c4356866514e830",
+    "dist/2022-08-19/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "23fc1e3e7fd1b0f1ad210273090494246e45cf43d4c30076afd28925575a9447",
+    "dist/2022-08-19/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "ada4af591dbac60a137d00c4030e240eca53874604b2a306db1fe8af10bf0332",
+    "dist/2022-08-19/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "b9180c5bf936713c89f6f0f5f6a637810f72194a7742fdcbbf8fe6e4a6bfd358",
+    "dist/2022-08-19/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1c2940139107d3aa8f6616e90f68fa42e62fd965f9e22cc264655ad5935971b6",
+    "dist/2022-08-19/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "3dee776bf2aa9bdaaa38235d88a1ca98f0418adc10ceb3d0e3d8999339925bb2",
+    "dist/2022-08-19/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "85f16418e4edc3b2d087104c51e4de61d7d9cf5631ee48065eaef9d796f662f7",
+    "dist/2022-08-19/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "ba374a6acaa1eee5beb9c234d2aa6e46b8b1fc7be65e0ffe8d55d9ff85cc4ff1",
+    "dist/2022-08-19/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "70621189ef43a8034d9f96765e35c43b17b16e077f143d3994e5e6cfc089e14e",
+    "dist/2022-08-19/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "143ab6fc7b3e57d551ada1d8335fdd77c4577d303d37663c4e7ce4b24557a752",
+    "dist/2022-08-19/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "a81db30558c46f43ef4c8cbf3480407af54bb6ad1813f0e912bab6ab0baef8b6",
+    "dist/2022-08-19/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "7def94fc92ad2ac6921d90efc821f37aa69bf59b6b6c8cddf958a7bc6e90ab51",
+    "dist/2022-08-19/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "c39b30a1dbb8c6a828b860f4b0685a3c0498a65dfde880df21e505c7b4ab545d",
+    "dist/2022-08-19/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "184441ee82c9578b62f905e0e1fae2e27d63cc0729ddc4a58797905341a18c30",
+    "dist/2022-08-19/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "b7677f219cb8158ce4a9dc64dafffb63f5bda0752d14390ba52c609bac629fd7",
+    "dist/2022-08-19/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "e295a74c453bf003d02d0aab07aa4b8c609878975cea9795ef467150b01f3b62",
+    "dist/2022-08-19/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "5c45723e1047a502718365252f66aa376e1ba7702fbf1453dee3a288367b3208",
+    "dist/2022-08-19/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "c348be9b8846b158b21cd73542dcfb891401421ad5fd4e0a8eacdb49e56cdb4c",
+    "dist/2022-08-19/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "f6036cb2c1fdb232016eb99f908a198c06bae44ac4d6d7536d3ebf42ba0b6db3",
+    "dist/2022-08-19/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "766ebdbc735cca0906a23683c5da5ada8a6e455dc12e49c7b34f71e66922f60a",
+    "dist/2022-08-19/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "83dc6727a20ac37273ad8b3ce043f005d5f2be7dab1d5d0c9658fe5897ee9ce2",
+    "dist/2022-08-19/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "5f059405fde4d25ff250c7219a5b7d8c009a69672f4255867d23ebd50539515e",
+    "dist/2022-08-19/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "2aad029aa8eaed74e95ac82d471bc750955323b2ef12066b5257e9779cdb9f79",
+    "dist/2022-08-19/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "734e92db50a3793eefba0378dfe2daceb37b6c06f5a6ed1692b83553406060ef",
+    "dist/2022-08-19/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "f2278a4aa83e2cba6ccf32744c3ae8b55fd44f77bdc31f08bff36105b945d2b8",
+    "dist/2022-08-19/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "4ce4d1659cd7ae70705c8f4808226814df18bfdedc079c44484fe1ce0dc06f00",
+    "dist/2022-08-19/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "77e5962551433593e6ee3a2b1ab6766706acdb9c364f5adc8c5b99e84338d3a0",
+    "dist/2022-08-19/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "6a85f89c5211fc18f86cdea8874ce4ee4d5cf15299b3884dca207003715bb54d",
+    "dist/2022-08-19/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "cfe8149d98fa1e6d1b406a5f4133ff6bcc9fe3cc5cdb006eebd354537efa55db",
+    "dist/2022-08-19/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "45c5918df046c2ac5fdce3025eba539eac759d09fd1a134d51272647b829b3ba",
+    "dist/2022-08-19/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "42d01adaa0a222270a303c10fe5b44e61817f317494595f09ab3101ab859e764",
+    "dist/2022-08-19/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "09ca832cd73a5f995a76ce9e6c330095417d8802d2b3afdcf3c42f646dc9346b",
+    "dist/2022-08-19/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "293fdda30521323f1cafe3cc0db92d80bca7fb25ec73a2b2e0c2cdcb48cc9564",
+    "dist/2022-08-19/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "f74c4dd7526251aeab43172f5bf043bdd70b8819c899866086a98c45f7895583",
+    "dist/2022-08-19/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "0de08e4670a7b5c3a4efd4b00ab6da6d2b3ceb37664d3adcc1050274b66f6a00",
+    "dist/2022-08-19/rust-std-beta-sparcv9-sun-solaris.tar.gz": "4b88e96c15cbcdc66f200fd216715c73ad26e0cdd5920105a15ba44cc02d9a50",
+    "dist/2022-08-19/rust-std-beta-sparcv9-sun-solaris.tar.xz": "819275f203ecff1bb37628dc0589b28a0667085f3e5115c3fcd26c4536b235aa",
+    "dist/2022-08-19/rust-std-beta-thumbv6m-none-eabi.tar.gz": "579d425d60bcb229cb61291caa8fcc99ea8a759b66c61b4f1c796d207ec08274",
+    "dist/2022-08-19/rust-std-beta-thumbv6m-none-eabi.tar.xz": "d2ebf00fda10f4f2e8476b5bcfce2be358f046f60a413b6e71aef4e76c6b55da",
+    "dist/2022-08-19/rust-std-beta-thumbv7em-none-eabi.tar.gz": "c898ca80eca184ed57125d8b463ca7bc60293bdedb6a3980a2c8da0d222f1869",
+    "dist/2022-08-19/rust-std-beta-thumbv7em-none-eabi.tar.xz": "01a73cb52d6fadb848eb672c567eedac339a6ebd432756c2a9e42c7273c4e9f4",
+    "dist/2022-08-19/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "cdb64f9439964310c7a35edcb36596fb68b5925b7bd2c89a048dbbd5cbbdd434",
+    "dist/2022-08-19/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "3f90031df2e3de1d423c327764cf7c83ff9b422414bceaeb8f4ca7786a17b6cd",
+    "dist/2022-08-19/rust-std-beta-thumbv7m-none-eabi.tar.gz": "626d6e503c6f72766d211faebb88cb8d8bba95775e8536eb181bd76e9a26434a",
+    "dist/2022-08-19/rust-std-beta-thumbv7m-none-eabi.tar.xz": "5bcd4b052b2699798c14bc2b50b40c9e538c24ed00bc7fc1f9c812816f47a965",
+    "dist/2022-08-19/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "90196536e30d2ae5e59ab0bceac283a1934170484c98c4672a86f8a3198307e5",
+    "dist/2022-08-19/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "8dbf82b8f8c9f5b054c5281bcb5429503d7e7f916aec7fbdd4e1422db6ccbee1",
+    "dist/2022-08-19/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "45010646984aa7d942288d74e60052a4da6a57312e56ec812ba34ee66ee32709",
+    "dist/2022-08-19/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "c2ced97a849a6600163ef798adcb8aa9f9b0800bc8554c02b635ce0c26b9dc16",
+    "dist/2022-08-19/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "3d4f2fc427971a1bfb7de12c876a03e553e8741887568fa8895996da84d96fd3",
+    "dist/2022-08-19/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "2f81f4c2168dae4a76f2705b88eead61dcdf805d6f3796c9f8fb4a0f8ace21c3",
+    "dist/2022-08-19/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "f045bb0963aeb3e4d4b08da616c4ef298f1916d7491ee624f334c21427e26e9e",
+    "dist/2022-08-19/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "b963e0af4532cba9611c9cfa62d816c45b9cac75e3d390772dcee1bbc0111408",
+    "dist/2022-08-19/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "133a35f0ff672356dab8413aa7958fe70e1987eb95c7adfd2362e1f77fa1a17f",
+    "dist/2022-08-19/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "70ef699fe52f695bedce35910eb85527d492c8f663ce926e111522d3c70c62d2",
+    "dist/2022-08-19/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "386900d6fe52f807c20aa607cc76864406e096bc6282185bce4e1fe6c2e95350",
+    "dist/2022-08-19/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "7c40bb5d55bd01c865de037695ed088671318b2a1a5d7c1aeeb9fccdfce666bd",
+    "dist/2022-08-19/rust-std-beta-wasm32-unknown-unknown.tar.gz": "41a606a2e9148e288baa8548312c993bd82f8b288d558472ba6cc84938a2f61a",
+    "dist/2022-08-19/rust-std-beta-wasm32-unknown-unknown.tar.xz": "bceb44ce91d28547ac123d17f10788268c27c9af8c8da463260dd7c574a30de7",
+    "dist/2022-08-19/rust-std-beta-wasm32-wasi.tar.gz": "1bd60b74b2e1555c669e273687b84db1da3818ef6c9b0dbe8168852c3e8810db",
+    "dist/2022-08-19/rust-std-beta-wasm32-wasi.tar.xz": "d98e83775d0340d27f2deb0cb17a05250bca53f00c2c1039ae34f412dc1249c7",
+    "dist/2022-08-19/rust-std-beta-x86_64-apple-darwin.tar.gz": "476760a9a396adbcf5312afc135f2eeb97c04da8654188726a63734ad8f88725",
+    "dist/2022-08-19/rust-std-beta-x86_64-apple-darwin.tar.xz": "caccc07d4fff2d394f5aefbea589ade137a3154eba0a2562f7a1a036928fc8c4",
+    "dist/2022-08-19/rust-std-beta-x86_64-apple-ios.tar.gz": "3fb5384aa267a2f4495483cf2857f7b33f7d1df0409539bc0735f78f5e8fa1a4",
+    "dist/2022-08-19/rust-std-beta-x86_64-apple-ios.tar.xz": "e2383658b0dfc4bbdcea69eb42a9c75686d578c0f15adce039f46aa0f25297f4",
+    "dist/2022-08-19/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "6cc9433de637d2156ede6bd9620ab7a6895894d8ec848563620df131e30e79c5",
+    "dist/2022-08-19/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "408d1d1ceccc78df145f804bdd848d4b595274ff2e5a32c76e979134aadba2f8",
+    "dist/2022-08-19/rust-std-beta-x86_64-fuchsia.tar.gz": "6ee5d79ba87acfa1f2093c1e9cfa26eb2851db48bec86d4f25654c40f9980900",
+    "dist/2022-08-19/rust-std-beta-x86_64-fuchsia.tar.xz": "eb3e2e365edc084594666862345d903165630034e4c6fe97e206be68920d1657",
+    "dist/2022-08-19/rust-std-beta-x86_64-linux-android.tar.gz": "1713831fd1675c317d7d6059a27181591b51d094b6c39978e1d52cc92fff4ba9",
+    "dist/2022-08-19/rust-std-beta-x86_64-linux-android.tar.xz": "864c4f5edf3602ae629fe77f6d08d8ed49d354ce88bc5ea034858b77aebb2c1d",
+    "dist/2022-08-19/rust-std-beta-x86_64-pc-solaris.tar.gz": "683bc54f134507fef80665397c3e2aff1b854d08cc8130b8cef2aa6e5b573561",
+    "dist/2022-08-19/rust-std-beta-x86_64-pc-solaris.tar.xz": "86f037d022446e277dc92c007ed531da9e0ec5013b7c757f0810f1abaa7376be",
+    "dist/2022-08-19/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "312db623e7d4711eb965d4826c19986019194fdd8528086aed6a08d3f6457b5c",
+    "dist/2022-08-19/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "1581eaf570f86f49189b4f8f51cf84e535a2bc3cb41fbd8043719d0dcf5185eb",
+    "dist/2022-08-19/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "0cd8dc6a60623bc64410cac94e89abbddcc7b3cba1b89f8fb2fa56ccea4493c1",
+    "dist/2022-08-19/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "1831ca7a6ed59064a201cae8f2fe919e74c05e825ff67c671d57393506e95edc",
+    "dist/2022-08-19/rust-std-beta-x86_64-sun-solaris.tar.gz": "9845a9ac85f716ab46d186696fc44993e701de7d89c2c5aad188d7b0fe1761a1",
+    "dist/2022-08-19/rust-std-beta-x86_64-sun-solaris.tar.xz": "16fa497ccd7fd94a6f7ab03ba975d00c63b60f1786fe2da1a7eedca3da62642c",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "3c3e24897193e3feb947a387d09059d2ee495b642dd5a160cfd1ae61eb1ae155",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "2ffd051693a8e831ede8e93285da11b0fef127473d95fcdcc40b4e6ef811ae5b",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-illumos.tar.gz": "4d32d311dc0c3350c329d2aff147529db13e537f8405ae0bf317b8a85e9242a4",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-illumos.tar.xz": "fb9d10ef315f2555a0374903d66695078d5f483167c4df2c680d48af4312d109",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "67fa67de6bb7d34ca870a52346dc410084702705b1f9f9adf92d9b71afe11d1b",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "b8df9d518bf30a87633745430f41172d10fd833ee94d6331a73de3649866b62d",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "42f03a9aeff106f40f3d2ada7a02b1e91135adfc98be1acda0f9ebd63b388097",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "da4f0915a71736b3d3c2479440f8a9728250eb50234b39aedbc17d9d1b390651",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "06d00f30c2332d68a924b50e42e813f2f8479d568b74c5edf51b7fbdf57b66d5",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "1e3b5a879ddd2e4fdc31c3853783cbe8a5a4183250b909198553a4d95f1a7cd5",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "cc4e9cb8e856ee173eb028746487604f0436347223f163294aa1ad34c0d740a3",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "02a2ef7754af534e1fe6be3a04ef4446dc6abb6e6c57326ca460a5ba6c96f9d2",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-none.tar.gz": "62d55c2a36afbf210d0b9947ef2f05104e7da71bb7958509119b0336874f0f92",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-none.tar.xz": "86270ba78b8d74d0f3ac6c2f9a38906d25ec888a8ab604b0c593e99ba5128eed",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-redox.tar.gz": "194a933992ab2596af7966e1b10900b1a4627bfef99b0ff1fc87bdf0a4e2ca17",
+    "dist/2022-08-19/rust-std-beta-x86_64-unknown-redox.tar.xz": "1a2137c628946d1cb1a84e24abe3a44758425a7470ed4a48555f9c6dca8e7013",
+    "dist/2022-08-19/rustc-beta-aarch64-apple-darwin.tar.gz": "b4a4752c96d439c2977a148a40b63864041f903e5733419faacd96c5839bc8e5",
+    "dist/2022-08-19/rustc-beta-aarch64-apple-darwin.tar.xz": "f3f83489cd6890aed11a75f4b60d3edf2b32dfac023c93faa8cf1604a9e8fad3",
+    "dist/2022-08-19/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "5d012c23083429116ffb171923343169380559f3ee90fbaee0989f77da878487",
+    "dist/2022-08-19/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "15f3534ff3b881709eebaf55e55359d700686429bf55eb4b1c7292ad1a13ff54",
+    "dist/2022-08-19/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "d3aa46b9f2f052b080222a13e598ffa96227ec271c9db2efd2ddbeb0b1fef2ed",
+    "dist/2022-08-19/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "932d89e503d2b4fad90241c014c4b4f892ab8054d9555590819422abb51a999e",
+    "dist/2022-08-19/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "5c006e8324bc8a5b9039da7b61d1147575d0383a18deca3b75d01ebe684c7850",
+    "dist/2022-08-19/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "0d03091ccefff702877e2c38d131932125f0b2d25c8a94e260601c277a3e494f",
+    "dist/2022-08-19/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "373650c44db5568d8d2889b6002d3b5948acd0079773f257d9dc0e380de8c026",
+    "dist/2022-08-19/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "0cbd356980688e816baf4c88b7c8963e4c4b009cdf3e9bac057a3fedccf0c552",
+    "dist/2022-08-19/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "de83386be1885fad366b0b3379f41a8c9e30ca6cfcc5752a0bd917ec635954ba",
+    "dist/2022-08-19/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "a605234a11f44a65b80554bbfd10b6fe83c20a2a62102aaa46f0febc5ad846b9",
+    "dist/2022-08-19/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "22c323b69a4786bee149402c7c64d85795540e2143e0da1e48739b2dbb1a869a",
+    "dist/2022-08-19/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "f9daad394d53aa405f783d9013916610b014d930a355fdb88757b47469619cf3",
+    "dist/2022-08-19/rustc-beta-i686-pc-windows-gnu.tar.gz": "275d21aafcc272b18bdefdd6adf28116a493beb053eb214b6ab842ccd31e9cbb",
+    "dist/2022-08-19/rustc-beta-i686-pc-windows-gnu.tar.xz": "5a032ea14e3845de2f39305a4fb5b9a4415939f6bd0ff79a0e527c4ebd9af669",
+    "dist/2022-08-19/rustc-beta-i686-pc-windows-msvc.tar.gz": "d892ad811e831b6f1cedf8d352dc71f9f86a26089fe4fce4d22b4f77482094eb",
+    "dist/2022-08-19/rustc-beta-i686-pc-windows-msvc.tar.xz": "ca16e42ea493c869b53031ea80b52c66c5771fc25531fb13529931d0740ec92a",
+    "dist/2022-08-19/rustc-beta-i686-unknown-linux-gnu.tar.gz": "d3aa43cb3bef265d6d2fdb17c6962e906ff021c4ca0d638eba6a98f09324d942",
+    "dist/2022-08-19/rustc-beta-i686-unknown-linux-gnu.tar.xz": "9dbd9e4a20535c8e19d9cee1218f2b3e0d3289d118b840b27e12aab3e48c80d8",
+    "dist/2022-08-19/rustc-beta-mips-unknown-linux-gnu.tar.gz": "5c17afb542d3661dc31cd3d334de66706de956f45959404494f90cf73e6f6d21",
+    "dist/2022-08-19/rustc-beta-mips-unknown-linux-gnu.tar.xz": "68fc729c47c290c09a14fe450ab0b82eba568a4e687554e0f87d095fe64d056f",
+    "dist/2022-08-19/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "64e77868b050b0d237eae46f33a723daa2cac8c8736e3787664315e13d879629",
+    "dist/2022-08-19/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "c3c339f17752f334dacf18c75837578d8bcd1020a59a8a21ad0b3cca0e58e49b",
+    "dist/2022-08-19/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "45e586abdfb8a46f126b2327e64e115f8acfa861d183a276ef3688c148e99d46",
+    "dist/2022-08-19/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "7be6e24c013bc03ae28d494d78e767488c38f7487557d5debd5a42eceaa49e34",
+    "dist/2022-08-19/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "a3af91bc8d8179bd06d51615ee2ccbda0c838f99c2b30fb91c52c76304ce46e0",
+    "dist/2022-08-19/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "948b7598e5c7648b02c39757e50ad9550f78fda4943b578b4d19831c2496e86c",
+    "dist/2022-08-19/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "1f01de1fb0274b98424867fba7eef93e00485624a5fb6e21657d6591607d9f50",
+    "dist/2022-08-19/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "879bf1abc548a1dee7fc6c26c0b0881fab064be58a1540b67730b8d3643f8ddd",
+    "dist/2022-08-19/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "3303c7dcbdd1a38a8e32e4b96071be4afd191bb6403d6fbf17fbc65087b1f15b",
+    "dist/2022-08-19/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "cf8693715e3d58e016c2dbe0bf77a3933765ea5fe0a65091cc427b694a490d60",
+    "dist/2022-08-19/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "4ad0221a3df7e223d3bdf271f28f0a694aef8184cd377cae530fbca5c12d82d6",
+    "dist/2022-08-19/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "ad1390820e4fcc426a27d18f97fc8f952c9e949327d8d6b60e6853e4dc9e2c04",
+    "dist/2022-08-19/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "c9232ad8c52060c40ef35eae32e79585d550e2abc011d2b6562edb1b02244966",
+    "dist/2022-08-19/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "3e937985bbf7ef5af05e96e82114fec6ee17bc04f784c3e7472224dae1ebb148",
+    "dist/2022-08-19/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "f4dfa226259ce0d9f8fb9295f82a18a130470f11479811717ddb0f5064a9eb81",
+    "dist/2022-08-19/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "919dd5fbfc80c77f270e1eefee8dbe1c76ed7cc94cc11dff34f54ee05fd415de",
+    "dist/2022-08-19/rustc-beta-x86_64-apple-darwin.tar.gz": "482c51eef00cc238872b5002f12c351259a666e8b1380b08f5536fb87b046f4a",
+    "dist/2022-08-19/rustc-beta-x86_64-apple-darwin.tar.xz": "3b78a63fb9d27e7960ea35d8bef3734789bd48d80ed1605ddb9f547859977260",
+    "dist/2022-08-19/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "4c7ec47ced7a7cbd9e6b038ac0f57d0e705801f42375011eac42a708808d75c5",
+    "dist/2022-08-19/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "6935fbe4de2b5712fe15c865ef2eb4c41959267b03afe4f276f8fcc6eee992bd",
+    "dist/2022-08-19/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "30b78a0ac0852bbb3aecea5d4f61f4e1737b5d4910e07a59c64e7cdfeb3da215",
+    "dist/2022-08-19/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "73d15af622a7accb4a04bd596acc95cd0856545fe6a386df18905cd221107fee",
+    "dist/2022-08-19/rustc-beta-x86_64-unknown-freebsd.tar.gz": "dc00c8c6f6121ac1ba112120b82215ce811a4c518025cdc4d1202c53db88f65e",
+    "dist/2022-08-19/rustc-beta-x86_64-unknown-freebsd.tar.xz": "e827aa07bff90fb978b1055826d9e672e1e40056caab3d8a182afa3c371f0f4f",
+    "dist/2022-08-19/rustc-beta-x86_64-unknown-illumos.tar.gz": "05f6a99d63847d910e05a93d78944014c775c5b6e8b8bd742f2c74c39f7cd883",
+    "dist/2022-08-19/rustc-beta-x86_64-unknown-illumos.tar.xz": "86cde423efde88155ce35514399897fcb2248ddac9f77244827ba4e10189038a",
+    "dist/2022-08-19/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "e2dea522d946db96791f651fdbb098bcf7285bdb0182e14c573f87826f6d99b2",
+    "dist/2022-08-19/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "399847ea81239d666acdd890b4407bf2f62f3a527a60515fa38fdfd3ff61d0d0",
+    "dist/2022-08-19/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "9e1511eb0704962ad3932578821bcfca877826cb18f14e4b7defbc08aaa9f0d8",
+    "dist/2022-08-19/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "1e0eb9eb917a1db99764b374844ab3ed2cbc83495c50b28f3dcf9512edcb035f",
+    "dist/2022-08-19/rustc-beta-x86_64-unknown-netbsd.tar.gz": "28651213923b8009c6317b59a2a15f6f202108efa0b604a590b735b0cd031202",
+    "dist/2022-08-19/rustc-beta-x86_64-unknown-netbsd.tar.xz": "36591aefa17e1a4cb55625632bc97931db6f3c4252d457963353bbfa5e997a32",
+    "dist/2022-08-20/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "3f90dbf1c64d8b4cddd1fcb589b85e4b76fae6c3fed88483210bf5bddecd2bf6",
+    "dist/2022-08-20/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "1f850ef1e1a6ee89cbb862ec986cc3b5de2b4654db625a5da0906f3eff3e834c",
+    "dist/2022-08-20/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "3b1a7f2e5d380b58bd02fd1f28212869f9feeb2fbb971694425cb837f99f8f0f",
+    "dist/2022-08-20/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "f24153076383ad22da9cefd9073c1e6dc227c582ef7fb92c73cdfbd4cef6c295",
+    "dist/2022-08-20/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "e409988fc3bd50f2120d3f5828e8f5a5494fa0bc5296a97f1c26294fb2e1ade7",
+    "dist/2022-08-20/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "854e275ecd011e12606203f4b9737c373a678821b7f11df6bc08b774d670ada7",
+    "dist/2022-08-20/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "31bb41173b63d3aaae977b0ab48b0302d1ba2b7f6470fbd7b0206557e2dca2f3",
+    "dist/2022-08-20/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "7f4e356dca11bfc4bcfc9ffa588640cd9321cd73bc70c16d55901f04a119ca2d",
+    "dist/2022-08-20/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "1a8a63027aeaca5c9981567c862222b9c2d0de0456c4534213f5686862507890",
+    "dist/2022-08-20/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "2d217c695886cd59bf7bf40091813d427eb302323650d3641439f050308b2660",
+    "dist/2022-08-20/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "bc257cce6466ef7bfd30eb9790db3e72cc425ce78f763954861b28232dfe1d55",
+    "dist/2022-08-20/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "3326acc5adcf63dde12937d1ad9be4eb8c01ed3f24b07e1df28d194754506a77",
+    "dist/2022-08-20/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "14dc0a6e21cd6e7294995bf7c14238c97cccaf37910765602ca37292267060b0",
+    "dist/2022-08-20/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "93628b8ea58d6484423ff58666520701702f36eab86846a19b205a9c8d737313",
+    "dist/2022-08-20/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "199dfdf436b9ae97aa7a4a081d6a88b29e825e0e3e24409a008531dc3ea3ae5b",
+    "dist/2022-08-20/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "cbce925e5bc323d970d7df1c714b31b693208eae0a00eb43a616da3ba499cca2",
+    "dist/2022-08-20/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "0c899e9273fb04c73c3abbd9483e74cf0312aa61d0818acbd2737a515432cb1c",
+    "dist/2022-08-20/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "bc3d2e850d77f13b563ce3b286fd781f49abc6ac17f046aea7397655c3955194",
+    "dist/2022-08-20/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "8940d2f6219a956521ef3c3c43001843cc5bd65706853e7b506848bf11c785d1",
+    "dist/2022-08-20/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "bee2d0136087693ed3328b8264f4c652f843a18128bfbf3d679b6ce426b44d07",
+    "dist/2022-08-20/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "37f383823d76b2f88fe7c7950b96aad73b94ffe5bf74f7af05d0bbe18c492f66",
+    "dist/2022-08-20/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "832d60d4dad18f729638c5cea3b5a3a8577b1875977b8bf2110537a4b17a71e2",
+    "dist/2022-08-20/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "e060d1a8925f9b7f670244718fc0d84519a590cc630e832b27a0bd8149c009af",
+    "dist/2022-08-20/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "3743c798e26306d3f55afcf989221ade32e5174132e939bd4d3f0a2f1fd7523e",
+    "dist/2022-08-20/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "723509d619bb3f2c5423267afdbe082b426678d5d1df850b7e0d51cbcad99491",
+    "dist/2022-08-20/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "da258b293fa651db38348eee14239171010b230e390074a65f5975bfd9a990f2",
+    "dist/2022-08-20/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "6ad271d28309c92a76bdef40052c624b8d9e62e389ab14c8df372a6d0cfb8883",
+    "dist/2022-08-20/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "b3e71cedf9df9ce72bdd9b559197fd3989e4d108cd71ff30806b75541c072c34",
+    "dist/2022-08-20/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "82e7f9cd8409e9eeb89166c8ff047910e24a45d65712cc4bef883bb5ccbeb51d",
+    "dist/2022-08-20/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "9e0da808f7a3c03b10b309b2a1d934e447bef877adbe78b8d5f9485b2464bb32",
+    "dist/2022-08-20/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "31841de97f5f7fef456205ab14b7cb568b7edd202f31fc8a4465105ab59ed413",
+    "dist/2022-08-20/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "bc55f15780a850f2fa19fa26d39edce194745235d6f209d21b86a2ab7924c4dd",
+    "dist/2022-08-20/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "bdb86ba6b1dfe3359823aa2be3ff1b945d7a34c21383fb2b2ec6f06122ef5587",
+    "dist/2022-08-20/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "1df7664bd1f32e1a9b5d37a4eaaaac54ca7b71853edfed4b0ece2e256f17290b",
+    "dist/2022-08-20/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "67727084e37de55a4cfa4ad2c1f3a834ef49379f949b50440aeb53d65c6dfc36",
+    "dist/2022-08-20/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "820fdce7d561b7e0118b25093cf639eab304ed29852921286f0cbda62e3e8752",
+    "dist/2022-08-20/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "8cf01738cb6e7450753000737c6b33acf7d433d32b28f6b278d6efb9513c4464",
+    "dist/2022-08-20/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "3bb194f2d770934580d063b7f0939cea231dbd280a4df062f0309c3dcbcd1d32",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "95a42b3a88d411d7c2567f8532bf86d3bd8ee57ff2a5254c147f08502f5488a9",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "ed885440a7a03d81dfc6ba206c37afdcd4480368a11143805ca12d8df583172d",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "2d6aa369242b820621cddc095f833eb5bf9dda9127dbcea179d730b2e1fc0d09",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "49291adffb00f8f25e9dadfb8e8f530d6a151479e8024de4b0b42c52c7a21f7e",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "a61ebb7b049b8a8c8440acc7e8698896a3143c0e1f8b1c29084f680e12087d9b",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "8bde3268496729d1f5178863859fdad77fa94f85887b0c129e0517226e3bdfb4",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "08f4bcd90bc01fea5e0c6238d40fb59bd1160e6635b401f908c046e6446d2183",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "a13ad331d827666d8631b4b30a51b1b69de0a90e9cfecc1e8bfb559d52144353",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "2c7c0607392a0d2cf517cc4fcb726f443c85c26b7deca0f10cbc555de56d20d3",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "bbd31f2bd64b4cc2e11c0936787bb44d792d20ec303e3b55efd53e0bd8efe88c",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "27703699164e10526a32a6920eb8d0b71e3572d423defecd81cd6b24c2c5134a",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "e4d388af9bdfee7bb6470a4467e7743a9b7827cd9d4219174fd424c18204a6b6",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "e090c6410f3ded22065097b5839a80d1ca6c80a7657ca28b88244fe119977371",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "a00a785d87e64660165b56489f6709c0d0280ae728782356a3274e8c0be48c36",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "ab9736c80331f0febe42a0e1f29d758327c4c8035954111370ff2c568c784fe4",
+    "dist/2022-08-20/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "ca8127aeae4e84a208ce9a5cdd04c497894e62c226c8bccd00713c1a41f99ddd"
   }
 }
index b4fda5f8c8428d0c879382dbf0a6e616af8315f6..4dc9d183b0b20d2d1515e1a092057a411eee80f1 100644 (file)
@@ -24,7 +24,7 @@ trait Freeze { }
 #[lang="copy"]
 trait Copy { }
 
-//x86_64: define win64cc void @has_efiapi
+//x86_64: define dso_local win64cc void @has_efiapi
 //i686: define void @has_efiapi
 //aarch64: define dso_local void @has_efiapi
 //arm: define dso_local void @has_efiapi
index 530164edd468278073cbf036d0393f6fd3c37d60..a038dfe76f7077dbb59134f3f5d9ea4f36c36db5 100644 (file)
@@ -77,7 +77,7 @@ fn update_bar_value() {
     }
 }
 
-// CHECK: define void @test(){{.+}}addrspace(1)
+// CHECK: define dso_local void @test(){{.+}}addrspace(1)
 #[no_mangle]
 pub extern "C" fn test() {
     let mut buf = 7;
index 6c18adbcb3c92b5efc46cdc5122ab49e646c9ea4..f53fa240cd1adba3e52e9a9a92fe6af0aeae0a78 100644 (file)
@@ -1,5 +1,5 @@
 // Test that `wrapping_div` only checks divisor once.
-// This test checks that there is only a single compare agains -1 and -1 is not present as a
+// This test checks that there is only a single compare against -1 and -1 is not present as a
 // switch case (the second check present until rustc 1.12).
 // This test also verifies that a single panic call is generated (for the division by zero case).
 
diff --git a/src/test/codegen/issue-85872-multiple-reverse.rs b/src/test/codegen/issue-85872-multiple-reverse.rs
new file mode 100644 (file)
index 0000000..591a1ac
--- /dev/null
@@ -0,0 +1,20 @@
+// min-llvm-version: 15.0.0
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn u16_be_to_arch(mut data: [u8; 2]) -> [u8; 2] {
+    // CHECK-LABEL: @u16_be_to_arch
+    // CHECK: @llvm.bswap.i16
+    data.reverse();
+    data
+}
+
+#[no_mangle]
+pub fn u32_be_to_arch(mut data: [u8; 4]) -> [u8; 4] {
+    // CHECK-LABEL: @u32_be_to_arch
+    // CHECK: @llvm.bswap.i32
+    data.reverse();
+    data
+}
diff --git a/src/test/codegen/issue-96274.rs b/src/test/codegen/issue-96274.rs
new file mode 100644 (file)
index 0000000..28bfcce
--- /dev/null
@@ -0,0 +1,17 @@
+// min-llvm-version: 15.0
+// compile-flags: -O
+
+#![crate_type = "lib"]
+#![feature(inline_const)]
+
+use std::mem::MaybeUninit;
+
+pub fn maybe_uninit() -> [MaybeUninit<u8>; 3000] {
+    // CHECK-NOT: memset
+    [MaybeUninit::uninit(); 3000]
+}
+
+pub fn maybe_uninit_const<T>() -> [MaybeUninit<T>; 8192] {
+    // CHECK-NOT: memset
+    [const { MaybeUninit::uninit() }; 8192]
+}
index 1fe048068601d436e1dc85f71bc23cb446c0caf6..c092e28a05ac8f098769965785aeb9ae4f75f988 100644 (file)
@@ -5,7 +5,7 @@
 #[lang="sized"]
 trait Sized { }
 
-// Test that `nounwind` atributes are correctly applied to exported `aapcs` and
+// Test that `nounwind` attributes are correctly applied to exported `aapcs` and
 // `aapcs-unwind` extern functions. `aapcs-unwind` functions MUST NOT have this attribute. We
 // disable optimizations above to prevent LLVM from inferring the attribute.
 
index e817d5715a189c9d321f83cb18369e69056a8295..8447bbeb1ed205e6f6a9b2695339e2c4d43f6de7 100644 (file)
@@ -1,6 +1,6 @@
 // compile-flags: -C panic=abort
 
-// Test that `nounwind` atributes are also applied to extern `C-unwind` Rust functions
+// Test that `nounwind` attributes are also applied to extern `C-unwind` Rust functions
 // when the code is compiled with `panic=abort`.
 
 #![crate_type = "lib"]
index f15765367532261eca351376d3d45337b642e023..e258dbcacd229a3f5aa7bfaffc7e3108546a597f 100644 (file)
@@ -1,6 +1,6 @@
 // compile-flags: -C opt-level=0
 
-// Test that `nounwind` atributes are correctly applied to exported `C` and `C-unwind` extern
+// Test that `nounwind` attributes are correctly applied to exported `C` and `C-unwind` extern
 // functions. `C-unwind` functions MUST NOT have this attribute. We disable optimizations above
 // to prevent LLVM from inferring the attribute.
 
index 52e0d2d6e02526ff3a5484bee386e744e8c5eec2..19a7228839abfb82662085d69e69b643416e16d1 100644 (file)
@@ -1,6 +1,6 @@
 // compile-flags: -C opt-level=0
 
-// Test that `nounwind` atributes are correctly applied to exported `cdecl` and
+// Test that `nounwind` attributes are correctly applied to exported `cdecl` and
 // `cdecl-unwind` extern functions. `cdecl-unwind` functions MUST NOT have this attribute. We
 // disable optimizations above to prevent LLVM from inferring the attribute.
 
index ed23235ebfa809c08f0e5e1f46915b8982f4818c..b74099a5d965b0f386e361404dd1121908f9852c 100644 (file)
@@ -5,7 +5,7 @@
 #[lang="sized"]
 trait Sized { }
 
-// Test that `nounwind` atributes are correctly applied to exported `fastcall` and
+// Test that `nounwind` attributes are correctly applied to exported `fastcall` and
 // `fastcall-unwind` extern functions. `fastcall-unwind` functions MUST NOT have this attribute. We
 // disable optimizations above to prevent LLVM from inferring the attribute.
 
index 9a4b3d3b4848080f8c07696429bba0b669d1f229..106d593b21de23bda5e1a941117403b7692bddb1 100644 (file)
@@ -3,7 +3,7 @@
 
 #![crate_type = "lib"]
 
-// We disable optimizations to prevent LLVM from infering the attribute.
+// We disable optimizations to prevent LLVM from inferring the attribute.
 
 // CHECK: Function Attrs:{{.*}}nounwind
 // CHECK-NEXT: @foo
index 2783c83d3efe08e6c94827e33dfe89e45cc28999..c1c5bbdda3456ba8121cd62d24a090bc50172408 100644 (file)
@@ -3,7 +3,7 @@
 
 #![crate_type = "lib"]
 
-// We disable optimizations to prevent LLVM from infering the attribute.
+// We disable optimizations to prevent LLVM from inferring the attribute.
 
 extern "C" {
     fn bar();
index cfc140361f62363bb03c27eba653bc554dd3916a..c46d717331b465fda746b35aa9e6da5b329361c5 100644 (file)
@@ -4,7 +4,7 @@
 #![crate_type = "lib"]
 #![feature(c_unwind)]
 
-// We disable optimizations to prevent LLVM from infering the attribute.
+// We disable optimizations to prevent LLVM from inferring the attribute.
 
 // CHECK: Function Attrs:{{.*}}nounwind
 // CHECK-NEXT: @foo
index f1dff27ad67b25d1413423e67dd4b11d7c7710cd..8eff0719f8fa7c19826e56420e01d80b1b63f40a 100644 (file)
@@ -5,7 +5,7 @@
 #[lang="sized"]
 trait Sized { }
 
-// Test that `nounwind` atributes are correctly applied to exported `stdcall` and `stdcall-unwind`
+// Test that `nounwind` attributes are correctly applied to exported `stdcall` and `stdcall-unwind`
 // extern functions. `stdcall-unwind` functions MUST NOT have this attribute. We disable
 // optimizations above to prevent LLVM from inferring the attribute.
 
index c4d51328352c06ca138f792ad2734913258244e3..2591c1d4814302f1cfb4882dc9d6bbf58b17536c 100644 (file)
@@ -1,6 +1,6 @@
 // compile-flags: -C opt-level=0
 
-// Test that `nounwind` atributes are correctly applied to exported `system` and `system-unwind`
+// Test that `nounwind` attributes are correctly applied to exported `system` and `system-unwind`
 // extern functions. `system-unwind` functions MUST NOT have this attribute. We disable
 // optimizations above to prevent LLVM from inferring the attribute.
 
index a38736f2a1f956ab60991d07d10752bca316d959..694fde17c3cbeedc5593ed638e7f925216c3b898 100644 (file)
@@ -5,7 +5,7 @@
 #[lang="sized"]
 trait Sized { }
 
-// Test that `nounwind` atributes are correctly applied to exported `sysv64` and
+// Test that `nounwind` attributes are correctly applied to exported `sysv64` and
 // `sysv64-unwind` extern functions. `sysv64-unwind` functions MUST NOT have this attribute. We
 // disable optimizations above to prevent LLVM from inferring the attribute.
 
index d2cf041b72d2371efa2b994ce219d3b74cf3f227..7e81367fc5b78d5165c5c744e251620a6e105603 100644 (file)
@@ -5,7 +5,7 @@
 #[lang="sized"]
 trait Sized { }
 
-// Test that `nounwind` atributes are correctly applied to exported `thiscall` and
+// Test that `nounwind` attributes are correctly applied to exported `thiscall` and
 // `thiscall-unwind` extern functions. `thiscall-unwind` functions MUST NOT have this attribute. We
 // disable optimizations above to prevent LLVM from inferring the attribute.
 
index 0fb9612a5e4e86a3657cbe01982f125884f58c30..d7eca2a97000298b15ba2dc919fe35754d3b074b 100644 (file)
@@ -5,7 +5,7 @@
 #[lang="sized"]
 trait Sized { }
 
-// Test that `nounwind` atributes are correctly applied to exported `vectorcall` and
+// Test that `nounwind` attributes are correctly applied to exported `vectorcall` and
 // `vectorcall-unwind` extern functions. `vectorcall-unwind` functions MUST NOT have this attribute.
 // We disable optimizations above to prevent LLVM from inferring the attribute.
 
index 5d8482da63056cdc635d33fdb37eb74900fa035f..6591348c35d3d436d1409281be8091f227cefd92 100644 (file)
@@ -5,7 +5,7 @@
 #[lang="sized"]
 trait Sized { }
 
-// Test that `nounwind` atributes are correctly applied to exported `win64` and
+// Test that `nounwind` attributes are correctly applied to exported `win64` and
 // `win64-unwind` extern functions. `win64-unwind` functions MUST NOT have this attribute. We
 // disable optimizations above to prevent LLVM from inferring the attribute.
 
index c939235fb5006c121d4afa0c5402b0e2a21a58d9..6ac3c079f81ba5da6457a56cb81f463a2de546cf 100644 (file)
@@ -5,7 +5,7 @@
 #![feature(c_unwind)]
 
 // Make sure these all do *not* get the attribute.
-// We disable optimizations to prevent LLVM from infering the attribute.
+// We disable optimizations to prevent LLVM from inferring the attribute.
 // CHECK-NOT: nounwind
 
 // "C" ABI
index 53358b183cbf527ad6d6476088aa71fc6e7ed6ec..5ff7b19d8945e635434250ddce7012c63f42e947 100644 (file)
@@ -9,6 +9,7 @@ fn c<T, const N: std::num::NonZeroUsize>()
     use std::convert::TryFrom;
     <[T; N.get()]>::try_from(())
     //~^ error: the trait bound
+    //~| error: the trait bound
     //~| error: mismatched types
 }
 
index b466cfdd595946e5212305a460c26cae2ce909f7..0f8898c389b7f4b33a819f03ff42622696884748 100644 (file)
@@ -504,9 +504,9 @@ enum EnumAddLifetimeBoundToParameter<'a, T> {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail6")]
 enum EnumAddLifetimeBoundToParameter<'a, T: 'a> {
     Variant1(T),
@@ -559,9 +559,9 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail6")]
 enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a {
     Variant1(T),
index 1988f3f35417cbc94be1426148328e0bdd54cf0e..c453eeceb77f53b1266e25a5eccef6a814f5a297 100644 (file)
@@ -1066,9 +1066,9 @@ trait TraitAddTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
 trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { }
 
@@ -1144,9 +1144,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0 + Refer
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a> { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { }
 
@@ -1201,9 +1201,9 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0
 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { }
 
@@ -1254,9 +1254,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T>
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { }
 
index 8124141418bc3cfbe53396a658f9e5077fbccc84..355d334585249bcc28e5c1ceb74250defd7547ae 100644 (file)
@@ -2,7 +2,7 @@
 // compile-flags: -Z query-dep-graph
 // aux-build:cached_hygiene.rs
 
-// This tests the folllowing scenario
+// This tests the following scenario
 // 1. A foreign crate is compiled with incremental compilation.
 //    This causes hygiene information to be saved to the incr cache.
 // 2. One function is the foreign crate is modified. This causes the
index 50d8fb86930776580195074f87c6dfc8556d36ee..8d13718b8d847a767c3c6f8a52d2b7f2dfd2c92f 100644 (file)
@@ -1,5 +1,5 @@
 // Regression test for hashing involving canonical variables.  In this
-// test -- which has an intensional error -- the type of the value
+// test -- which has an intentional error -- the type of the value
 // being dropped winds up including a type variable. Canonicalization
 // would then produce a `?0` which -- in turn -- triggered an ICE in
 // hashing.
index 4d48a5f0ac528e2d138504350b4a2463abed0447..95f3b8ae4d9868fa8050317b99dffdb67693b1ec 100644 (file)
@@ -3,7 +3,7 @@
 
 // rust-lang/rust#69798:
 //
-// This is analgous to cgu_invalidated_when_import_added, but it covers a
+// This is analogous to cgu_invalidated_when_import_added, but it covers a
 // problem uncovered where a change to the *export* set caused a link failure
 // when reusing post-LTO optimized object code.
 
index e85b4856f3a96ef98297eec55e1f042c73e50b2e..e86ebd354b1a9601b4ae29b2e13d17ba6ee1640f 100644 (file)
@@ -3,7 +3,7 @@
 
 // rust-lang/rust#69798:
 //
-// This is analgous to cgu_invalidated_when_export_added, but it covers the
+// This is analogous to cgu_invalidated_when_export_added, but it covers the
 // other direction. This is analogous to cgu_invalidated_when_import_added: we
 // include it, because it may uncover bugs in variant implementation strategies.
 
index 4f205667be0e2821a76f724caa84733ed84e2304..186a953735675ec67382585fca5dc3510245b973 100644 (file)
@@ -41,7 +41,8 @@
           StorageLive(_4);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10
           _4 = (_2.1: i32);                // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16
           StorageLive(_5);                 // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10
-          _5 = (_2.0: i32);                // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
+-         _5 = (_2.0: i32);                // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
++         _5 = const 1_i32;                // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16
           nop;                             // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+0:11: +6:2
           StorageDead(_5);                 // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
           StorageDead(_4);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
index 68c834dfbbf27bb491e76f51e1369074848ee83b..eb6cb09fc455492d9dcf2201b7565c83382f1316 100644 (file)
@@ -1,4 +1,4 @@
-//! Tests that we can propogate into places that are projections into unions
+//! Tests that we can propagate into places that are projections into unions
 // compile-flags: -Zunsound-mir-opts
 fn val() -> u32 {
     1
index ca298e9211d4864400aa0116975c4c86ad5c9f04..a6a56f3a95d18b302869fac8672cd620e0b68829 100644 (file)
@@ -1,4 +1,6 @@
-// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
+// unit-test: EarlyOtherwiseBranch
+
+// FIXME: This test was broken by the derefer change.
 
 // example from #68867
 type CSSFloat = f32;
@@ -11,7 +13,6 @@ pub enum ViewportPercentageLength {
 }
 
 // EMIT_MIR early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
-// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyConstCondition-final.after
 #[no_mangle]
 pub extern "C" fn try_sum(
     x: &ViewportPercentageLength,
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
deleted file mode 100644 (file)
index 8b37fb7..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-- // MIR for `try_sum` before EarlyOtherwiseBranch
-+ // MIR for `try_sum` after SimplifyConstCondition-final
-  
-  fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> Result<ViewportPercentageLength, ()> {
-      debug x => _1;                       // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+1:5: +1:6
-      debug other => _2;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+2:5: +2:10
-      let mut _0: std::result::Result<ViewportPercentageLength, ()>; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:+3:6: +3:42
-      let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6
-      let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16
-      let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23
-      let mut _7: isize;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:21: +6:30
-      let mut _8: isize;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:21: +7:30
-      let mut _9: isize;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:23: +8:34
-      let mut _10: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:23: +9:34
-      let mut _11: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:11: +6:18
-      let _12: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
-      let _13: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
-      let mut _14: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49
-      let mut _15: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41
-      let mut _16: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49
-      let _17: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
-      let _18: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
-      let mut _19: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49
-      let mut _20: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41
-      let mut _21: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49
-      let _22: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
-      let _23: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
-      let mut _24: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55
-      let mut _25: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47
-      let mut _26: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55
-      let _27: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
-      let _28: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
-      let mut _29: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55
-      let mut _30: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47
-      let mut _31: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55
-      let mut _32: !;                      // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:14: +10:28
-      let mut _33: ();                     // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
-      let mut _34: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _35: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _36: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _37: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _38: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _39: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _40: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _41: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _42: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _43: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _44: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _45: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      let mut _46: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-      scope 1 {
--         debug one => _12;                // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
--         debug other => _13;              // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
-+         debug one => _15;                // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
-+         debug other => _16;              // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
-      }
-      scope 2 {
--         debug one => _17;                // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
--         debug other => _18;              // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
-+         debug one => _20;                // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
-+         debug other => _21;              // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
-      }
-      scope 3 {
--         debug one => _22;                // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
--         debug other => _23;              // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
-+         debug one => _25;                // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
-+         debug other => _26;              // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
-      }
-      scope 4 {
--         debug one => _27;                // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
--         debug other => _28;              // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
-+         debug one => _30;                // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
-+         debug other => _31;              // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
-      }
-  
-      bb0: {
--         StorageLive(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6
--         StorageLive(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
--         StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16
--         _5 = _1;                         // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16
-+         (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16
-          StorageLive(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23
-          _6 = _2;                         // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23
-          Deinit(_4);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
--         (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          StorageDead(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24
--         StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24
-          _34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          _11 = discriminant((*_34));      // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb11]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
-      }
-  
-      bb1: {
-          _35 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          _7 = discriminant((*_35));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
-      }
-  
-      bb2: {
-          StorageLive(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
-          nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
-          Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
-          nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
-          discriminant(_0) = 1;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
-          StorageDead(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:27: +10:28
--         StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
--         StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
-          return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
-      }
-  
-      bb3: {
-          _36 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          _8 = discriminant((*_36));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
-      }
-  
-      bb4: {
-          _37 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          _9 = discriminant((*_37));       // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
-      }
-  
-      bb5: {
-          _38 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          _10 = discriminant((*_38));      // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
-      }
-  
-      bb6: {
--         StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
-          _39 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
--         _12 = (((*_39) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
--         StorageLive(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
-+         _15 = (((*_39) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
-          _40 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
--         _13 = (((*_40) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
--         StorageLive(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49
--         StorageLive(_15);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41
--         _15 = _12;                       // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41
--         StorageLive(_16);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49
--         _16 = _13;                       // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49
--         _14 = Add(move _15, move _16);   // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49
--         StorageDead(_16);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49
--         StorageDead(_15);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49
--         Deinit(_3);                      // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
--         ((_3 as Vw).0: f32) = move _14;  // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
--         discriminant(_3) = 0;            // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
--         StorageDead(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
--         StorageDead(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
--         StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
-+         _16 = (((*_40) as Vw).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49
-+         ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49
-+         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
-+         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
-          goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50
-      }
-  
-      bb7: {
--         StorageLive(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
-          _41 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
--         _17 = (((*_41) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
--         StorageLive(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
-+         _20 = (((*_41) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
-          _42 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
--         _18 = (((*_42) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
--         StorageLive(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49
--         StorageLive(_20);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41
--         _20 = _17;                       // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41
--         StorageLive(_21);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49
--         _21 = _18;                       // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49
--         _19 = Add(move _20, move _21);   // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49
--         StorageDead(_21);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49
--         StorageDead(_20);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49
--         Deinit(_3);                      // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
--         ((_3 as Vh).0: f32) = move _19;  // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
--         discriminant(_3) = 1;            // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
--         StorageDead(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
--         StorageDead(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
--         StorageDead(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
-+         _21 = (((*_42) as Vh).0: f32);   // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49
-+         ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49
-+         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
-+         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
-          goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50
-      }
-  
-      bb8: {
--         StorageLive(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
-          _43 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
--         _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
--         StorageLive(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
-+         _25 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
-          _44 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
--         _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
--         StorageLive(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55
--         StorageLive(_25);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47
--         _25 = _22;                       // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47
--         StorageLive(_26);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55
--         _26 = _23;                       // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55
--         _24 = Add(move _25, move _26);   // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55
--         StorageDead(_26);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55
--         StorageDead(_25);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55
--         Deinit(_3);                      // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
--         ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
--         discriminant(_3) = 2;            // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
--         StorageDead(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
--         StorageDead(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
--         StorageDead(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
-+         _26 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55
-+         ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55
-+         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
-+         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
-          goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56
-      }
-  
-      bb9: {
--         StorageLive(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
-          _45 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
--         _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
--         StorageLive(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
-+         _30 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
-          _46 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
--         _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
--         StorageLive(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55
--         StorageLive(_30);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47
--         _30 = _27;                       // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47
--         StorageLive(_31);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55
--         _31 = _28;                       // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55
--         _29 = Add(move _30, move _31);   // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55
--         StorageDead(_31);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55
--         StorageDead(_30);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55
--         Deinit(_3);                      // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
--         ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
--         discriminant(_3) = 3;            // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
--         StorageDead(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
--         StorageDead(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
--         StorageDead(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
-+         _31 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55
-+         ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55
-+         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
-+         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
-          goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56
-      }
-  
-      bb10: {
-          Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
--         ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
-          discriminant(_0) = 0;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
--         StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
--         StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
-          return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
-      }
-  
-      bb11: {
-          unreachable;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
-      }
-  }
-  
index 50a58d4792a8d19ed25fafc1a2da11e30eac2592..6bc025bb5b204897dc703bc1ddfa995e634377de 100644 (file)
@@ -80,7 +80,7 @@
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24
           _34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
           _11 = discriminant((*_34));      // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24
-          switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb11]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
+          switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24
       }
   
       bb1: {
   
       bb2: {
           StorageLive(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
-          nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
+          Deinit(_33);                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27
           Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
-          nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
+          ((_0 as Err).0: ()) = move _33;  // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
           discriminant(_0) = 1;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28
           StorageDead(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:27: +10:28
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
-          return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
+          goto -> bb11;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
       }
   
       bb3: {
           discriminant(_0) = 0;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2
-          return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
+          goto -> bb11;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
       }
   
       bb11: {
-          unreachable;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
+          return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2
       }
   }
   
index 5f677eafeb7f29e19a6b9c272ae8d030788df503..94f4a5a63178d73fd591ada5e72c9872b3e6cf03 100644 (file)
@@ -21,15 +21,13 @@ yields ()
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:13: 23:14
-        Deinit(_3);                      // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
-        (_3.0: i32) = const 5_i32;       // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
+        _3 = Foo(const 5_i32);           // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
         StorageLive(_4);                 // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:13: 24:14
-        Deinit(_4);                      // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
-        (_4.0: i32) = const 6_i32;       // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
+        _4 = Bar(const 6_i32);           // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
         StorageLive(_5);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
         StorageLive(_6);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
-        Deinit(_6);                      // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
-        _5 = yield(move _6) -> [resume: bb1, drop: bb5]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
+        _6 = ();                         // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
+        _5 = yield(move _6) -> [resume: bb1, drop: bb6]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
     }
 
     bb1: {
@@ -38,7 +36,7 @@ yields ()
         StorageLive(_7);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16
         StorageLive(_8);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:14: 26:15
         _8 = move _3;                    // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:14: 26:15
-        _7 = take::<Foo>(move _8) -> [return: bb2, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16
+        _7 = take::<Foo>(move _8) -> [return: bb2, unwind: bb10]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16
                                          // mir::Constant
                                          // + span: $DIR/generator-storage-dead-unwind.rs:26:9: 26:13
                                          // + literal: Const { ty: fn(Foo) {take::<Foo>}, val: Value(<ZST>) }
@@ -50,7 +48,7 @@ yields ()
         StorageLive(_9);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16
         StorageLive(_10);                // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:14: 27:15
         _10 = move _4;                   // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:14: 27:15
-        _9 = take::<Bar>(move _10) -> [return: bb3, unwind: bb8]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16
+        _9 = take::<Bar>(move _10) -> [return: bb3, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16
                                          // mir::Constant
                                          // + span: $DIR/generator-storage-dead-unwind.rs:27:9: 27:13
                                          // + literal: Const { ty: fn(Bar) {take::<Bar>}, val: Value(<ZST>) }
@@ -61,54 +59,66 @@ yields ()
         StorageDead(_9);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17
         _0 = const ();                   // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 28:6
         StorageDead(_4);                 // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-        StorageDead(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-        drop(_1) -> [return: bb4, unwind: bb11]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        goto -> bb4;                     // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
     }
 
     bb4: {
-        return;                          // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:18: +0:18
+        StorageDead(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        drop(_1) -> [return: bb5, unwind: bb14]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
     }
 
     bb5: {
+        return;                          // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:18: +0:18
+    }
+
+    bb6: {
         StorageDead(_6);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:13: 25:14
         StorageDead(_5);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:14: 25:15
         StorageDead(_4);                 // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-        drop(_3) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        drop(_3) -> [return: bb7, unwind: bb15]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
     }
 
-    bb6: {
+    bb7: {
         StorageDead(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-        drop(_1) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        drop(_1) -> [return: bb8, unwind: bb14]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
     }
 
-    bb7: {
+    bb8: {
         generator_drop;                  // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:16: +0:18
     }
 
-    bb8 (cleanup): {
+    bb9 (cleanup): {
         StorageDead(_10);                // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:15: 27:16
         StorageDead(_9);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17
-        goto -> bb10;                    // scope 2 at no-location
+        goto -> bb12;                    // scope 2 at no-location
     }
 
-    bb9 (cleanup): {
+    bb10 (cleanup): {
+        goto -> bb11;                    // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16
+    }
+
+    bb11 (cleanup): {
         StorageDead(_8);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16
         StorageDead(_7);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:16: 26:17
-        goto -> bb10;                    // scope 2 at no-location
+        goto -> bb12;                    // scope 2 at no-location
     }
 
-    bb10 (cleanup): {
+    bb12 (cleanup): {
         StorageDead(_4);                 // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        goto -> bb13;                    // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+    }
+
+    bb13 (cleanup): {
         StorageDead(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-        drop(_1) -> bb11;                // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        drop(_1) -> bb14;                // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
     }
 
-    bb11 (cleanup): {
+    bb14 (cleanup): {
         resume;                          // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:16: +0:18
     }
 
-    bb12 (cleanup): {
+    bb15 (cleanup): {
         StorageDead(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-        drop(_1) -> bb11;                // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        drop(_1) -> bb14;                // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
     }
 }
index 1917f757b6f0f4e8976a0ac560853365fd6cfc12..927f10242d2fee913e8ebecac4c0e3a43e47b19e 100644 (file)
@@ -38,7 +38,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 19:24
     bb1: {
         _10 = move _2;                   // scope 0 at $DIR/generator-tiny.rs:+0:16: +0:24
         nop;                             // scope 0 at $DIR/generator-tiny.rs:20:13: 20:15
-        Deinit((((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop)); // scope 0 at $DIR/generator-tiny.rs:20:18: 20:25
+        (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop) = HasDrop; // scope 0 at $DIR/generator-tiny.rs:20:18: 20:25
         StorageLive(_4);                 // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10
         goto -> bb2;                     // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10
     }
@@ -46,7 +46,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 19:24
     bb2: {
         StorageLive(_6);                 // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         StorageLive(_7);                 // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
-        Deinit(_7);                      // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
+        _7 = ();                         // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         Deinit(_0);                      // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         ((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         discriminant(_0) = 0;            // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
index 703b876123133a2f01e82f08d2096e6382ad6b8b..9e731c40908790c8a9c30440333ca8bc7c8bbca9 100644 (file)
@@ -10,4 +10,3 @@ fn main() {
 
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR issue_73223.main.SimplifyArmIdentity.diff
-// EMIT_MIR issue_73223.main.PreCodegen.diff
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
deleted file mode 100644 (file)
index be8e86a..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-- // MIR for `main` before PreCodegen
-+ // MIR for `main` after PreCodegen
-  
-  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 _3: i32;                         // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-      let mut _5: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _6: &i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _7: &i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _10: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _11: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _12: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _14: !;                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _15: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _16: &i32;                       // 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 _18: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _19: 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 _4: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
-          scope 3 {
-              debug _prev => _4;           // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14
-              let _8: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let _9: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let mut _20: &i32;           // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              scope 4 {
-                  debug left_val => _8;    // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  debug right_val => _9;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  let _13: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  scope 5 {
-                      debug kind => _13;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  }
-              }
-          }
-      }
-      scope 2 {
-          debug v => _3;                   // 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
-          StorageLive(_3);                 // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-          _3 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-          _1 = _3;                         // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21
-          StorageDead(_3);                 // 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(_4);                 // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
-          StorageLive(_5);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_6);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _6 = &_1;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _20 = 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])) }
-          _7 = _20;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_5);                      // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_5.0: &i32) = move _6;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_5.1: &i32) = move _7;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_6);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _8 = (_5.0: &i32);               // 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
-          _9 = (_5.1: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_10);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_12);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _12 = (*_8);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _11 = Eq(move _12, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_12);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _10 = Not(move _11);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          switchInt(move _10) -> [false: bb2, otherwise: bb1]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb1: {
-          StorageLive(_13);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_14);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_15);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_16);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _16 = _8;                        // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _15 = _16;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_17);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_18);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _18 = _9;                        // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _17 = _18;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_19);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_19);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          discriminant(_19) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _14 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _15, move _17, move _19); // 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)) }
-      }
-  
-      bb2: {
-          StorageDead(_10);                // scope 4 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
-          StorageDead(_5);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_4);                 // 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.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
deleted file mode 100644 (file)
index be8e86a..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-- // MIR for `main` before PreCodegen
-+ // MIR for `main` after PreCodegen
-  
-  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 _3: i32;                         // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-      let mut _5: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _6: &i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _7: &i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _10: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _11: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _12: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _14: !;                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _15: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _16: &i32;                       // 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 _18: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _19: 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 _4: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
-          scope 3 {
-              debug _prev => _4;           // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14
-              let _8: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let _9: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let mut _20: &i32;           // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              scope 4 {
-                  debug left_val => _8;    // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  debug right_val => _9;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  let _13: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  scope 5 {
-                      debug kind => _13;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  }
-              }
-          }
-      }
-      scope 2 {
-          debug v => _3;                   // 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
-          StorageLive(_3);                 // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-          _3 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-          _1 = _3;                         // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21
-          StorageDead(_3);                 // 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(_4);                 // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
-          StorageLive(_5);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_6);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _6 = &_1;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _20 = 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])) }
-          _7 = _20;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_5);                      // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_5.0: &i32) = move _6;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_5.1: &i32) = move _7;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_6);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _8 = (_5.0: &i32);               // 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
-          _9 = (_5.1: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_10);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_12);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _12 = (*_8);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _11 = Eq(move _12, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_12);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _10 = Not(move _11);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          switchInt(move _10) -> [false: bb2, otherwise: bb1]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb1: {
-          StorageLive(_13);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_14);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_15);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_16);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _16 = _8;                        // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _15 = _16;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_17);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_18);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _18 = _9;                        // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _17 = _18;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_19);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_19);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          discriminant(_19) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _14 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _15, move _17, move _19); // 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)) }
-      }
-  
-      bb2: {
-          StorageDead(_10);                // scope 4 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
-          StorageDead(_5);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_4);                 // 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_array_len.array_bound.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff
deleted file mode 100644 (file)
index 2589c9f..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-- // MIR for `array_bound` before InstCombine
-+ // MIR for `array_bound` after InstCombine
-  
-  fn array_bound(_1: usize, _2: &[u8; N]) -> u8 {
-      debug index => _1;                   // in scope 0 at $DIR/lower_array_len.rs:+0:36: +0:41
-      debug slice => _2;                   // in scope 0 at $DIR/lower_array_len.rs:+0:50: +0:55
-      let mut _0: u8;                      // return place in scope 0 at $DIR/lower_array_len.rs:+0:70: +0:72
-      let mut _3: bool;                    // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-      let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
-      let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-      let mut _6: &[u8];                   // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-      let mut _7: &[u8; N];                // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-      let _8: usize;                       // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-      let mut _9: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-      let mut _10: bool;                   // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-      let mut _11: &[u8; N];               // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-  
-      bb0: {
-          StorageLive(_3);                 // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-          StorageLive(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
-          _4 = _1;                         // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
-          StorageLive(_5);                 // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          StorageLive(_6);                 // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          StorageLive(_7);                 // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         _7 = &(*_2);                     // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+         _7 = _2;                         // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          StorageLive(_11);                // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          _11 = _7;                        // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          StorageDead(_7);                 // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21
--         _5 = Len((*_11));                // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+         _5 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          StorageDead(_11);                // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          StorageDead(_6);                 // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
-          _3 = Lt(move _4, move _5);       // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-          StorageDead(_5);                 // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
-          StorageDead(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
-          switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-      }
-  
-      bb1: {
-          StorageLive(_8);                 // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-          _8 = _1;                         // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
--         _9 = Len((*_2));                 // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+         _9 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-          _10 = Lt(_8, _9);                // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-          assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-      }
-  
-      bb2: {
-          _0 = (*_2)[_8];                  // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-          StorageDead(_8);                 // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6
-          goto -> bb4;                     // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6
-      }
-  
-      bb3: {
-          _0 = const 42_u8;                // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:11
-          goto -> bb4;                     // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6
-      }
-  
-      bb4: {
-          StorageDead(_3);                 // scope 0 at $DIR/lower_array_len.rs:+5:5: +5:6
-          return;                          // scope 0 at $DIR/lower_array_len.rs:+6:2: +6:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff
deleted file mode 100644 (file)
index 8312db6..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-- // MIR for `array_bound` before SimplifyLocals
-+ // MIR for `array_bound` after SimplifyLocals
-  
-  fn array_bound(_1: usize, _2: &[u8; N]) -> u8 {
-      debug index => _1;                   // in scope 0 at $DIR/lower_array_len.rs:+0:36: +0:41
-      debug slice => _2;                   // in scope 0 at $DIR/lower_array_len.rs:+0:50: +0:55
-      let mut _0: u8;                      // return place in scope 0 at $DIR/lower_array_len.rs:+0:70: +0:72
-      let mut _3: bool;                    // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-      let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
-      let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--     let mut _6: &[u8];                   // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--     let mut _7: &[u8; N];                // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--     let _8: usize;                       // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
--     let mut _9: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
--     let mut _10: bool;                   // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
--     let mut _11: &[u8; N];               // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+     let _6: usize;                       // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-+     let mut _7: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+     let mut _8: bool;                    // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-  
-      bb0: {
-          StorageLive(_3);                 // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-          StorageLive(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
-          _4 = _1;                         // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
-          StorageLive(_5);                 // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         StorageLive(_6);                 // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         StorageLive(_7);                 // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         StorageLive(_11);                // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         StorageDead(_7);                 // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21
-          _5 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         StorageDead(_11);                // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         StorageDead(_6);                 // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
-          _3 = Lt(move _4, move _5);       // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-          StorageDead(_5);                 // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
-          StorageDead(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
-          switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-      }
-  
-      bb1: {
--         StorageLive(_8);                 // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
--         _8 = _1;                         // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
--         _9 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
--         _10 = Lt(_8, _9);                // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
--         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+         StorageLive(_6);                 // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-+         _6 = _1;                         // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-+         _7 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+         _8 = Lt(_6, _7);                 // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-      }
-  
-      bb2: {
--         _0 = (*_2)[_8];                  // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
--         StorageDead(_8);                 // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6
-+         _0 = (*_2)[_6];                  // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+         StorageDead(_6);                 // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6
-          goto -> bb4;                     // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6
-      }
-  
-      bb3: {
-          _0 = const 42_u8;                // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:11
-          goto -> bb4;                     // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6
-      }
-  
-      bb4: {
-          StorageDead(_3);                 // scope 0 at $DIR/lower_array_len.rs:+5:5: +5:6
-          return;                          // scope 0 at $DIR/lower_array_len.rs:+6:2: +6:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff
deleted file mode 100644 (file)
index 401d4ba..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-- // MIR for `array_bound_mut` before InstCombine
-+ // MIR for `array_bound_mut` after InstCombine
-  
-  fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 {
-      debug index => _1;                   // in scope 0 at $DIR/lower_array_len.rs:+0:40: +0:45
-      debug slice => _2;                   // in scope 0 at $DIR/lower_array_len.rs:+0:54: +0:59
-      let mut _0: u8;                      // return place in scope 0 at $DIR/lower_array_len.rs:+0:78: +0:80
-      let mut _3: bool;                    // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-      let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
-      let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-      let mut _6: &[u8];                   // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-      let mut _7: &[u8; N];                // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-      let _8: usize;                       // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-      let mut _9: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-      let mut _10: bool;                   // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-      let _11: usize;                      // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
-      let mut _12: usize;                  // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-      let mut _13: bool;                   // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-      let mut _14: &[u8; N];               // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-  
-      bb0: {
-          StorageLive(_3);                 // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-          StorageLive(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
-          _4 = _1;                         // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
-          StorageLive(_5);                 // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          StorageLive(_6);                 // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          StorageLive(_7);                 // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          _7 = &(*_2);                     // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          StorageLive(_14);                // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          _14 = _7;                        // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          StorageDead(_7);                 // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21
--         _5 = Len((*_14));                // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+         _5 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          StorageDead(_14);                // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-          StorageDead(_6);                 // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
-          _3 = Lt(move _4, move _5);       // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-          StorageDead(_5);                 // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
-          StorageDead(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
-          switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-      }
-  
-      bb1: {
-          StorageLive(_8);                 // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-          _8 = _1;                         // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
--         _9 = Len((*_2));                 // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+         _9 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-          _10 = Lt(_8, _9);                // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-          assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-      }
-  
-      bb2: {
-          _0 = (*_2)[_8];                  // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-          StorageDead(_8);                 // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6
-          goto -> bb5;                     // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6
-      }
-  
-      bb3: {
-          StorageLive(_11);                // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
-          _11 = const 0_usize;             // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
--         _12 = Len((*_2));                // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-+         _12 = const N;                   // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-          _13 = Lt(_11, _12);              // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-          assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> bb4; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-      }
-  
-      bb4: {
-          (*_2)[_11] = const 42_u8;        // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22
-          StorageDead(_11);                // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23
-          _0 = const 42_u8;                // scope 0 at $DIR/lower_array_len.rs:+6:9: +6:11
-          goto -> bb5;                     // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6
-      }
-  
-      bb5: {
-          StorageDead(_3);                 // scope 0 at $DIR/lower_array_len.rs:+7:5: +7:6
-          return;                          // scope 0 at $DIR/lower_array_len.rs:+8:2: +8:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff
deleted file mode 100644 (file)
index 4f241d7..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-- // MIR for `array_bound_mut` before SimplifyLocals
-+ // MIR for `array_bound_mut` after SimplifyLocals
-  
-  fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 {
-      debug index => _1;                   // in scope 0 at $DIR/lower_array_len.rs:+0:40: +0:45
-      debug slice => _2;                   // in scope 0 at $DIR/lower_array_len.rs:+0:54: +0:59
-      let mut _0: u8;                      // return place in scope 0 at $DIR/lower_array_len.rs:+0:78: +0:80
-      let mut _3: bool;                    // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-      let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
-      let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--     let mut _6: &[u8];                   // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--     let mut _7: &[u8; N];                // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--     let _8: usize;                       // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
--     let mut _9: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
--     let mut _10: bool;                   // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
--     let _11: usize;                      // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
--     let mut _12: usize;                  // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
--     let mut _13: bool;                   // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
--     let mut _14: &[u8; N];               // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+     let _6: usize;                       // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-+     let mut _7: usize;                   // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+     let mut _8: bool;                    // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+     let _9: usize;                       // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
-+     let mut _10: usize;                  // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-+     let mut _11: bool;                   // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-  
-      bb0: {
-          StorageLive(_3);                 // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-          StorageLive(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
-          _4 = _1;                         // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13
-          StorageLive(_5);                 // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         StorageLive(_6);                 // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         StorageLive(_7);                 // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         StorageLive(_14);                // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         StorageDead(_7);                 // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21
-          _5 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         StorageDead(_14);                // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
--         StorageDead(_6);                 // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
-          _3 = Lt(move _4, move _5);       // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-          StorageDead(_5);                 // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
-          StorageDead(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27
-          switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
-      }
-  
-      bb1: {
--         StorageLive(_8);                 // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
--         _8 = _1;                         // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
--         _9 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
--         _10 = Lt(_8, _9);                // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
--         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+         StorageLive(_6);                 // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-+         _6 = _1;                         // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
-+         _7 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+         _8 = Lt(_6, _7);                 // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-      }
-  
-      bb2: {
--         _0 = (*_2)[_8];                  // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
--         StorageDead(_8);                 // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6
-+         _0 = (*_2)[_6];                  // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+         StorageDead(_6);                 // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6
-          goto -> bb5;                     // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6
-      }
-  
-      bb3: {
--         StorageLive(_11);                // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
--         _11 = const 0_usize;             // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
--         _12 = const N;                   // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
--         _13 = Lt(const 0_usize, _12);    // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
--         assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-+         StorageLive(_9);                 // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
-+         _9 = const 0_usize;              // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
-+         _10 = const N;                   // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-+         _11 = Lt(const 0_usize, _10);    // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-+         assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-      }
-  
-      bb4: {
--         (*_2)[_11] = const 42_u8;        // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22
--         StorageDead(_11);                // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23
-+         (*_2)[_9] = const 42_u8;         // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22
-+         StorageDead(_9);                 // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23
-          _0 = const 42_u8;                // scope 0 at $DIR/lower_array_len.rs:+6:9: +6:11
-          goto -> bb5;                     // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6
-      }
-  
-      bb5: {
-          StorageDead(_3);                 // scope 0 at $DIR/lower_array_len.rs:+7:5: +7:6
-          return;                          // scope 0 at $DIR/lower_array_len.rs:+8:2: +8:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff
deleted file mode 100644 (file)
index 26f45be..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-- // MIR for `array_len` before InstCombine
-+ // MIR for `array_len` after InstCombine
-  
-  fn array_len(_1: &[u8; N]) -> usize {
-      debug arr => _1;                     // in scope 0 at $DIR/lower_array_len.rs:+0:34: +0:37
-      let mut _0: usize;                   // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57
-      let mut _2: &[u8];                   // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-      let mut _3: &[u8; N];                // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-      let mut _4: &[u8; N];                // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          StorageLive(_3);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--         _3 = &(*_1);                     // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+         _3 = _1;                         // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          StorageLive(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          _4 = _3;                         // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          StorageDead(_3);                 // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8
--         _0 = Len((*_4));                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+         _0 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          StorageDead(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          StorageDead(_2);                 // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14
-          return;                          // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff
deleted file mode 100644 (file)
index 09d571d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-- // MIR for `array_len` before SimplifyLocals
-+ // MIR for `array_len` after SimplifyLocals
-  
-  fn array_len(_1: &[u8; N]) -> usize {
-      debug arr => _1;                     // in scope 0 at $DIR/lower_array_len.rs:+0:34: +0:37
-      let mut _0: usize;                   // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57
--     let mut _2: &[u8];                   // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--     let mut _3: &[u8; N];                // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--     let mut _4: &[u8; N];                // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-  
-      bb0: {
--         StorageLive(_2);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--         StorageLive(_3);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--         StorageLive(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--         StorageDead(_3);                 // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8
-          _0 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--         StorageDead(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--         StorageDead(_2);                 // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14
-          return;                          // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff
deleted file mode 100644 (file)
index 843da75..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-- // MIR for `array_len_by_value` before InstCombine
-+ // MIR for `array_len_by_value` after InstCombine
-  
-  fn array_len_by_value(_1: [u8; N]) -> usize {
-      debug arr => _1;                     // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:46
-      let mut _0: usize;                   // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65
-      let mut _2: &[u8];                   // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-      let mut _3: &[u8; N];                // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-      let mut _4: &[u8; N];                // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          StorageLive(_3);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          _3 = &_1;                        // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          StorageLive(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          _4 = _3;                         // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          StorageDead(_3);                 // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8
--         _0 = Len((*_4));                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+         _0 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          StorageDead(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-          StorageDead(_2);                 // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14
-          return;                          // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff
deleted file mode 100644 (file)
index dc1c00b..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-- // MIR for `array_len_by_value` before SimplifyLocals
-+ // MIR for `array_len_by_value` after SimplifyLocals
-  
-  fn array_len_by_value(_1: [u8; N]) -> usize {
-      debug arr => _1;                     // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:46
-      let mut _0: usize;                   // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65
--     let mut _2: &[u8];                   // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--     let mut _3: &[u8; N];                // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--     let mut _4: &[u8; N];                // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-  
-      bb0: {
--         StorageLive(_2);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--         StorageLive(_3);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--         StorageLive(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--         StorageDead(_3);                 // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8
-          _0 = const N;                    // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--         StorageDead(_4);                 // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
--         StorageDead(_2);                 // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14
-          return;                          // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2
-      }
-  }
-  
index fc12ee75fcfcd233bccd82626f2e907bfa06ca5d..ea0224b21d72d769972aef5f75c3c0876ae8b495 100644 (file)
@@ -1,8 +1,7 @@
-// compile-flags: -Z mir-opt-level=4
+// unit-test: NormalizeArrayLen
+// compile-flags: -Zmir-enable-passes=+LowerSliceLenCalls
 
 // EMIT_MIR lower_array_len.array_bound.NormalizeArrayLen.diff
-// EMIT_MIR lower_array_len.array_bound.SimplifyLocals.diff
-// EMIT_MIR lower_array_len.array_bound.InstCombine.diff
 pub fn array_bound<const N: usize>(index: usize, slice: &[u8; N]) -> u8 {
     if index < slice.len() {
         slice[index]
@@ -12,8 +11,6 @@
 }
 
 // EMIT_MIR lower_array_len.array_bound_mut.NormalizeArrayLen.diff
-// EMIT_MIR lower_array_len.array_bound_mut.SimplifyLocals.diff
-// EMIT_MIR lower_array_len.array_bound_mut.InstCombine.diff
 pub fn array_bound_mut<const N: usize>(index: usize, slice: &mut [u8; N]) -> u8 {
     if index < slice.len() {
         slice[index]
 }
 
 // EMIT_MIR lower_array_len.array_len.NormalizeArrayLen.diff
-// EMIT_MIR lower_array_len.array_len.SimplifyLocals.diff
-// EMIT_MIR lower_array_len.array_len.InstCombine.diff
 pub fn array_len<const N: usize>(arr: &[u8; N]) -> usize {
     arr.len()
 }
 
 // EMIT_MIR lower_array_len.array_len_by_value.NormalizeArrayLen.diff
-// EMIT_MIR lower_array_len.array_len_by_value.SimplifyLocals.diff
-// EMIT_MIR lower_array_len.array_len_by_value.InstCombine.diff
 pub fn array_len_by_value<const N: usize>(arr: [u8; N]) -> usize {
     arr.len()
 }
diff --git a/src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir b/src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..2c6c93c
--- /dev/null
@@ -0,0 +1,49 @@
+// MIR for `array_bound` after PreCodegen
+
+fn array_bound(_1: usize, _2: &[u8; N]) -> u8 {
+    debug index => _1;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:36: +0:41
+    debug slice => _2;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:50: +0:55
+    let mut _0: u8;                      // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:70: +0:72
+    let mut _3: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+    let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
+    let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+    let _6: usize;                       // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20
+    let mut _7: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    let mut _8: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+
+    bb0: {
+        StorageLive(_3);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+        StorageLive(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
+        _4 = _1;                         // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
+        StorageLive(_5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+        _5 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+        _3 = Lt(move _4, move _5);       // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+        StorageDead(_5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+        StorageDead(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+        switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+    }
+
+    bb1: {
+        StorageLive(_6);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20
+        _6 = _1;                         // scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20
+        _7 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        _8 = Lt(_6, _7);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    }
+
+    bb2: {
+        _0 = (*_2)[_6];                  // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        StorageDead(_6);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+3:5: +3:6
+        goto -> bb4;                     // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6
+    }
+
+    bb3: {
+        _0 = const 42_u8;                // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:11
+        goto -> bb4;                     // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6
+    }
+
+    bb4: {
+        StorageDead(_3);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+5:5: +5:6
+        return;                          // scope 0 at $DIR/lower_array_len_e2e.rs:+6:2: +6:2
+    }
+}
diff --git a/src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir b/src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..aee3a82
--- /dev/null
@@ -0,0 +1,62 @@
+// MIR for `array_bound_mut` after PreCodegen
+
+fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 {
+    debug index => _1;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:40: +0:45
+    debug slice => _2;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:54: +0:59
+    let mut _0: u8;                      // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:78: +0:80
+    let mut _3: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+    let mut _4: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
+    let mut _5: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+    let _6: usize;                       // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20
+    let mut _7: usize;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    let mut _8: bool;                    // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    let _9: usize;                       // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+    let mut _10: usize;                  // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+    let mut _11: bool;                   // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+
+    bb0: {
+        StorageLive(_3);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+        StorageLive(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
+        _4 = _1;                         // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13
+        StorageLive(_5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+        _5 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
+        _3 = Lt(move _4, move _5);       // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+        StorageDead(_5);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+        StorageDead(_4);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
+        switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
+    }
+
+    bb1: {
+        StorageLive(_6);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20
+        _6 = _1;                         // scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20
+        _7 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        _8 = Lt(_6, _7);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+    }
+
+    bb2: {
+        _0 = (*_2)[_6];                  // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
+        StorageDead(_6);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+3:5: +3:6
+        goto -> bb5;                     // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6
+    }
+
+    bb3: {
+        StorageLive(_9);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+        _9 = const 0_usize;              // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
+        _10 = const N;                   // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+        _11 = Lt(const 0_usize, _10);    // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+        assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
+    }
+
+    bb4: {
+        (*_2)[_9] = const 42_u8;         // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22
+        StorageDead(_9);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23
+        _0 = const 42_u8;                // scope 0 at $DIR/lower_array_len_e2e.rs:+6:9: +6:11
+        goto -> bb5;                     // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6
+    }
+
+    bb5: {
+        StorageDead(_3);                 // scope 0 at $DIR/lower_array_len_e2e.rs:+7:5: +7:6
+        return;                          // scope 0 at $DIR/lower_array_len_e2e.rs:+8:2: +8:2
+    }
+}
diff --git a/src/test/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir b/src/test/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..4b19f67
--- /dev/null
@@ -0,0 +1,11 @@
+// MIR for `array_len` after PreCodegen
+
+fn array_len(_1: &[u8; N]) -> usize {
+    debug arr => _1;                     // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:34: +0:37
+    let mut _0: usize;                   // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:52: +0:57
+
+    bb0: {
+        _0 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14
+        return;                          // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2
+    }
+}
diff --git a/src/test/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir b/src/test/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..4dc0ba9
--- /dev/null
@@ -0,0 +1,11 @@
+// MIR for `array_len_by_value` after PreCodegen
+
+fn array_len_by_value(_1: [u8; N]) -> usize {
+    debug arr => _1;                     // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:43: +0:46
+    let mut _0: usize;                   // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:60: +0:65
+
+    bb0: {
+        _0 = const N;                    // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14
+        return;                          // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2
+    }
+}
diff --git a/src/test/mir-opt/lower_array_len_e2e.rs b/src/test/mir-opt/lower_array_len_e2e.rs
new file mode 100644 (file)
index 0000000..49b35d5
--- /dev/null
@@ -0,0 +1,39 @@
+// compile-flags: -Z mir-opt-level=4
+
+// EMIT_MIR lower_array_len_e2e.array_bound.PreCodegen.after.mir
+pub fn array_bound<const N: usize>(index: usize, slice: &[u8; N]) -> u8 {
+    if index < slice.len() {
+        slice[index]
+    } else {
+        42
+    }
+}
+
+// EMIT_MIR lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir
+pub fn array_bound_mut<const N: usize>(index: usize, slice: &mut [u8; N]) -> u8 {
+    if index < slice.len() {
+        slice[index]
+    } else {
+        slice[0] = 42;
+
+        42
+    }
+}
+
+// EMIT_MIR lower_array_len_e2e.array_len.PreCodegen.after.mir
+pub fn array_len<const N: usize>(arr: &[u8; N]) -> usize {
+    arr.len()
+}
+
+// EMIT_MIR lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir
+pub fn array_len_by_value<const N: usize>(arr: [u8; N]) -> usize {
+    arr.len()
+}
+
+fn main() {
+    let _ = array_bound(3, &[0, 1, 2, 3]);
+    let mut tmp = [0, 1, 2, 3, 4];
+    let _ = array_bound_mut(3, &mut [0, 1, 2, 3]);
+    let _ = array_len(&[0]);
+    let _ = array_len_by_value([0, 2]);
+}
index 5c635e2220ed707ce1de3fa180afae64e08f1413..3389db733b992a3a0576e83bae9c2d04a0490348 100644 (file)
@@ -7,7 +7,7 @@
       bb0: {
 -         _0 = std::intrinsics::min_align_of::<T>() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:19:5: 19:40
+-                                          // + span: $DIR/lower_intrinsics.rs:21:5: 21:40
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::min_align_of::<T>}, val: Value(<ZST>) }
 +         _0 = AlignOf(T);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42
index 8a80de32f3ae36d4c7916cc1849c93b4abed061a..f92ff9faf979686efb80d8edd3b0ba4def816b80 100644 (file)
@@ -31,7 +31,7 @@
           _3 = &(*_4);                     // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44
 -         _2 = discriminant_value::<T>(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:74:5: 74:41
+-                                          // + span: $DIR/lower_intrinsics.rs:49:5: 49:41
 -                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) }
 +         _2 = discriminant((*_3));        // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
           StorageLive(_7);                 // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
           _19 = const discriminant::<T>::promoted[2]; // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
                                            // mir::Constant
-                                           // + span: $DIR/lower_intrinsics.rs:75:42: 75:44
+                                           // + span: $DIR/lower_intrinsics.rs:50:42: 50:44
                                            // + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) }
           _7 = &(*_19);                    // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
           _6 = &(*_7);                     // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
 -         _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:75:5: 75:41
+-                                          // + span: $DIR/lower_intrinsics.rs:50:5: 50:41
 -                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) }
 +         _5 = discriminant((*_6));        // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
 +         goto -> bb2;                     // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
           StorageLive(_11);                // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
           _18 = const discriminant::<T>::promoted[1]; // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
                                            // mir::Constant
-                                           // + span: $DIR/lower_intrinsics.rs:76:42: 76:45
+                                           // + span: $DIR/lower_intrinsics.rs:51:42: 51:45
                                            // + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) }
           _11 = &(*_18);                   // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
           _10 = &(*_11);                   // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
 -         _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:76:5: 76:41
+-                                          // + span: $DIR/lower_intrinsics.rs:51:5: 51:41
 -                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) }
 +         _9 = discriminant((*_10));       // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
 +         goto -> bb3;                     // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
           StorageLive(_15);                // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
           _17 = const discriminant::<T>::promoted[0]; // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
                                            // mir::Constant
-                                           // + span: $DIR/lower_intrinsics.rs:77:42: 77:47
+                                           // + span: $DIR/lower_intrinsics.rs:52:42: 52:47
                                            // + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) }
           _15 = &(*_17);                   // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
           _14 = &(*_15);                   // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
 -         _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:77:5: 77:41
+-                                          // + span: $DIR/lower_intrinsics.rs:52:5: 52:41
 -                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) }
 +         _13 = discriminant((*_14));      // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
 +         goto -> bb4;                     // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
           StorageDead(_15);                // scope 0 at $DIR/lower_intrinsics.rs:+4:48: +4:49
           StorageDead(_13);                // scope 0 at $DIR/lower_intrinsics.rs:+4:48: +4:49
           _0 = const ();                   // scope 0 at $DIR/lower_intrinsics.rs:+0:30: +5:2
-          drop(_1) -> bb5;                 // scope 0 at $DIR/lower_intrinsics.rs:+5:1: +5:2
+          drop(_1) -> [return: bb5, unwind: bb6]; // scope 0 at $DIR/lower_intrinsics.rs:+5:1: +5:2
       }
   
       bb5: {
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+5:2: +5:2
       }
+  
+      bb6 (cleanup): {
+          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +5:2
+      }
   }
   
diff --git a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir b/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir
deleted file mode 100644 (file)
index 2a9a099..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// MIR for `f_u64` before PreCodegen
-
-fn f_u64() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:16: +0:16
-    let mut _1: u64;                     // in scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21
-    scope 1 (inlined f_dispatch::<u64>) { // at $DIR/lower_intrinsics.rs:40:5: 40:21
-        debug t => _1;                   // in scope 1 at $DIR/lower_intrinsics.rs:44:22: 44:23
-        let _2: ();                      // in scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21
-        let mut _3: u64;                 // in scope 1 at $DIR/lower_intrinsics.rs:48:19: 48:20
-        scope 2 (inlined std::mem::size_of::<u64>) { // at $DIR/lower_intrinsics.rs:45:8: 45:32
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21
-        _1 = const 0_u64;                // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21
-        StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21
-        StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:48:19: 48:20
-        _3 = move _1;                    // scope 1 at $DIR/lower_intrinsics.rs:48:19: 48:20
-        _2 = f_non_zst::<u64>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21
-                                         // mir::Constant
-                                         // + span: $DIR/lower_intrinsics.rs:48:9: 48:18
-                                         // + literal: Const { ty: fn(u64) {f_non_zst::<u64>}, val: Value(<ZST>) }
-    }
-
-    bb1: {
-        StorageDead(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:48:20: 48:21
-        StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:48:21: 48:22
-        StorageDead(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21
-        return;                          // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
-    }
-}
diff --git a/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir b/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir
deleted file mode 100644 (file)
index 5783822..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// MIR for `f_unit` before PreCodegen
-
-fn f_unit() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:17: +0:17
-    let mut _1: ();                      // in scope 0 at $DIR/lower_intrinsics.rs:+1:16: +1:18
-    scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics.rs:34:5: 34:19
-        debug t => _1;                   // in scope 1 at $DIR/lower_intrinsics.rs:44:22: 44:23
-        let _2: ();                      // in scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
-        let mut _3: ();                  // in scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16
-        scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics.rs:45:8: 45:32
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:16: +1:18
-        StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
-        StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16
-        _2 = f_zst::<()>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
-                                         // mir::Constant
-                                         // + span: $DIR/lower_intrinsics.rs:46:9: 46:14
-                                         // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value(<ZST>) }
-    }
-
-    bb1: {
-        StorageDead(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:46:16: 46:17
-        StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:46:17: 46:18
-        StorageDead(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:18: +1:19
-        return;                          // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
-    }
-}
index e6a2f6512f55af51df45fa5cc4b7a7ae8ece4190..4cbbc02c94333514a9091517956216b63945092f 100644 (file)
@@ -11,7 +11,7 @@
           _2 = move _1;                    // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31
 -         _0 = std::intrinsics::forget::<T>(move _2) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:24:5: 24:29
+-                                          // + span: $DIR/lower_intrinsics.rs:26:5: 26:29
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::<T>}, val: Value(<ZST>) }
 +         _0 = const ();                   // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32
index 1ab2f2a0a046828c32577c7ce3721661dfa879bd..d8cd5f59a3532fa0bcf496c6502ecae349ddbaa6 100644 (file)
@@ -13,7 +13,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:18
           _1 = std::intrinsics::size_of::<T>; // scope 0 at $DIR/lower_intrinsics.rs:+2:21: +2:51
                                            // mir::Constant
-                                           // + span: $DIR/lower_intrinsics.rs:62:21: 62:51
+                                           // + span: $DIR/lower_intrinsics.rs:37:21: 37:51
                                            // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(<ZST>) }
           StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14
           _2 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14
index eab51b65f1a19a6e868dbe6b4c24221a5d7b917e..195543d42bb5ba157b8a46c5d2b5fed5c1a96a13 100644 (file)
@@ -1,4 +1,6 @@
-// compile-flags: -Cpanic=abort
+// unit-test: LowerIntrinsics
+// ignore-wasm32 compiled with panic=abort by default
+
 #![feature(core_intrinsics)]
 #![crate_type = "lib"]
 
@@ -29,33 +31,6 @@ pub fn unreachable() -> ! {
     unsafe { core::intrinsics::unreachable() };
 }
 
-// EMIT_MIR lower_intrinsics.f_unit.PreCodegen.before.mir
-pub fn f_unit() {
-    f_dispatch(());
-}
-
-
-// EMIT_MIR lower_intrinsics.f_u64.PreCodegen.before.mir
-pub fn f_u64() {
-    f_dispatch(0u64);
-}
-
-#[inline(always)]
-pub fn f_dispatch<T>(t: T) {
-    if std::mem::size_of::<T>() == 0 {
-        f_zst(t);
-    } else {
-        f_non_zst(t);
-    }
-}
-
-#[inline(never)]
-pub fn f_zst<T>(_t: T) {
-}
-
-#[inline(never)]
-pub fn f_non_zst<T>(_t: T) {}
-
 // EMIT_MIR lower_intrinsics.non_const.LowerIntrinsics.diff
 pub fn non_const<T>() -> usize {
     // Check that lowering works with non-const operand as a func.
index 11b27976b551c9f171e11cbe7f9b0a0edb3ce07f..cf0ab73a5d4b1786b0eceb29f70859da81eef00d 100644 (file)
@@ -7,7 +7,7 @@
       bb0: {
 -         _0 = std::intrinsics::size_of::<T>() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:14:5: 14:35
+-                                          // + span: $DIR/lower_intrinsics.rs:16:5: 16:35
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(<ZST>) }
 +         _0 = SizeOf(T);                  // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37
index ac077e85b04f357a3ed5eab40a6182c2ec3e63b9..6f17d44516de194475d6f93250ee6b42443a22d5 100644 (file)
@@ -14,7 +14,7 @@
           StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
 -         _3 = std::intrinsics::unreachable(); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:29:14: 29:43
+-                                          // + span: $DIR/lower_intrinsics.rs:31:14: 31:43
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(<ZST>) }
 +         unreachable;                     // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
       }
index e0a5416b22b5fbe431578dadf506d8c7fab940c9..22ef75fd8046089c57c566a5705ac77d91166ac9 100644 (file)
@@ -32,7 +32,7 @@
           _5 = _2;                         // scope 0 at $DIR/lower_intrinsics.rs:+1:48: +1:49
 -         _3 = wrapping_add::<i32>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:7:14: 7:44
+-                                          // + span: $DIR/lower_intrinsics.rs:9:14: 9:44
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_add::<i32>}, val: Value(<ZST>) }
 +         _3 = Add(move _4, move _5);      // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50
@@ -48,7 +48,7 @@
           _8 = _2;                         // scope 1 at $DIR/lower_intrinsics.rs:+2:48: +2:49
 -         _6 = wrapping_sub::<i32>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:8:14: 8:44
+-                                          // + span: $DIR/lower_intrinsics.rs:10:14: 10:44
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_sub::<i32>}, val: Value(<ZST>) }
 +         _6 = Sub(move _7, move _8);      // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50
 +         goto -> bb2;                     // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50
@@ -64,7 +64,7 @@
           _11 = _2;                        // scope 2 at $DIR/lower_intrinsics.rs:+3:48: +3:49
 -         _9 = wrapping_mul::<i32>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50
 -                                          // mir::Constant
--                                          // + span: $DIR/lower_intrinsics.rs:9:14: 9:44
+-                                          // + span: $DIR/lower_intrinsics.rs:11:14: 11:44
 -                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_mul::<i32>}, val: Value(<ZST>) }
 +         _9 = Mul(move _10, move _11);    // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50
 +         goto -> bb3;                     // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50
diff --git a/src/test/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir b/src/test/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..8e18532
--- /dev/null
@@ -0,0 +1,32 @@
+// MIR for `f_u64` after PreCodegen
+
+fn f_u64() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics_e2e.rs:+0:16: +0:16
+    let mut _1: u64;                     // in scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21
+    scope 1 (inlined f_dispatch::<u64>) { // at $DIR/lower_intrinsics_e2e.rs:15:5: 15:21
+        debug t => _1;                   // in scope 1 at $DIR/lower_intrinsics_e2e.rs:19:22: 19:23
+        let _2: ();                      // in scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21
+        let mut _3: u64;                 // in scope 1 at $DIR/lower_intrinsics_e2e.rs:23:19: 23:20
+        scope 2 (inlined std::mem::size_of::<u64>) { // at $DIR/lower_intrinsics_e2e.rs:20:8: 20:32
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21
+        _1 = const 0_u64;                // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21
+        StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21
+        StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:19: 23:20
+        _3 = move _1;                    // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:19: 23:20
+        _2 = f_non_zst::<u64>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21
+                                         // mir::Constant
+                                         // + span: $DIR/lower_intrinsics_e2e.rs:23:9: 23:18
+                                         // + literal: Const { ty: fn(u64) {f_non_zst::<u64>}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        StorageDead(_3);                 // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:20: 23:21
+        StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:21: 23:22
+        StorageDead(_1);                 // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21
+        return;                          // scope 0 at $DIR/lower_intrinsics_e2e.rs:+2:2: +2:2
+    }
+}
diff --git a/src/test/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir b/src/test/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..a5b396c
--- /dev/null
@@ -0,0 +1,30 @@
+// MIR for `f_unit` after PreCodegen
+
+fn f_unit() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics_e2e.rs:+0:17: +0:17
+    let mut _1: ();                      // in scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:16: +1:18
+    scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics_e2e.rs:9:5: 9:19
+        debug t => _1;                   // in scope 1 at $DIR/lower_intrinsics_e2e.rs:19:22: 19:23
+        let _2: ();                      // in scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
+        let mut _3: ();                  // in scope 1 at $DIR/lower_intrinsics_e2e.rs:21:15: 21:16
+        scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics_e2e.rs:20:8: 20:32
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:16: +1:18
+        StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
+        StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:15: 21:16
+        _2 = f_zst::<()>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17
+                                         // mir::Constant
+                                         // + span: $DIR/lower_intrinsics_e2e.rs:21:9: 21:14
+                                         // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        StorageDead(_3);                 // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:16: 21:17
+        StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:17: 21:18
+        StorageDead(_1);                 // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:18: +1:19
+        return;                          // scope 0 at $DIR/lower_intrinsics_e2e.rs:+2:2: +2:2
+    }
+}
diff --git a/src/test/mir-opt/lower_intrinsics_e2e.rs b/src/test/mir-opt/lower_intrinsics_e2e.rs
new file mode 100644 (file)
index 0000000..872ef59
--- /dev/null
@@ -0,0 +1,32 @@
+// Checks that we do not have any branches in the MIR for the two tested functions.
+
+// compile-flags: -Cpanic=abort
+#![feature(core_intrinsics)]
+#![crate_type = "lib"]
+
+// EMIT_MIR lower_intrinsics_e2e.f_unit.PreCodegen.after.mir
+pub fn f_unit() {
+    f_dispatch(());
+}
+
+
+// EMIT_MIR lower_intrinsics_e2e.f_u64.PreCodegen.after.mir
+pub fn f_u64() {
+    f_dispatch(0u64);
+}
+
+#[inline(always)]
+pub fn f_dispatch<T>(t: T) {
+    if std::mem::size_of::<T>() == 0 {
+        f_zst(t);
+    } else {
+        f_non_zst(t);
+    }
+}
+
+#[inline(never)]
+pub fn f_zst<T>(_t: T) {
+}
+
+#[inline(never)]
+pub fn f_non_zst<T>(_t: T) {}
index 2005c10efa93bf6700cae844553ddd21159e9fef..f9eeb1ea5b96095be840b3afd1c193409cdb55ba 100644 (file)
@@ -41,7 +41,7 @@
 -         _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
--         nop;                             // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
+-         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
 -     }
 - 
@@ -54,7 +54,7 @@
 +         _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
--         nop;                             // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
+          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
 -     }
 - 
index 2005c10efa93bf6700cae844553ddd21159e9fef..f9eeb1ea5b96095be840b3afd1c193409cdb55ba 100644 (file)
@@ -41,7 +41,7 @@
 -         _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
--         nop;                             // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
+-         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
 -     }
 - 
@@ -54,7 +54,7 @@
 +         _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
--         nop;                             // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
+          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
 -     }
 - 
index b7862e5678f23598d3ba2afb8b144d73309b0cdb..0b40b3be8bdd41efd5e773ab32228a05b64f394c 100644 (file)
@@ -4,26 +4,51 @@
   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: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
-+     let mut _3: isize;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      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: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
--         switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--     }
-- 
--     bb1: {
+          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: {
-+         StorageLive(_3);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         _3 = move _2;                    // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         StorageDead(_3);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-         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
       }
   }
index b7862e5678f23598d3ba2afb8b144d73309b0cdb..0b40b3be8bdd41efd5e773ab32228a05b64f394c 100644 (file)
@@ -4,26 +4,51 @@
   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: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
-+     let mut _3: isize;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      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: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
--         switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--     }
-- 
--     bb1: {
+          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: {
-+         StorageLive(_3);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         _3 = move _2;                    // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         StorageDead(_3);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+-         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.PreCodegen.before.32bit.mir b/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.32bit.mir
deleted file mode 100644 (file)
index a36ec8d..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// MIR for `foo` before PreCodegen
-
-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
-
-    bb0: {
-        return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
-    }
-}
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.64bit.mir b/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.64bit.mir
deleted file mode 100644 (file)
index a36ec8d..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// MIR for `foo` before PreCodegen
-
-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
-
-    bb0: {
-        return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
-    }
-}
index 672c6b34e94b612b6c2c5d9f1d933aa56855df17..b8c7722cd3713c905b31331b98b0cc2623594660 100644 (file)
   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: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+     let mut _3: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+      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:+2:24: +2:28
-          _2 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
--         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+          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: {
-+         StorageLive(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+         _3 = move _2;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
--         _1 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
--         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
+-         _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: {
--         StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
--         _1 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
--         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
+-         _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: {
-+         _1 = Ne(_3, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-+         StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++         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 672c6b34e94b612b6c2c5d9f1d933aa56855df17..b8c7722cd3713c905b31331b98b0cc2623594660 100644 (file)
   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: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+     let mut _3: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+      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:+2:24: +2:28
-          _2 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
--         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
+          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: {
-+         StorageLive(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+         _3 = move _2;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
--         _1 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
--         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
+-         _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: {
--         StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
--         _1 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
--         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
+-         _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: {
-+         _1 = Ne(_3, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-+         StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
++         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 51be3884d48dd27b7a8f86d586a10bba0de5209b..c122b4c69d15a1a8f17411371eec649a526e8e05 100644 (file)
@@ -1,6 +1,7 @@
+// unit-test: MatchBranchSimplification
+
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
-// EMIT_MIR matches_reduce_branches.foo.PreCodegen.before.mir
 // EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
 // EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
 
index 78373be48b6854d5efdbb6cf5ef0c85881eb677d..2c748b02a8b76711fc937d7447016410a440644d 100644 (file)
@@ -1,3 +1,5 @@
+// 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 c3874d3b39d38c2d459f4a82460c1c74bb5b0181..f9ed1036f0060ef1680f5da15f96c57132cf4355 100644 (file)
@@ -16,15 +16,20 @@ fn main() -> () {
         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
-        _3 = Droppy(const 0_usize);      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-        _2 = Aligned(move _3);           // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
+        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
-        _1 = Packed(move _2);            // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
+        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
-        _5 = Droppy(const 0_usize);      // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-        _4 = Aligned(move _5);           // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
+        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
index c3874d3b39d38c2d459f4a82460c1c74bb5b0181..f9ed1036f0060ef1680f5da15f96c57132cf4355 100644 (file)
@@ -16,15 +16,20 @@ fn main() -> () {
         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
-        _3 = Droppy(const 0_usize);      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-        _2 = Aligned(move _3);           // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
+        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
-        _1 = Packed(move _2);            // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
+        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
-        _5 = Droppy(const 0_usize);      // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-        _4 = Aligned(move _5);           // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
+        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
index 05554174ae2c78aa6dd13da4083ee1f82ba18564..8ea61533d073d22b04e9b0ffd3f8e0586d5a0439 100644 (file)
@@ -128,7 +128,9 @@ fn array_casts() -> () {
         Retag(_35);                      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _18 = &(*_35);                   // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         Retag(_18);                      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        _13 = (move _14, move _18);      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        Deinit(_13);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        (_13.0: &usize) = move _14;      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        (_13.1: &usize) = move _18;      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         Retag(_13);                      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageDead(_18);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageDead(_14);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -154,7 +156,8 @@ fn array_casts() -> () {
 
     bb3: {
         StorageLive(_27);                // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        _27 = core::panicking::AssertKind::Eq; // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        Deinit(_27);                     // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        discriminant(_27) = 0;           // scope 7 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageLive(_28);                // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageLive(_29);                // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _29 = move _27;                  // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -171,7 +174,8 @@ fn array_casts() -> () {
         _32 = &(*_33);                   // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         Retag(_32);                      // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageLive(_34);                // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-        _34 = Option::<Arguments>::None; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        Deinit(_34);                     // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        discriminant(_34) = 0;           // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         Retag(_34);                      // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _28 = core::panicking::assert_failed::<usize, usize>(move _29, move _30, move _32, move _34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                          // mir::Constant
index 8802f3b295851a4aaa4d9e9bf34b968dbd6b61c9..e4a06554f1a6b2b17228d75ee140f62e4c584cfb 100644 (file)
@@ -62,7 +62,8 @@ fn main() -> () {
         StorageLive(_3);                 // scope 1 at $DIR/retag.rs:+3:13: +3:14
         StorageLive(_4);                 // scope 1 at $DIR/retag.rs:+3:17: +3:36
         StorageLive(_5);                 // scope 1 at $DIR/retag.rs:+3:17: +3:24
-        _5 = Test(const 0_i32);          // scope 1 at $DIR/retag.rs:+3:17: +3:24
+        Deinit(_5);                      // scope 1 at $DIR/retag.rs:+3:17: +3:24
+        (_5.0: i32) = const 0_i32;       // scope 1 at $DIR/retag.rs:+3:17: +3:24
         _4 = &_5;                        // scope 1 at $DIR/retag.rs:+3:17: +3:36
         Retag(_4);                       // scope 1 at $DIR/retag.rs:+3:17: +3:36
         StorageLive(_6);                 // scope 1 at $DIR/retag.rs:+3:29: +3:35
@@ -111,14 +112,7 @@ fn main() -> () {
         StorageDead(_2);                 // scope 1 at $DIR/retag.rs:+8:5: +8:6
         StorageLive(_13);                // scope 1 at $DIR/retag.rs:+11:9: +11:10
         StorageLive(_14);                // scope 1 at $DIR/retag.rs:+11:31: +14:6
-        _14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:+11:31: +14:6
-                                         // closure
-                                         // + def_id: DefId(0:14 ~ retag[4622]::main::{closure#0})
-                                         // + substs: [
-                                         //     i8,
-                                         //     for<'r> extern "rust-call" fn((&'r i32,)) -> &'r i32,
-                                         //     (),
-                                         // ]
+        Deinit(_14);                     // scope 1 at $DIR/retag.rs:+11:31: +14:6
         Retag(_14);                      // scope 1 at $DIR/retag.rs:+11:31: +14:6
         _13 = move _14 as for<'r> fn(&'r i32) -> &'r i32 (Pointer(ClosureFnPointer(Normal))); // scope 1 at $DIR/retag.rs:+11:31: +14:6
         StorageDead(_14);                // scope 1 at $DIR/retag.rs:+11:47: +11:48
@@ -142,7 +136,8 @@ fn main() -> () {
         StorageLive(_19);                // scope 7 at $DIR/retag.rs:+18:5: +18:24
         StorageLive(_20);                // scope 7 at $DIR/retag.rs:+18:5: +18:24
         StorageLive(_21);                // scope 7 at $DIR/retag.rs:+18:5: +18:12
-        _21 = Test(const 0_i32);         // scope 7 at $DIR/retag.rs:+18:5: +18:12
+        Deinit(_21);                     // scope 7 at $DIR/retag.rs:+18:5: +18:12
+        (_21.0: i32) = const 0_i32;      // scope 7 at $DIR/retag.rs:+18:5: +18:12
         _20 = &_21;                      // scope 7 at $DIR/retag.rs:+18:5: +18:24
         Retag(_20);                      // scope 7 at $DIR/retag.rs:+18:5: +18:24
         StorageLive(_22);                // scope 7 at $DIR/retag.rs:+18:21: +18:23
index b8c554d3ea6b02818cb2b26c179b21531e089f07..f25b3ce724be2db89b3f95fff98746d059aaaa80 100644 (file)
@@ -15,7 +15,7 @@
       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
+              scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:25:8: 25: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
@@ -34,7 +34,7 @@
           scope 4 {
           }
       }
-      scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+      scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:25:8: 25: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
index 5d82acf4d60905259414f168367a26ac7b818044..c809e5629cc152b4c02cd0b92efb6d138bc5c127 100644 (file)
@@ -4,8 +4,6 @@
 use std::ops::ControlFlow;
 
 // EMIT_MIR separate_const_switch.too_complex.SeparateConstSwitch.diff
-// EMIT_MIR separate_const_switch.too_complex.ConstProp.diff
-// EMIT_MIR separate_const_switch.too_complex.PreCodegen.after.mir
 fn too_complex(x: Result<i32, usize>) -> Option<i32> {
     // The pass should break the outer match into
     // two blocks that only have one parent each.
@@ -23,8 +21,6 @@ fn too_complex(x: Result<i32, usize>) -> Option<i32> {
 }
 
 // EMIT_MIR separate_const_switch.identity.SeparateConstSwitch.diff
-// EMIT_MIR separate_const_switch.identity.ConstProp.diff
-// EMIT_MIR separate_const_switch.identity.PreCodegen.after.mir
 fn identity(x: Result<i32, i32>) -> Result<i32, i32> {
     Ok(x?)
 }
index bedc86bbacb8c67fbe2d3b965e0e20a7fcad2ed5..cf6ff57aa96deef66017ce5bbde5f94fe420f23e 100644 (file)
@@ -4,6 +4,9 @@
 // compile-flags: -Zmir-opt-level=3
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
+// This pass is broken since deaggregation changed
+// ignore-test
+
 enum Src {
     Foo(u8),
     Bar,
index f7dcaa13449eac88c17898376922e5975859a142..c247872e2af46fb4bad904d0185a647a5559ea57 100644 (file)
@@ -6,6 +6,9 @@
 // EMIT_MIR simplify_arm.id_try.SimplifyArmIdentity.diff
 // EMIT_MIR simplify_arm.id_try.SimplifyBranchSame.diff
 
+// This pass is broken since deaggregation changed
+// ignore-test
+
 fn id(o: Option<u8>) -> Option<u8> {
     match o {
         Some(v) => Some(v),
index 84f57deccf7e0fa810dbe1039d5e2da91b1b9cc7..62a15df04b14429940d05a89f1711268caa43dc2 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Zunsound-mir-opts
+// unit-test: SimplifyLocals
 
 fn map(x: Option<Box<()>>) -> Option<Box<()>> {
     match x {
diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff
deleted file mode 100644 (file)
index 9c3ad4b..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-- // MIR for `id` before SimplifyArmIdentity
-+ // MIR for `id` after SimplifyArmIdentity
-  
-  fn id(_1: Option<u8>) -> Option<u8> {
-      debug o => _1;                       // in scope 0 at $DIR/simplify-arm.rs:+0:7: +0:8
-      let mut _0: std::option::Option<u8>; // return place in scope 0 at $DIR/simplify-arm.rs:+0:25: +0:35
-      let mut _2: isize;                   // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:16
-      let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15
-      let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:+2:25: +2:26
-      scope 1 {
-          debug v => _3;                   // in scope 1 at $DIR/simplify-arm.rs:+2:14: +2:15
-      }
-  
-      bb0: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          Deinit(_0);                      // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21
-          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21
-          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15
-          _3 = ((_1 as Some).0: u8);       // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15
-          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26
-          _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26
-          Deinit(_0);                      // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27
-          ((_0 as Some).0: u8) = move _4;  // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27
-          discriminant(_0) = 1;            // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27
-          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:+2:26: +2:27
-          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27
-          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27
-      }
-  
-      bb4: {
-          return;                          // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff
deleted file mode 100644 (file)
index 7b3a699..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-- // MIR for `id` before SimplifyBranchSame
-+ // MIR for `id` after SimplifyBranchSame
-  
-  fn id(_1: Option<u8>) -> Option<u8> {
-      debug o => _1;                       // in scope 0 at $DIR/simplify-arm.rs:+0:7: +0:8
-      let mut _0: std::option::Option<u8>; // return place in scope 0 at $DIR/simplify-arm.rs:+0:25: +0:35
-      let mut _2: isize;                   // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:16
-      let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15
-      let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:+2:25: +2:26
-      scope 1 {
-          debug v => _3;                   // in scope 1 at $DIR/simplify-arm.rs:+2:14: +2:15
-      }
-  
-      bb0: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          Deinit(_0);                      // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21
-          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21
-          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15
-          _3 = ((_1 as Some).0: u8);       // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15
-          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26
-          _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26
-          Deinit(_0);                      // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27
-          ((_0 as Some).0: u8) = move _4;  // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27
-          discriminant(_0) = 1;            // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27
-          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:+2:26: +2:27
-          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27
-          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27
-      }
-  
-      bb4: {
-          return;                          // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff
deleted file mode 100644 (file)
index 31d8453..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-- // MIR for `id_result` before SimplifyArmIdentity
-+ // MIR for `id_result` after SimplifyArmIdentity
-  
-  fn id_result(_1: Result<u8, i32>) -> Result<u8, i32> {
-      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:+0:14: +0:15
-      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:+0:37: +0:52
-      let mut _2: isize;                   // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:14
-      let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13
-      let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:+2:21: +2:22
-      let _5: i32;                         // in scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14
-      let mut _6: i32;                     // in scope 0 at $DIR/simplify-arm.rs:+3:23: +3:24
-      scope 1 {
-          debug x => _3;                   // in scope 1 at $DIR/simplify-arm.rs:+2:12: +2:13
-      }
-      scope 2 {
-          debug y => _5;                   // in scope 2 at $DIR/simplify-arm.rs:+3:13: +3:14
-      }
-  
-      bb0: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          StorageLive(_5);                 // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14
-          _5 = ((_1 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14
-          StorageLive(_6);                 // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24
-          _6 = _5;                         // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24
-          Deinit(_0);                      // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25
-          ((_0 as Err).0: i32) = move _6;  // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25
-          discriminant(_0) = 1;            // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25
-          StorageDead(_6);                 // scope 2 at $DIR/simplify-arm.rs:+3:24: +3:25
-          StorageDead(_5);                 // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25
-          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13
-          _3 = ((_1 as Ok).0: u8);         // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13
-          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22
-          _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22
-          Deinit(_0);                      // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23
-          ((_0 as Ok).0: u8) = move _4;    // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23
-          discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23
-          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:+2:22: +2:23
-          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23
-          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23
-      }
-  
-      bb4: {
-          return;                          // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff
deleted file mode 100644 (file)
index 3692ebf..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-- // MIR for `id_result` before SimplifyBranchSame
-+ // MIR for `id_result` after SimplifyBranchSame
-  
-  fn id_result(_1: Result<u8, i32>) -> Result<u8, i32> {
-      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:+0:14: +0:15
-      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:+0:37: +0:52
-      let mut _2: isize;                   // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:14
-      let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13
-      let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:+2:21: +2:22
-      let _5: i32;                         // in scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14
-      let mut _6: i32;                     // in scope 0 at $DIR/simplify-arm.rs:+3:23: +3:24
-      scope 1 {
-          debug x => _3;                   // in scope 1 at $DIR/simplify-arm.rs:+2:12: +2:13
-      }
-      scope 2 {
-          debug y => _5;                   // in scope 2 at $DIR/simplify-arm.rs:+3:13: +3:14
-      }
-  
-      bb0: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          StorageLive(_5);                 // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14
-          _5 = ((_1 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14
-          StorageLive(_6);                 // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24
-          _6 = _5;                         // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24
-          Deinit(_0);                      // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25
-          ((_0 as Err).0: i32) = move _6;  // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25
-          discriminant(_0) = 1;            // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25
-          StorageDead(_6);                 // scope 2 at $DIR/simplify-arm.rs:+3:24: +3:25
-          StorageDead(_5);                 // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25
-          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13
-          _3 = ((_1 as Ok).0: u8);         // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13
-          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22
-          _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22
-          Deinit(_0);                      // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23
-          ((_0 as Ok).0: u8) = move _4;    // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23
-          discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23
-          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:+2:22: +2:23
-          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23
-          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23
-      }
-  
-      bb4: {
-          return;                          // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff
deleted file mode 100644 (file)
index 118f5dd..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-- // MIR for `main` before SimplifyArmIdentity
-+ // MIR for `main` after SimplifyArmIdentity
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +0:11
-      let _1: Src;                         // in scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10
-      let mut _2: Dst;                     // in scope 0 at $DIR/simplify-arm-identity.rs:+2:18: +5:6
-      let mut _3: isize;                   // in scope 0 at $DIR/simplify-arm-identity.rs:+3:9: +3:20
-      let mut _5: u8;                      // in scope 0 at $DIR/simplify-arm-identity.rs:+3:33: +3:34
-      scope 1 {
-          debug e => _1;                   // in scope 1 at $DIR/simplify-arm-identity.rs:+1:9: +1:10
-          let _4: u8;                      // in scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
-          scope 2 {
-          }
-          scope 3 {
-              debug x => _4;               // in scope 3 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10
-          Deinit(_1);                      // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29
-          ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29
-          discriminant(_1) = 0;            // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29
-          StorageLive(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +5:6
-          _3 = const 0_isize;              // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25
-          goto -> bb3;                     // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +2:25
-      }
-  
-      bb1: {
-          Deinit(_2);                      // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
-          ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
-          discriminant(_2) = 0;            // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
-          goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
-      }
-  
-      bb2: {
-          unreachable;                     // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25
-      }
-  
-      bb3: {
-          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
-          _4 = ((_1 as Foo).0: u8);        // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
-          StorageLive(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34
-          _5 = _4;                         // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34
-          Deinit(_2);                      // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35
-          ((_2 as Foo).0: u8) = move _5;   // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35
-          discriminant(_2) = 0;            // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35
-          StorageDead(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:+3:34: +3:35
-          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35
-          goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35
-      }
-  
-      bb4: {
-          StorageDead(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:+5:6: +5:7
-          nop;                             // scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +6:2
-          StorageDead(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:+6:1: +6:2
-          return;                          // scope 0 at $DIR/simplify-arm-identity.rs:+6:2: +6:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff
deleted file mode 100644 (file)
index 118f5dd..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-- // MIR for `main` before SimplifyArmIdentity
-+ // MIR for `main` after SimplifyArmIdentity
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +0:11
-      let _1: Src;                         // in scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10
-      let mut _2: Dst;                     // in scope 0 at $DIR/simplify-arm-identity.rs:+2:18: +5:6
-      let mut _3: isize;                   // in scope 0 at $DIR/simplify-arm-identity.rs:+3:9: +3:20
-      let mut _5: u8;                      // in scope 0 at $DIR/simplify-arm-identity.rs:+3:33: +3:34
-      scope 1 {
-          debug e => _1;                   // in scope 1 at $DIR/simplify-arm-identity.rs:+1:9: +1:10
-          let _4: u8;                      // in scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
-          scope 2 {
-          }
-          scope 3 {
-              debug x => _4;               // in scope 3 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10
-          Deinit(_1);                      // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29
-          ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29
-          discriminant(_1) = 0;            // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29
-          StorageLive(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +5:6
-          _3 = const 0_isize;              // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25
-          goto -> bb3;                     // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +2:25
-      }
-  
-      bb1: {
-          Deinit(_2);                      // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
-          ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
-          discriminant(_2) = 0;            // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
-          goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32
-      }
-  
-      bb2: {
-          unreachable;                     // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25
-      }
-  
-      bb3: {
-          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
-          _4 = ((_1 as Foo).0: u8);        // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19
-          StorageLive(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34
-          _5 = _4;                         // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34
-          Deinit(_2);                      // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35
-          ((_2 as Foo).0: u8) = move _5;   // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35
-          discriminant(_2) = 0;            // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35
-          StorageDead(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:+3:34: +3:35
-          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35
-          goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35
-      }
-  
-      bb4: {
-          StorageDead(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:+5:6: +5:7
-          nop;                             // scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +6:2
-          StorageDead(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:+6:1: +6:2
-          return;                          // scope 0 at $DIR/simplify-arm-identity.rs:+6:2: +6:2
-      }
-  }
-  
index d8e0657c6ebc66908583970518b57cdbb9328851..51d26b08b2a1c69217fbf247a24d4bf5f43efa4d 100644 (file)
@@ -5,24 +5,32 @@
       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 _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 => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+          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: {
-          ((_0 as Some).0: std::boxed::Box<()>) = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+          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
       }
   
@@ -37,6 +45,7 @@
       }
   
       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 d8e0657c6ebc66908583970518b57cdbb9328851..51d26b08b2a1c69217fbf247a24d4bf5f43efa4d 100644 (file)
@@ -5,24 +5,32 @@
       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 _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 => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+          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: {
-          ((_0 as Some).0: std::boxed::Box<()>) = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+          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
       }
   
@@ -37,6 +45,7 @@
       }
   
       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_try.rs b/src/test/mir-opt/simplify_try.rs
deleted file mode 100644 (file)
index 15e351e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// compile-flags: -Zunsound-mir-opts
-// EMIT_MIR simplify_try.try_identity.SimplifyArmIdentity.diff
-// EMIT_MIR simplify_try.try_identity.SimplifyBranchSame.after.mir
-// EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir
-// EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff
-
-
-fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> {
-    r
-}
-
-fn from_error<T, E>(e: E) -> Result<T, E> {
-    Err(e)
-}
-
-// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure,
-// so the relevant desugar is copied inline in order to keep the test testing the same thing.
-// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR
-// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not.
-fn try_identity(x: Result<u32, i32>) -> Result<u32, i32> {
-    let y = match into_result(x) {
-        Err(e) => return from_error(From::from(e)),
-        Ok(v) => v,
-    };
-    Ok(y)
-}
-
-fn main() {
-    let _ = try_identity(Ok(0));
-}
diff --git a/src/test/mir-opt/try_identity_e2e.new.PreCodegen.after.mir b/src/test/mir-opt/try_identity_e2e.new.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..330929c
--- /dev/null
@@ -0,0 +1,96 @@
+// MIR for `new` after PreCodegen
+
+fn new(_1: Result<T, E>) -> Result<T, E> {
+    debug x => _1;                       // in scope 0 at $DIR/try_identity_e2e.rs:+0:14: +0:15
+    let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46
+    let mut _2: T;                       // in scope 0 at $DIR/try_identity_e2e.rs:+2:9: +10:10
+    let mut _3: std::ops::ControlFlow<E, T>; // in scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
+    let mut _4: isize;                   // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:22
+    let _5: T;                           // in scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
+    let mut _6: T;                       // in scope 0 at $DIR/try_identity_e2e.rs:+4:48: +4:49
+    let _7: E;                           // in scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
+    let mut _8: E;                       // in scope 0 at $DIR/try_identity_e2e.rs:+5:46: +5:47
+    let mut _9: isize;                   // in scope 0 at $DIR/try_identity_e2e.rs:+8:13: +8:37
+    let _10: T;                          // in scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
+    let _11: E;                          // in scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
+    let mut _12: E;                      // in scope 0 at $DIR/try_identity_e2e.rs:+9:49: +9:50
+    scope 1 {
+        debug v => _5;                   // in scope 1 at $DIR/try_identity_e2e.rs:+4:20: +4:21
+    }
+    scope 2 {
+        debug e => _7;                   // in scope 2 at $DIR/try_identity_e2e.rs:+5:21: +5:22
+    }
+    scope 3 {
+        debug v => _10;                  // in scope 3 at $DIR/try_identity_e2e.rs:+8:35: +8:36
+    }
+    scope 4 {
+        debug e => _11;                  // in scope 4 at $DIR/try_identity_e2e.rs:+9:32: +9:33
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +10:10
+        StorageLive(_3);                 // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
+        _4 = discriminant(_1);           // scope 0 at $DIR/try_identity_e2e.rs:+3:19: +3:20
+        switchInt(move _4) -> [0_isize: bb2, 1_isize: bb1, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:20
+    }
+
+    bb1: {
+        StorageLive(_7);                 // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
+        _7 = move ((_1 as Err).0: E);    // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22
+        StorageLive(_8);                 // scope 2 at $DIR/try_identity_e2e.rs:+5:46: +5:47
+        _8 = move _7;                    // scope 2 at $DIR/try_identity_e2e.rs:+5:46: +5:47
+        Deinit(_3);                      // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
+        ((_3 as Break).0: E) = move _8;  // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
+        discriminant(_3) = 1;            // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48
+        StorageDead(_8);                 // scope 2 at $DIR/try_identity_e2e.rs:+5:47: +5:48
+        StorageDead(_7);                 // scope 0 at $DIR/try_identity_e2e.rs:+5:47: +5:48
+        _9 = discriminant(_3);           // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
+        switchInt(move _9) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10
+    }
+
+    bb2: {
+        StorageLive(_5);                 // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
+        _5 = move ((_1 as Ok).0: T);     // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21
+        StorageLive(_6);                 // scope 1 at $DIR/try_identity_e2e.rs:+4:48: +4:49
+        _6 = move _5;                    // scope 1 at $DIR/try_identity_e2e.rs:+4:48: +4:49
+        Deinit(_3);                      // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
+        ((_3 as Continue).0: T) = move _6; // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
+        discriminant(_3) = 0;            // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50
+        StorageDead(_6);                 // scope 1 at $DIR/try_identity_e2e.rs:+4:49: +4:50
+        StorageDead(_5);                 // scope 0 at $DIR/try_identity_e2e.rs:+4:49: +4:50
+        _9 = discriminant(_3);           // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
+        switchInt(move _9) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10
+    }
+
+    bb3: {
+        StorageLive(_11);                // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
+        _11 = move ((_3 as Break).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33
+        StorageLive(_12);                // scope 4 at $DIR/try_identity_e2e.rs:+9:49: +9:50
+        _12 = move _11;                  // scope 4 at $DIR/try_identity_e2e.rs:+9:49: +9:50
+        Deinit(_0);                      // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
+        ((_0 as Err).0: E) = move _12;   // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
+        discriminant(_0) = 1;            // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
+        StorageDead(_12);                // scope 4 at $DIR/try_identity_e2e.rs:+9:50: +9:51
+        StorageDead(_11);                // scope 0 at $DIR/try_identity_e2e.rs:+9:50: +9:51
+        StorageDead(_2);                 // scope 0 at $DIR/try_identity_e2e.rs:+11:5: +11:6
+        StorageDead(_3);                 // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
+        return;                          // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
+    }
+
+    bb4: {
+        unreachable;                     // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10
+    }
+
+    bb5: {
+        StorageLive(_10);                // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
+        _10 = move ((_3 as Continue).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36
+        _2 = move _10;                   // scope 3 at $DIR/try_identity_e2e.rs:+8:41: +8:42
+        StorageDead(_10);                // scope 0 at $DIR/try_identity_e2e.rs:+8:41: +8:42
+        Deinit(_0);                      // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
+        ((_0 as Ok).0: T) = move _2;     // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
+        discriminant(_0) = 0;            // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
+        StorageDead(_2);                 // scope 0 at $DIR/try_identity_e2e.rs:+11:5: +11:6
+        StorageDead(_3);                 // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
+        return;                          // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
+    }
+}
diff --git a/src/test/mir-opt/try_identity_e2e.old.PreCodegen.after.mir b/src/test/mir-opt/try_identity_e2e.old.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..18d3e0f
--- /dev/null
@@ -0,0 +1,53 @@
+// MIR for `old` after PreCodegen
+
+fn old(_1: Result<T, E>) -> Result<T, E> {
+    debug x => _1;                       // in scope 0 at $DIR/try_identity_e2e.rs:+0:14: +0:15
+    let mut _0: std::result::Result<T, E>; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46
+    let mut _2: T;                       // in scope 0 at $DIR/try_identity_e2e.rs:+2:9: +5:10
+    let mut _3: isize;                   // in scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:18
+    let _4: T;                           // in scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
+    let _5: E;                           // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
+    let mut _6: E;                       // in scope 0 at $DIR/try_identity_e2e.rs:+4:34: +4:35
+    scope 1 {
+        debug v => _4;                   // in scope 1 at $DIR/try_identity_e2e.rs:+3:16: +3:17
+    }
+    scope 2 {
+        debug e => _5;                   // in scope 2 at $DIR/try_identity_e2e.rs:+4:17: +4:18
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +5:10
+        _3 = discriminant(_1);           // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +2:16
+        switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +2:16
+    }
+
+    bb1: {
+        StorageLive(_5);                 // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
+        _5 = move ((_1 as Err).0: E);    // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18
+        StorageLive(_6);                 // scope 2 at $DIR/try_identity_e2e.rs:+4:34: +4:35
+        _6 = move _5;                    // scope 2 at $DIR/try_identity_e2e.rs:+4:34: +4:35
+        Deinit(_0);                      // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
+        ((_0 as Err).0: E) = move _6;    // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
+        discriminant(_0) = 1;            // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
+        StorageDead(_6);                 // scope 2 at $DIR/try_identity_e2e.rs:+4:35: +4:36
+        StorageDead(_5);                 // scope 0 at $DIR/try_identity_e2e.rs:+4:35: +4:36
+        StorageDead(_2);                 // scope 0 at $DIR/try_identity_e2e.rs:+6:5: +6:6
+        return;                          // scope 0 at $DIR/try_identity_e2e.rs:+7:1: +7:2
+    }
+
+    bb2: {
+        unreachable;                     // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +2:16
+    }
+
+    bb3: {
+        StorageLive(_4);                 // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
+        _4 = move ((_1 as Ok).0: T);     // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17
+        _2 = move _4;                    // scope 1 at $DIR/try_identity_e2e.rs:+3:22: +3:23
+        StorageDead(_4);                 // scope 0 at $DIR/try_identity_e2e.rs:+3:22: +3:23
+        Deinit(_0);                      // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
+        ((_0 as Ok).0: T) = move _2;     // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
+        discriminant(_0) = 0;            // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
+        StorageDead(_2);                 // scope 0 at $DIR/try_identity_e2e.rs:+6:5: +6:6
+        return;                          // scope 0 at $DIR/try_identity_e2e.rs:+7:1: +7:2
+    }
+}
diff --git a/src/test/mir-opt/try_identity_e2e.rs b/src/test/mir-opt/try_identity_e2e.rs
new file mode 100644 (file)
index 0000000..00cb80f
--- /dev/null
@@ -0,0 +1,34 @@
+// Track the status of MIR optimizations simplifying `Ok(res?)` for both the old and new desugarings
+// of that syntax.
+
+use std::ops::ControlFlow;
+
+// EMIT_MIR try_identity_e2e.new.PreCodegen.after.mir
+fn new<T, E>(x: Result<T, E>) -> Result<T, E> {
+    Ok(
+        match {
+            match x {
+                Ok(v) => ControlFlow::Continue(v),
+                Err(e) => ControlFlow::Break(e),
+            }
+        } {
+            ControlFlow::Continue(v) => v,
+            ControlFlow::Break(e) => return Err(e),
+        }
+    )
+}
+
+// EMIT_MIR try_identity_e2e.old.PreCodegen.after.mir
+fn old<T, E>(x: Result<T, E>) -> Result<T, E> {
+    Ok(
+        match x {
+            Ok(v) => v,
+            Err(e) => return Err(e),
+        }
+    )
+}
+
+fn main() {
+    let _ = new::<(), ()>(Ok(()));
+    let _ = old::<(), ()>(Ok(()));
+}
index 51dc6b53a4504cfdb9f2674394ae4c23f5f71901..f42ea620fb9d13313b4ab3e1e22bc84bccf3b5cb 100644 (file)
@@ -19,7 +19,7 @@ all:
        # Dump all the symbols from the staticlib into `syms`
        "$(LLVM_BIN_DIR)"/llvm-objdump -t $(TMPDIR)/libdownstream.a > $(TMPDIR)/syms
        # Count the global instances of `issue64153_test_function`. There'll be 2
-       # if the `upstream` object file got erronously included twice.
+       # if the `upstream` object file got erroneously included twice.
        # The line we are testing for with the regex looks something like:
        # 0000000000000000 g     F .text.issue64153_test_function       00000023 issue64153_test_function
        grep -c -e "[[:space:]]g[[:space:]]*F[[:space:]].*issue64153_test_function" $(TMPDIR)/syms > $(TMPDIR)/count
index cac881ece1296ef5b502e5f2c85ff3736d427f88..6fc2a6bada9a05d3028fdaa863d67a5773f52711 100644 (file)
@@ -60,7 +60,7 @@ endif
 # for now, but it is effectively ignored for all tests that don't include this file anyway.
 #
 # (Note that it's also possible the `_counters.<test>.txt` and `<test>.json` files (if generated)
-# may order results from multiple files inconsistently, which might also have to be accomodated
+# may order results from multiple files inconsistently, which might also have to be accommodated
 # if and when we allow `llvm-cov` to produce results for multiple files. Note, the path separators
 # appear to be normalized to `/` in those files, thankfully.)
 LLVM_COV_IGNORE_FILES=\
@@ -157,7 +157,7 @@ else
        # `// ignore-llvm-cov-show-diffs` anymore. This directive exists to work around a limitation
        # with `llvm-cov show`. When reporting coverage for multiple instantiations of a generic function,
        # with different type substitutions, `llvm-cov show` prints these in a non-deterministic order,
-       # breaking the `diff` comparision.
+       # breaking the `diff` comparison.
        #
        # A partial workaround is implemented below, with `diff --ignore-matching-lines=RE`
        # to ignore each line prefixing each generic instantiation coverage code region.
index 2f69adbd81c51eb884cb9ca25e4ac269a016b146..87ccb6c43eab3e344d29ee59325d1793a937fe44 100644 (file)
@@ -55,7 +55,7 @@
    53|      1|            1 // This line appears covered, but the 1-character expression span covering the `1`
                           ^0
    54|      1|              // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because
-   55|      1|              // `fn j()` executes the open brace for the funciton body, followed by the function's
+   55|      1|              // `fn j()` executes the open brace for the function body, followed by the function's
    56|      1|              // first executable statement, `match x`. Inner function declarations are not
    57|      1|              // "visible" to the MIR for `j()`, so the code region counts all lines between the
    58|      1|              // open brace and the first statement as executed, which is, in a sense, true.
index a6e387747068abedd73e2360cdcad9d4e6e598ec..efd9e62d64e1d3453f00a3f3a48700c52269e225 100644 (file)
@@ -52,7 +52,7 @@ fn c(x: u8) -> u8 {
         if x == 8 {
             1 // This line appears covered, but the 1-character expression span covering the `1`
               // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because
-              // `fn j()` executes the open brace for the funciton body, followed by the function's
+              // `fn j()` executes the open brace for the function body, followed by the function's
               // first executable statement, `match x`. Inner function declarations are not
               // "visible" to the MIR for `j()`, so the code region counts all lines between the
               // open brace and the first statement as executed, which is, in a sense, true.
index 54645e9e257c97d6d95ef979b8384ab3c96cde2c..944343df6e587fea2b6aefb2f4af315ec40ac893 100644 (file)
@@ -45,7 +45,7 @@ check cc_plus_one_cxx cc_plus_one_cxx.checks
 check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks
 check cc_plus_one_asm cc_plus_one_asm.checks \
   || echo "warning: the cc crate forwards assembly files to the CC compiler." \
-           "Clang uses its own intergrated assembler, which does not include the LVI passes."
+           "Clang uses its own integrated assembler, which does not include the LVI passes."
 
 check cmake_plus_one_c cmake_plus_one_c.checks
 check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks
index c35a86ccd1cab0cf0cc5b989542681d3c189b1a4..1c64974e9162710a3aad4b4790c89a01aa680f6c 100644 (file)
@@ -92,7 +92,7 @@ reload:
 assert-css: (
     ".search-input",
     {
-        "border-color": "rgb(240, 240, 240)",
+        "border-color": "rgb(224, 224, 224)",
         "background-color": "rgb(240, 240, 240)",
         "color": "rgb(17, 17, 17)",
     },
index 6903e1a1bf5c63e941975c068295961b929e2036..fd61c4f43d18139e9b5449cde0f10fec82d9ac34 100644 (file)
@@ -3,7 +3,7 @@ goto: file://|DOC_PATH|/test_docs/index.html
 local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"}
 reload:
 
-assert-css: (".search-input", {"border-color": "rgb(240, 240, 240)"})
+assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"})
 click: ".search-input"
 assert-css: (".search-input", {"border-color": "rgb(0, 141, 253)"})
 
index 9a49ae2c6b853661f83c5007943dabda13d9ccb4..5e328133e62a19db5ba5cc327a4bff0b5e9f46f6 100644 (file)
@@ -29,6 +29,23 @@ assert-css: (
     {"color": "rgb(120, 135, 151)"},
 )
 
+// Checking the `<a>` container.
+assert-css: (
+    "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a",
+    {"color": "rgb(0, 150, 207)", "background-color": "rgba(0, 0, 0, 0)"},
+)
+
+// Checking color and background on hover.
+move-cursor-to: "//*[@class='desc']//*[text()='Just a normal struct.']"
+assert-css: (
+    "//*[@class='result-name']/*[text()='test_docs::']",
+    {"color": "rgb(255, 255, 255)"},
+)
+assert-css: (
+    "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a",
+    {"color": "rgb(255, 255, 255)", "background-color": "rgb(60, 60, 60)"},
+)
+
 // Dark theme
 local-storage: {
     "rustdoc-theme": "dark",
@@ -54,6 +71,23 @@ assert-css: (
     {"color": "rgb(221, 221, 221)"},
 )
 
+// Checking the `<a>` container.
+assert-css: (
+    "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a",
+    {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
+)
+
+// Checking color and background on hover.
+move-cursor-to: "//*[@class='desc']//*[text()='Just a normal struct.']"
+assert-css: (
+    "//*[@class='result-name']/*[text()='test_docs::']",
+    {"color": "rgb(221, 221, 221)"},
+)
+assert-css: (
+    "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a",
+    {"color": "rgb(221, 221, 221)", "background-color": "rgb(119, 119, 119)"},
+)
+
 // Light theme
 local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
 reload:
@@ -75,6 +109,23 @@ assert-css: (
     {"color": "rgb(0, 0, 0)"},
 )
 
+// Checking the `<a>` container.
+assert-css: (
+    "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a",
+    {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
+)
+
+// Checking color and background on hover.
+move-cursor-to: "//*[@class='desc']//*[text()='Just a normal struct.']"
+assert-css: (
+    "//*[@class='result-name']/*[text()='test_docs::']",
+    {"color": "rgb(0, 0, 0)"},
+)
+assert-css: (
+    "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a",
+    {"color": "rgb(0, 0, 0)", "background-color": "rgb(221, 221, 221)"},
+)
+
 // Check the alias more specifically in the dark theme.
 goto: file://|DOC_PATH|/test_docs/index.html
 // We set the theme so we're sure that the correct values will be used, whatever the computer
index 87f91be3ac82cec26d87785a1afe2debd038aed8..7f3172878bfb5f74325ee5b1a0f75db7143c30d1 100644 (file)
@@ -143,3 +143,30 @@ pub trait SimpleTrait {}
 /// Some docs.
 #[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "emscripten", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
 impl SimpleTrait for LongItemInfo2 {}
+
+pub struct WhereWhitespace<T>;
+
+impl<T> WhereWhitespace<T> {
+    pub fn new<F>(f: F) -> Self
+    where
+        F: FnMut() -> i32,
+    {}
+}
+
+impl<K, T> Whitespace<&K> for WhereWhitespace<T>
+where
+    K: std::fmt::Debug,
+{
+    type Output = WhereWhitespace<T>;
+    fn index(&self, _key: &K) -> &Self::Output {
+        self
+    }
+}
+
+pub trait Whitespace<Idx>
+where
+    Idx: ?Sized,
+{
+    type Output;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
index 22212a31728dca6dc06524be2c9cc60e216a10fc..85e03c45e700e985bebd41ecd88898398fc70a30 100644 (file)
@@ -32,6 +32,6 @@ assert-property: (".item-decl pre", {"scrollWidth": "950"})
 size: (600, 600)
 goto: file://|DOC_PATH|/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html
 // It shouldn't have an overflow in the topbar either.
-assert-property: (".mobile-topbar .location", {"scrollWidth": "492"})
-assert-property: (".mobile-topbar .location", {"clientWidth": "492"})
+assert-property: (".mobile-topbar .location", {"scrollWidth": "502"})
+assert-property: (".mobile-topbar .location", {"clientWidth": "502"})
 assert-css: (".mobile-topbar .location", {"overflow-x": "hidden"})
diff --git a/src/test/rustdoc-gui/where-whitespace.goml b/src/test/rustdoc-gui/where-whitespace.goml
new file mode 100644 (file)
index 0000000..1a3ff1f
--- /dev/null
@@ -0,0 +1,27 @@
+// This test ensures that the where conditions are correctly displayed.
+goto: file://|DOC_PATH|/lib2/trait.Whitespace.html
+show-text: true
+// First, we check in the trait definition if the where clause is "on its own" (not on the same
+// line than "pub trait Whitespace<Idx>").
+compare-elements-position-false: (".item-decl code", ".where.fmt-newline", ("y"))
+// And that the code following it isn't on the same line either.
+compare-elements-position-false: (".item-decl .fnname", ".where.fmt-newline", ("y"))
+
+goto: file://|DOC_PATH|/lib2/struct.WhereWhitespace.html
+// We make the screen a bit wider to ensure that the trait impl is on one line.
+size: (915, 915)
+
+compare-elements-position-false: ("#method\.new .fnname", "#method\.new .where.fmt-newline", ("y"))
+// We ensure that both the trait name and the struct name are on the same line in
+// "impl<K, T> Whitespace<&K> for WhereWhitespace<T>".
+compare-elements-position: (
+    "#trait-implementations-list .impl h3 .trait",
+    "#trait-implementations-list .impl h3 .struct",
+    ("y"),
+)
+// And we now check that the where condition isn't on the same line.
+compare-elements-position-false: (
+    "#trait-implementations-list .impl h3 .trait",
+    "#trait-implementations-list .impl h3 .where.fmt-newline",
+    ("y"),
+)
diff --git a/src/test/rustdoc-json/fns/async_return.rs b/src/test/rustdoc-json/fns/async_return.rs
new file mode 100644 (file)
index 0000000..b89781c
--- /dev/null
@@ -0,0 +1,36 @@
+// edition:2021
+// ignore-tidy-linelength
+
+// Regression test for <https://github.com/rust-lang/rust/issues/101199>
+
+use std::future::Future;
+
+// @is "$.index[*][?(@.name=='get_int')].inner.decl.output" '{"inner": "i32", "kind": "primitive"}'
+// @is "$.index[*][?(@.name=='get_int')].inner.header.async" false
+pub fn get_int() -> i32 {
+    42
+}
+
+// @is "$.index[*][?(@.name=='get_int_async')].inner.decl.output" '{"inner": "i32", "kind": "primitive"}'
+// @is "$.index[*][?(@.name=='get_int_async')].inner.header.async" true
+pub async fn get_int_async() -> i32 {
+    42
+}
+
+// @is "$.index[*][?(@.name=='get_int_future')].inner.decl.output.kind" '"impl_trait"'
+// @is "$.index[*][?(@.name=='get_int_future')].inner.decl.output.inner[0].trait_bound.trait.name" '"Future"'
+// @is "$.index[*][?(@.name=='get_int_future')].inner.decl.output.inner[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"'
+// @is "$.index[*][?(@.name=='get_int_future')].inner.decl.output.inner[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type" '{"inner": "i32", "kind": "primitive"}'
+// @is "$.index[*][?(@.name=='get_int_future')].inner.header.async" false
+pub fn get_int_future() -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+// @is "$.index[*][?(@.name=='get_int_future_async')].inner.decl.output.kind" '"impl_trait"'
+// @is "$.index[*][?(@.name=='get_int_future_async')].inner.decl.output.inner[0].trait_bound.trait.name" '"Future"'
+// @is "$.index[*][?(@.name=='get_int_future_async')].inner.decl.output.inner[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"'
+// @is "$.index[*][?(@.name=='get_int_future_async')].inner.decl.output.inner[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type" '{"inner": "i32", "kind": "primitive"}'
+// @is "$.index[*][?(@.name=='get_int_future_async')].inner.header.async" true
+pub async fn get_int_future_async() -> impl Future<Output = i32> {
+    async { 42 }
+}
diff --git a/src/test/rustdoc-json/reexport/glob_collision.rs b/src/test/rustdoc-json/reexport/glob_collision.rs
new file mode 100644 (file)
index 0000000..f91144d
--- /dev/null
@@ -0,0 +1,28 @@
+// Regression test for https://github.com/rust-lang/rust/issues/100973
+
+#![feature(no_core)]
+#![no_core]
+
+// @set m1 = "$.index[*][?(@.name == 'm1' && @.kind == 'module')].id"
+// @is "$.index[*][?(@.name == 'm1' && @.kind == 'module')].inner.items" []
+// @is "$.index[*][?(@.name == 'm1' && @.kind == 'module')].inner.is_stripped" true
+mod m1 {
+    pub fn f() {}
+}
+// @set m2 = "$.index[*][?(@.name == 'm2' && @.kind == 'module')].id"
+// @is "$.index[*][?(@.name == 'm2' && @.kind == 'module')].inner.items" []
+// @is "$.index[*][?(@.name == 'm2' && @.kind == 'module')].inner.is_stripped" true
+mod m2 {
+    pub fn f(_: u8) {}
+}
+
+// @set m1_use = "$.index[*][?(@.inner.name=='m1')].id"
+// @is "$.index[*][?(@.inner.name=='m1')].inner.id" $m1
+// @is "$.index[*][?(@.inner.name=='m1')].inner.glob" true
+pub use m1::*;
+// @set m2_use = "$.index[*][?(@.inner.name=='m2')].id"
+// @is "$.index[*][?(@.inner.name=='m2')].inner.id" $m2
+// @is "$.index[*][?(@.inner.name=='m2')].inner.glob" true
+pub use m2::*;
+
+// @ismany "$.index[*][?(@.inner.is_crate==true)].inner.items[*]" $m1_use $m2_use
diff --git a/src/test/rustdoc-json/reexport/glob_empty_mod.rs b/src/test/rustdoc-json/reexport/glob_empty_mod.rs
new file mode 100644 (file)
index 0000000..da68228
--- /dev/null
@@ -0,0 +1,8 @@
+// Regression test for https://github.com/rust-lang/rust/issues/100973
+
+// @is "$.index[*][?(@.name=='m1' && @.kind == 'module')].inner.is_stripped" true
+// @set m1 = "$.index[*][?(@.name=='m1')].id"
+mod m1 {}
+
+// @is "$.index[*][?(@.inner.name=='m1' && @.kind=='import')].inner.id" $m1
+pub use m1::*;
index 68cb694f4994913b564e1d2a0af795b506a80aa2..7b97ebf2129eb91ce0c7908f611e424555f1c0d0 100644 (file)
@@ -1,8 +1,7 @@
 #![feature(no_core)]
 #![no_core]
 
-// @is "$.index[*][?(@.name=='foo')].kind" \"module\"
-// @is "$.index[*][?(@.name=='foo')].inner.is_stripped" "true"
+// @!has "$.index[*][?(@.name=='foo')]"
 mod foo {
     // @has "$.index[*][?(@.name=='Foo')]"
     pub struct Foo;
diff --git a/src/test/rustdoc-json/reexport/mod_not_included.rs b/src/test/rustdoc-json/reexport/mod_not_included.rs
new file mode 100644 (file)
index 0000000..7b7600e
--- /dev/null
@@ -0,0 +1,14 @@
+// Regression test for https://github.com/rust-lang/rust/issues/101103
+
+#![feature(no_core)]
+#![no_core]
+
+mod m1 {
+    pub fn x() {}
+}
+
+pub use m1::x;
+
+// @has "$.index[*][?(@.name=='x' && @.kind=='function')]"
+// @has "$.index[*][?(@.kind=='import' && @.inner.name=='x')].inner.source" '"m1::x"'
+// @!has "$.index[*][?(@.name=='m1')]"
index ec78b06d09ac873e5c113199244ef9bf0c29d2ae..9858538a9d046493b7926fc34c15303e47d115e3 100644 (file)
@@ -6,8 +6,7 @@
 #![no_core]
 #![feature(no_core)]
 
-// @is "$.index[*][?(@.name=='style')].kind" \"module\"
-// @is "$.index[*][?(@.name=='style')].inner.is_stripped" "true"
+// @!has "$.index[*][?(@.name=='style')]"
 mod style {
     // @set color_struct_id = "$.index[*][?(@.kind=='struct' && @.name=='Color')].id"
     pub struct Color;
index 1537f834481f49f49287c5a339c63ce8248464de..8fd850f9b1370ad7e00a78f59ef9b46ac2063f46 100644 (file)
@@ -3,8 +3,7 @@
 #![no_core]
 #![feature(no_core)]
 
-// @is "$.index[*][?(@.name=='inner')].kind" \"module\"
-// @is "$.index[*][?(@.name=='inner')].inner.is_stripped" "true"
+// @!has "$.index[*][?(@.kind=='inner')]"
 mod inner {
     // @has "$.index[*][?(@.name=='Public')]"
     pub struct Public;
index 82348b383c363b741d7007a0a6d39227c0fce5af..d058ce0598d43e557d1ecd998365a4252642e636 100644 (file)
@@ -2,16 +2,15 @@
 #![no_core]
 #![feature(no_core)]
 
-// @is "$.index[*][?(@.name=='inner')].kind" \"module\"
-// @is "$.index[*][?(@.name=='inner')].inner.is_stripped" "true"
+// @!has "$.index[*][?(@.name=='inner')]"
 mod inner {
     // @set pub_id = "$.index[*][?(@.name=='Public')].id"
     pub struct Public;
 }
 
 // @is "$.index[*][?(@.kind=='import')].inner.name" \"Public\"
+// @is "$.index[*][?(@.kind=='import')].inner.id" $pub_id
 // @set use_id = "$.index[*][?(@.kind=='import')].id"
 pub use inner::Public;
 
-// @ismany "$.index[*][?(@.name=='inner')].inner.items[*]" $pub_id
 // @ismany "$.index[*][?(@.name=='simple_private')].inner.items[*]" $use_id
index 33e95ce69d05947a34fdcd55d13f336bc5255b14..d2664b49e9c29209897d6216d3480e2756820684 100644 (file)
@@ -12,7 +12,7 @@ mod pub_inner_unreachable {
     pub fn pub_inner_1() {}
 }
 
-// @has "$.index[*][?(@.name=='pub_inner_reachable')]"
+// @!has "$.index[*][?(@.name=='pub_inner_reachable')]"
 mod pub_inner_reachable {
     // @has "$.index[*][?(@.name=='pub_inner_2')]"
     pub fn pub_inner_2() {}
index f48cad373cdedc9b083305b0cd552df1bbd0f8e7..14ffac1e1dce6c40ab9326f07ca9003a79be52a4 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// Regresion test for <https://github.com/rust-lang/rust/issues/79459>.
+// Regression test for <https://github.com/rust-lang/rust/issues/79459>.
 pub trait Query {}
 
 pub trait AsQuery {
index 352a8e646bb49fe76e9fc548a87be15378b2dd20..87d2f29e26055461a284f5b581469cc2e421e399 100644 (file)
@@ -31,12 +31,12 @@ impl Trait<{1 + 2}> for u8 {}
 impl<const N: usize> Trait<N> for [u8; N] {}
 
 // @has foo/struct.Foo.html '//pre[@class="rust struct"]' \
-//      'pub struct Foo<const N: usize> where u8: Trait<N>'
+//      'pub struct Foo<const N: usize>where u8: Trait<N>'
 pub struct Foo<const N: usize> where u8: Trait<N>;
 // @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
 pub struct Bar<T, const N: usize>([T; N]);
 
-// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
+// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M>where u8: Trait<M>'
 impl<const M: usize> Foo<M> where u8: Trait<M> {
     // @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
     pub const FOO_ASSOC: usize = M + 13;
@@ -50,14 +50,14 @@ pub fn hey<const N: usize>(&self) -> Bar<u8, N> {
 // @has foo/struct.Bar.html '//*[@id="impl-Bar%3Cu8%2C%20M%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>'
 impl<const M: usize> Bar<u8, M> {
     // @has - '//*[@id="method.hey"]' \
-    //      'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>'
+    //      'pub fn hey<const N: usize>(&self) -> Foo<N>where u8: Trait<N>'
     pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N> {
         Foo
     }
 }
 
 // @has foo/fn.test.html '//pre[@class="rust fn"]' \
-//      'pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N>'
+//      'pub fn test<const N: usize>() -> impl Trait<N>where u8: Trait<N>'
 pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N> {
     2u8
 }
diff --git a/src/test/rustdoc/doc_auto_cfg_nested_impl.rs b/src/test/rustdoc/doc_auto_cfg_nested_impl.rs
new file mode 100644 (file)
index 0000000..4d73e0d
--- /dev/null
@@ -0,0 +1,24 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/101129>.
+
+#![feature(doc_auto_cfg)]
+#![crate_type = "lib"]
+#![crate_name = "foo"]
+
+pub struct S;
+pub trait MyTrait1 {}
+pub trait MyTrait2 {}
+
+// @has foo/struct.S.html
+// @has - '//*[@id="impl-MyTrait1-for-S"]//*[@class="stab portability"]' \
+//        'Available on non-crate feature coolstuff only.'
+#[cfg(not(feature = "coolstuff"))]
+impl MyTrait1 for S {}
+
+#[cfg(not(feature = "coolstuff"))]
+mod submod {
+    use crate::{S, MyTrait2};
+    // This impl should also have the `not(feature = "coolstuff")`.
+    // @has - '//*[@id="impl-MyTrait2-for-S"]//*[@class="stab portability"]' \
+    //        'Available on non-crate feature coolstuff only.'
+    impl MyTrait2 for S {}
+}
index 9b4ceb4f9cd86bbd29c0eb55840e718dc423a040..006132ef8aa40f8994c068399c4fc3670c0913a9 100644 (file)
@@ -3,7 +3,7 @@
 // rust-lang/rust#75225
 //
 // Since Rust 2018 we encourage writing out <'_> explicitly to make it clear
-// that borrowing is occuring. Make sure rustdoc is following the same idiom.
+// that borrowing is occurring. Make sure rustdoc is following the same idiom.
 
 #![crate_name = "foo"]
 
index ae981b9499a67cb20d131528639b836c2196ae34..2b9d4952d04eecd6c670d920b4f530b62dfc009d 100644 (file)
@@ -3,7 +3,7 @@
 
 // @has foo/trait.LendingIterator.html
 pub trait LendingIterator {
-    // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a"
+    // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a"
     type Item<'a> where Self: 'a;
 
     // @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]' \
@@ -24,7 +24,7 @@ fn next<'a>(&self) -> () {}
 pub struct Infinite<T>(T);
 
 // @has foo/trait.LendingIterator.html
-// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a = &'a T"
+// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a = &'a T"
 impl<T> LendingIterator for Infinite<T> {
     type Item<'a> where Self: 'a = &'a T;
 
index b75b8de52f9cb6c3fab04e3a1dbf86caa7d4e019..59b5b6e5797cc47e3037fdd914df2f6476a24187 100644 (file)
@@ -4,7 +4,7 @@
 pub trait Trait<'x> {}
 
 // @has foo/fn.test1.html
-// @has - '//pre' "pub fn test1<T>() where for<'a> &'a T: Iterator,"
+// @has - '//pre' "pub fn test1<T>()where for<'a> &'a T: Iterator,"
 pub fn test1<T>()
 where
     for<'a> &'a T: Iterator,
@@ -12,7 +12,7 @@ pub fn test1<T>()
 }
 
 // @has foo/fn.test2.html
-// @has - '//pre' "pub fn test2<T>() where for<'a, 'b> &'a T: Trait<'b>,"
+// @has - '//pre' "pub fn test2<T>()where for<'a, 'b> &'a T: Trait<'b>,"
 pub fn test2<T>()
 where
     for<'a, 'b> &'a T: Trait<'b>,
@@ -20,7 +20,7 @@ pub fn test2<T>()
 }
 
 // @has foo/fn.test3.html
-// @has - '//pre' "pub fn test3<F>() where F: for<'a, 'b> Fn(&'a u8, &'b u8),"
+// @has - '//pre' "pub fn test3<F>()where F: for<'a, 'b> Fn(&'a u8, &'b u8),"
 pub fn test3<F>()
 where
     F: for<'a, 'b> Fn(&'a u8, &'b u8),
@@ -38,7 +38,7 @@ pub struct Foo<'a> {
 // @has - '//span[@id="structfield.some_trait"]' "some_trait: &'a dyn for<'b> Trait<'b>"
 
 impl<'a> Foo<'a> {
-    // @has - '//h4[@class="code-header"]' "pub fn bar<T>() where T: Trait<'a>,"
+    // @has - '//h4[@class="code-header"]' "pub fn bar<T>()where T: Trait<'a>,"
     pub fn bar<T>()
     where
         T: Trait<'a>,
index 249158c1a1f89bca9a9f1b63f1da16c76785e388..b1481e1f27978045e6864c92d42841fdf5d0755a 100644 (file)
@@ -6,7 +6,7 @@
 pub struct Foo<T> { field: T }
 
 // @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-//     "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
+//     "impl<T: Clone> !AnAutoTrait for Foo<T>where T: Sync,"
 // @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \
-//     "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
+//     "impl<T: Clone> !AnAutoTrait for Foo<T>where T: Sync,"
 impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync {}
index 96a43323ce29d2432ca9163030267dadff0d6c29..f037a8e1a83d48fb5ab3a7590ffb8628f11f7b92 100644 (file)
@@ -7,7 +7,7 @@
 // @has 'foo/builders/struct.ActionRowBuilder.html'
 // @has - '//*[@id="synthetic-implementations"]' 'Auto Trait Implementations'
 
-// And that the link in the module is targetting it.
+// And that the link in the module is targeting it.
 // @has 'foo/builders/index.html'
 // @has - '//a[@href="struct.ActionRowBuilder.html"]' 'ActionRowBuilder'
 
index 84fc6f94a265a62a5d5d1becf5daf1f7efaf389d..643f93875909390b0b8bf410c325ecfd9393a309 100644 (file)
@@ -25,7 +25,7 @@ pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
 
 pub mod reexport {
     // @has issue_20727_4/reexport/trait.Index.html
-    // @has - '//*[@class="rust trait"]' 'trait Index<Idx> where Idx: ?Sized, {'
+    // @has - '//*[@class="rust trait"]' 'trait Index<Idx>where Idx: ?Sized,{'
     // @has - '//*[@class="rust trait"]' 'type Output: ?Sized'
     // @has - '//*[@class="rust trait"]' \
     //        'fn index(&self, index: Idx) -> &Self::Output'
@@ -33,7 +33,7 @@ pub mod reexport {
 
     // @has issue_20727_4/reexport/trait.IndexMut.html
     // @has - '//*[@class="rust trait"]' \
-    //        'trait IndexMut<Idx>: Index<Idx> where Idx: ?Sized, {'
+    //        'trait IndexMut<Idx>: Index<Idx>where Idx: ?Sized,{'
     // @has - '//*[@class="rust trait"]' \
     //        'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;'
     pub use issue_20727::IndexMut;
index 2a586b6ff6cdcfe3f427800bfe57cdeabb89c50f..29d2ec64c206d007d1d1a395fc0c38a3feb10615 100644 (file)
@@ -5,5 +5,5 @@
 
 // @has issue_21801/struct.Foo.html
 // @has - '//*[@id="method.new"]' \
-//        'fn new<F>(f: F) -> Foo where F: FnMut() -> i32'
+//        'fn new<F>(f: F) -> Foowhere F: FnMut() -> i32'
 pub use issue_21801::Foo;
index 635c3175f8138a39e40bc83d04f2bc1a6c0386be..134821e1ef3ea9bc724bb81e119a664724597461 100644 (file)
@@ -5,7 +5,7 @@ pub trait MyTrait {
     fn my_string(&self) -> String;
 }
 
-// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait-for-T']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug"
+// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait-for-T']//h3[@class='code-header in-band']" "impl<T> MyTrait for Twhere T: Debug"
 impl<T> MyTrait for T
 where
     T: fmt::Debug,
index 4184086f622abaff7f57fb211360c358ccfe15c8..91b67757453d2e788343eb82a15fa1d26313d309 100644 (file)
@@ -2,5 +2,5 @@
 
 pub trait Bar {}
 
-// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T) where T: Bar;'
+// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T)where T: Bar;'
 pub struct Foo<T>(pub T) where T: Bar;
index d88c29217023a9f9b5da233a3766297a872eeb0b..43fb705f58994717d9868b4942bdf5801c7fb847 100644 (file)
@@ -11,8 +11,8 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> {
 }
 
 // @has issue_50159/struct.Switch.html
-// @has - '//h3[@class="code-header in-band"]' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send'
-// @has - '//h3[@class="code-header in-band"]' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync'
+// @has - '//h3[@class="code-header in-band"]' 'impl<B> Send for Switch<B>where <B as Signal>::Item: Send'
+// @has - '//h3[@class="code-header in-band"]' 'impl<B> Sync for Switch<B>where <B as Signal>::Item: Sync'
 // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
 // @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
 pub struct Switch<B: Signal> {
index ee11ccc6811633fac9cd3f6b09abfc35b7e0a62f..aa5890a84514fc56364e8724fbcaf5891fdbf6d0 100644 (file)
@@ -8,7 +8,7 @@ pub trait Owned<'a> {
 
 // @has issue_51236/struct.Owned.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<T> Send for Owned<T> where <T as Owned<'static>>::Reader: Send"
+// "impl<T> Send for Owned<T>where <T as Owned<'static>>::Reader: Send"
 pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
     marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
 }
index bedaf5c4ddc360a311c83fc415943cab0b1e08f2..ce0f85d25da56d70009b7fee9911db47c06bd05e 100644 (file)
@@ -1,13 +1,11 @@
 pub trait ScopeHandle<'scope> {}
 
-
-
 // @has issue_54705/struct.ScopeFutureContents.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'scope, S> Send for ScopeFutureContents<'scope, S> where S: Sync"
+// "impl<'scope, S> Send for ScopeFutureContents<'scope, S>where S: Sync"
 //
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S> where S: Sync"
+// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S>where S: Sync"
 pub struct ScopeFutureContents<'scope, S>
     where S: ScopeHandle<'scope>,
 {
index 83e08094c09534abf9da016c5c95fd7c42c8e9e9..a8841f137fecff11bb32a8a7fa028e850e30d40d 100644 (file)
@@ -8,7 +8,7 @@
 
 extern crate issue_98697_reexport_with_anonymous_lifetime;
 
-// @has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'fn repro<F>() where F: Fn(&str)'
+// @has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'fn repro<F>()where F: Fn(&str)'
 // @!has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'for<'
 pub use issue_98697_reexport_with_anonymous_lifetime::repro;
 
index ee3010514417a7da47aaaf9b9761b7ebb166a740..d3cf7e1406503f72ef67f4c38fb8614776410c5e 100644 (file)
@@ -4,7 +4,7 @@
 // (yes, that's a thing), rustdoc lists both of them on the index page,
 // but only documents the first one on the page for the macro.
 // Fortunately, this can only happen in document private items mode,
-// but it still isn't ideal beahvior.
+// but it still isn't ideal behavior.
 //
 // See https://github.com/rust-lang/rust/pull/88019#discussion_r693920453
 //
diff --git a/src/test/rustdoc/primitive-reference.rs b/src/test/rustdoc/primitive-reference.rs
new file mode 100644 (file)
index 0000000..5c11934
--- /dev/null
@@ -0,0 +1,37 @@
+#![crate_name = "foo"]
+
+#![feature(rustdoc_internals)]
+
+// @has foo/index.html
+// @has - '//h2[@id="primitives"]' 'Primitive Types'
+// @has - '//a[@href="primitive.reference.html"]' 'reference'
+// @has - '//div[@class="sidebar-elems"]//li/a' 'Primitive Types'
+// @has - '//div[@class="sidebar-elems"]//li/a/@href' '#primitives'
+// @has foo/primitive.reference.html
+// @has - '//a[@class="primitive"]' 'reference'
+// @has - '//span[@class="in-band"]' 'Primitive Type reference'
+// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
+
+// There should be only one implementation listed.
+// @count - '//*[@class="impl has-srclink"]' 1
+// @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header in-band"]' \
+//        'impl<A, B> Foo<&A> for &B'
+#[doc(primitive = "reference")]
+/// this is a test!
+mod reference {}
+
+pub struct Bar;
+
+// This implementation should **not** show up.
+impl<T> From<&T> for Bar {
+    fn from(s: &T) -> Self {
+        Bar
+    }
+}
+
+pub trait Foo<T> {
+    fn stuff(&self, other: &T) {}
+}
+
+// This implementation should show up.
+impl<A, B> Foo<&A> for &B {}
index b3f511bc1f153fc423b713ea2866bccc7cc4d65f..7f8f74ff457a5ab906ec670ea3d930d4e049adaa 100644 (file)
@@ -7,8 +7,8 @@
 // @has - '//span[@class="in-band"]' 'Primitive Type slice'
 // @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 // @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
-// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T] where T: Send'
-// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T] where T: Sync'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T]where T: Send'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T]where T: Sync'
 #[doc(primitive = "slice")]
 /// this is a test!
 mod slice_prim {}
index 54c54fdbf68a8acafc9e50e48d0af6f9f7d3bc7b..19138fd1aceb20d1c1c8edb5699b83befb86cac9 100644 (file)
@@ -1,6 +1,6 @@
 // @has basic/struct.Foo.html
-// @has - '//h3[@class="code-header in-band"]' 'impl<T> Send for Foo<T> where T: Send'
-// @has - '//h3[@class="code-header in-band"]' 'impl<T> Sync for Foo<T> where T: Sync'
+// @has - '//h3[@class="code-header in-band"]' 'impl<T> Send for Foo<T>where T: Send'
+// @has - '//h3[@class="code-header in-band"]' 'impl<T> Sync for Foo<T>where T: Sync'
 // @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0
 // @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
 pub struct Foo<T> {
index f9017b90caee774d2022797e0321002bb77b630f..39f78983da2b031766ab2c8968a2d26d73e4f320 100644 (file)
@@ -21,7 +21,7 @@ pub struct Foo<T> {
 
 // @has complex/struct.NotOuter.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
+// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K>where K: for<'b> Fn((&'b bool, &'a u8)) \
 // -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
 
 pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter};
index ee1393f9729c176ccff505f02e489c9e2116a2dc..0c94850e78608c2cb12b5f90bf4cf80d6fd18e77 100644 (file)
@@ -10,10 +10,10 @@ unsafe impl<'a, T> Send for Inner<'a, T>
 
 // @has lifetimes/struct.Foo.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'c, K> Send for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
+// "impl<'c, K> Send for Foo<'c, K>where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
 //
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'c, K> Sync for Foo<'c, K> where K: Sync"
+// "impl<'c, K> Sync for Foo<'c, K>where K: Sync"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
 }
index 49bad162211b7041be4ba179022091d2d11f3b9f..35047e3e8c0717349eca64a02043ac1b06c4bc97 100644 (file)
@@ -1,6 +1,6 @@
 // @has manual/struct.Foo.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// 'impl<T> Sync for Foo<T> where T: Sync'
+// 'impl<T> Sync for Foo<T>where T: Sync'
 //
 // @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
 // 'impl<T> Send for Foo<T>'
index 69edbee619e31e8316c1796bcc7916cfd9cd9c28..09587bcc30f13954f3c742080c7ec24be6453d9e 100644 (file)
@@ -10,10 +10,10 @@ unsafe impl<T> Send for Inner<T>
 
 // @has nested/struct.Foo.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// 'impl<T> Send for Foo<T> where T: Copy'
+// 'impl<T> Send for Foo<T>where T: Copy'
 //
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// 'impl<T> Sync for Foo<T> where T: Sync'
+// 'impl<T> Sync for Foo<T>where T: Sync'
 pub struct Foo<T> {
     inner_field: Inner<T>,
 }
index 16ab876e829ef8f25f4d82d79529e4c89c84f3ca..41375decc8a4aa6c9971764ab82fab822973f17c 100644 (file)
@@ -10,7 +10,7 @@ unsafe impl<T> Send for Inner<T>
 
 // @has no_redundancy/struct.Outer.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<T> Send for Outer<T> where T: Send + Copy"
+// "impl<T> Send for Outer<T>where T: Send + Copy"
 pub struct Outer<T> {
     inner_field: Inner<T>,
 }
index 8b020582563f3d3ac9fe6cd6be4975c2c66641bf..e80b1b1dc9bcf99c96fc535bcc8d9ca7f9ed470a 100644 (file)
@@ -24,10 +24,10 @@ unsafe impl<'a, T> Sync for Inner<'a, T>
 
 // @has project/struct.Foo.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'c, K> Send for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
+// "impl<'c, K> Send for Foo<'c, K>where K: MyTrait<MyItem = bool>, 'c: 'static"
 //
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<'c, K> Sync for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
+// "impl<'c, K> Sync for Foo<'c, K>where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
 // 'c: 'static,"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
index ccef901b18da3e57b359973eb52e04cb3f5f19ad..d15a8de7d2fe14fdb20381086bc6dc7a6762e58c 100644 (file)
@@ -24,6 +24,6 @@ impl<T> Pattern for Wrapper<T> {
 
 // @has self_referential/struct.WriteAndThen.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<P1> Send for WriteAndThen<P1>  where  <P1 as Pattern>::Value: Send"
+// "impl<P1> Send for WriteAndThen<P1>where    <P1 as Pattern>::Value: Send"
 pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
     where P1: Pattern;
index 36e985144b0e09026e60796a8908419b766eb363..08e9567313e22bb78f0faf6f5701537b6c9e3ecf 100644 (file)
@@ -4,7 +4,7 @@ pub trait OwnedTrait<'a> {
 
 // @has static_region/struct.Owned.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<T> Send for Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
+// "impl<T> Send for Owned<T>where <T as OwnedTrait<'static>>::Reader: Send"
 pub struct Owned<T> where T: OwnedTrait<'static> {
     marker: <T as OwnedTrait<'static>>::Reader,
 }
index 3150a8ea05f41f321dde58bbe2dded183deead48..b8502e10a48c4dcb5ad05e763930a673bae55046 100644 (file)
@@ -7,7 +7,7 @@ pub trait SomeTrait<Rhs = Self>
 }
 
 // @has 'foo/trait.SomeTrait.html'
-// @has - "//*[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, "
+// @has - "//*[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, "
 impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)
 where
     A: PartialOrd<A> + PartialEq<A>,
index 50a5722fbaff6926e5feec51c6ffd18d531bac5a..c1a630e25ba0ef00881c4682afd10ed922f97351 100644 (file)
@@ -3,17 +3,17 @@
 
 pub trait MyTrait { fn dummy(&self) { } }
 
-// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait"
+// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_)where A: MyTrait"
 pub struct Alpha<A>(A) where A: MyTrait;
-// @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B> where B: MyTrait"
+// @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B>where B: MyTrait"
 pub trait Bravo<B> where B: MyTrait { fn get(&self, B: B); }
-// @has foo/fn.charlie.html '//pre' "pub fn charlie<C>() where C: MyTrait"
+// @has foo/fn.charlie.html '//pre' "pub fn charlie<C>()where C: MyTrait"
 pub fn charlie<C>() where C: MyTrait {}
 
 pub struct Delta<D>(D);
 
 // @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-//          "impl<D> Delta<D> where D: MyTrait"
+//          "impl<D> Delta<D>where D: MyTrait"
 impl<D> Delta<D> where D: MyTrait {
     pub fn delta() {}
 }
@@ -33,19 +33,19 @@ pub trait TraitWhere {
 }
 
 // @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-//          "impl<E> MyTrait for Echo<E> where E: MyTrait"
+//          "impl<E> MyTrait for Echo<E>where E: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
-//          "impl<E> MyTrait for Echo<E> where E: MyTrait"
-impl<E> MyTrait for Echo<E> where E: MyTrait {}
+//          "impl<E> MyTrait for Echo<E>where E: MyTrait"
+impl<E> MyTrait for Echo<E>where E: MyTrait {}
 
 pub enum Foxtrot<F> { Foxtrot1(F) }
 
 // @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-//          "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
+//          "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
-//          "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
-impl<F> MyTrait for Foxtrot<F> where F: MyTrait {}
+//          "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
+impl<F> MyTrait for Foxtrot<F>where F: MyTrait {}
 
 // @has foo/type.Golf.html '//pre[@class="rust typedef"]' \
-//          "type Golf<T> where T: Clone, = (T, T)"
+//          "type Golf<T>where T: Clone, = (T, T)"
 pub type Golf<T> where T: Clone = (T, T);
index 33192433bbf38ca80e6d6b5a427f286cd77c7589..0e449256153a2224949094a65297991e4b39938d 100644 (file)
@@ -1,6 +1,7 @@
 // compile-flags: -Z unstable-options
 
 #![crate_type = "lib"]
+#![feature(rustc_attrs)]
 #![feature(rustc_private)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
@@ -71,3 +72,10 @@ pub fn make_diagnostics<'a>(sess: &'a ParseSess) {
     //~^ ERROR diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls
     //~^^ ERROR diagnostics should be created using translatable messages
 }
+
+// Check that `rustc_lint_diagnostics`-annotated functions aren't themselves linted.
+
+#[rustc_lint_diagnostics]
+pub fn skipped_because_of_annotation<'a>(sess: &'a ParseSess) {
+    let _diag = sess.struct_err("untranslatable diagnostic"); // okay!
+}
index bae78ffdc021b5fff868b5189e422d60a77332d9..ed5105dabcd3ff8d686257031a5d6106df10d4b5 100644 (file)
@@ -1,41 +1,41 @@
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:36:14
+  --> $DIR/diagnostics.rs:37:14
    |
 LL |         sess.struct_err("untranslatable diagnostic")
    |              ^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/diagnostics.rs:5:9
+  --> $DIR/diagnostics.rs:6:9
    |
 LL | #![deny(rustc::untranslatable_diagnostic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:53:14
+  --> $DIR/diagnostics.rs:54:14
    |
 LL |         diag.note("untranslatable diagnostic");
    |              ^^^^
 
 error: diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls
-  --> $DIR/diagnostics.rs:67:22
+  --> $DIR/diagnostics.rs:68:22
    |
 LL |     let _diag = sess.struct_err(fluent::parser::expect_path);
    |                      ^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/diagnostics.rs:6:9
+  --> $DIR/diagnostics.rs:7:9
    |
 LL | #![deny(rustc::diagnostic_outside_of_impl)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls
-  --> $DIR/diagnostics.rs:70:22
+  --> $DIR/diagnostics.rs:71:22
    |
 LL |     let _diag = sess.struct_err("untranslatable diagnostic");
    |                      ^^^^^^^^^^
 
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:70:22
+  --> $DIR/diagnostics.rs:71:22
    |
 LL |     let _diag = sess.struct_err("untranslatable diagnostic");
    |                      ^^^^^^^^^^
diff --git a/src/test/ui-fulldeps/issue-15778-pass.rs b/src/test/ui-fulldeps/issue-15778-pass.rs
deleted file mode 100644 (file)
index c031dbc..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// check-pass
-// aux-build:lint-for-crate-rpass.rs
-// ignore-stage1
-// compile-flags: -D crate-not-okay
-
-#![feature(plugin, register_attr, custom_inner_attributes)]
-
-#![register_attr(
-    crate_okay,
-    crate_blue,
-    crate_red,
-    crate_grey,
-    crate_green,
-)]
-
-#![plugin(lint_for_crate_rpass)] //~ WARNING compiler plugins are deprecated
-#![crate_okay]
-#![crate_blue]
-#![crate_red]
-#![crate_grey]
-#![crate_green]
-
-fn main() {}
diff --git a/src/test/ui-fulldeps/issue-15778-pass.stderr b/src/test/ui-fulldeps/issue-15778-pass.stderr
deleted file mode 100644 (file)
index a9d9721..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/issue-15778-pass.rs:16:1
-   |
-LL | #![plugin(lint_for_crate_rpass)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
-   |
-   = note: `#[warn(deprecated)]` on by default
-
-warning: 1 warning emitted
-
index b1f557cb94de8538e58ef71051a7628f05fbf842..c1c109ac1eade556f168b1c2000ef8ff04d624e2 100644 (file)
@@ -2,7 +2,7 @@
 // Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)]
 
 // normalize-stderr-test "the following other types implement trait `IntoDiagnosticArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr"
-
+// normalize-stderr-test "diagnostic_builder\.rs:[0-9]+:[0-9]+" -> "diagnostic_builder.rs:LL:CC"
 // The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
 // changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler
 // the test is just ignored on stable and beta:
index 621c59f448951ed0d972684a86272be7438063bf..ab5c28fe473326aa02b4a5a42cd62e32a4dc57e5 100644 (file)
@@ -453,7 +453,7 @@ LL | #[derive(SessionDiagnostic)]
    |
    = help: normalized in stderr
 note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
-  --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:569:19
+  --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
    |
 LL |         arg: impl IntoDiagnosticArg,
    |                   ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
index ddfc0d3365df0710e3457d5f233cb0c89736853c..812ca0c72bd058178d518b539eb4c709db737759 100644 (file)
@@ -167,8 +167,8 @@ enum P {
 #[derive(SessionSubdiagnostic)]
 enum Q {
     #[bar]
-//~^ ERROR `#[bar]` is not a valid attribute
-//~^^ ERROR cannot find attribute `bar` in this scope
+    //~^ ERROR `#[bar]` is not a valid attribute
+    //~^^ ERROR cannot find attribute `bar` in this scope
     A {
         #[primary_span]
         span: Span,
@@ -179,8 +179,8 @@ enum Q {
 #[derive(SessionSubdiagnostic)]
 enum R {
     #[bar = "..."]
-//~^ ERROR `#[bar = ...]` is not a valid attribute
-//~^^ ERROR cannot find attribute `bar` in this scope
+    //~^ ERROR `#[bar = ...]` is not a valid attribute
+    //~^^ ERROR cannot find attribute `bar` in this scope
     A {
         #[primary_span]
         span: Span,
@@ -191,8 +191,8 @@ enum R {
 #[derive(SessionSubdiagnostic)]
 enum S {
     #[bar = 4]
-//~^ ERROR `#[bar = ...]` is not a valid attribute
-//~^^ ERROR cannot find attribute `bar` in this scope
+    //~^ ERROR `#[bar = ...]` is not a valid attribute
+    //~^^ ERROR cannot find attribute `bar` in this scope
     A {
         #[primary_span]
         span: Span,
@@ -203,8 +203,8 @@ enum S {
 #[derive(SessionSubdiagnostic)]
 enum T {
     #[bar("...")]
-//~^ ERROR `#[bar("...")]` is not a valid attribute
-//~^^ ERROR cannot find attribute `bar` in this scope
+    //~^ ERROR `#[bar(...)]` is not a valid attribute
+    //~^^ ERROR cannot find attribute `bar` in this scope
     A {
         #[primary_span]
         span: Span,
@@ -215,7 +215,7 @@ enum T {
 #[derive(SessionSubdiagnostic)]
 enum U {
     #[label(code = "...")]
-//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
+    //~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
     A {
         #[primary_span]
         span: Span,
@@ -232,7 +232,7 @@ enum V {
         var: String,
     },
     B {
-//~^ ERROR subdiagnostic kind not specified
+    //~^ ERROR subdiagnostic kind not specified
         #[primary_span]
         span: Span,
         var: String,
@@ -309,11 +309,7 @@ union AC {
 
 #[derive(SessionSubdiagnostic)]
 #[label(parser::add_paren)]
-//~^ NOTE previously specified here
-//~^^ NOTE previously specified here
 #[label(parser::add_paren)]
-//~^ ERROR specified multiple times
-//~^^ ERROR specified multiple times
 struct AD {
     #[primary_span]
     span: Span,
@@ -331,16 +327,16 @@ struct AE {
 #[label(parser::add_paren)]
 struct AF {
     #[primary_span]
-//~^ NOTE previously specified here
+    //~^ NOTE previously specified here
     span_a: Span,
     #[primary_span]
-//~^ ERROR specified multiple times
+    //~^ ERROR specified multiple times
     span_b: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
 struct AG {
-//~^ ERROR subdiagnostic kind not specified
+    //~^ ERROR subdiagnostic kind not specified
     #[primary_span]
     span: Span,
 }
@@ -392,27 +388,25 @@ struct AK {
     #[primary_span]
     span: Span,
     #[applicability]
-//~^ NOTE previously specified here
+    //~^ NOTE previously specified here
     applicability_a: Applicability,
     #[applicability]
-//~^ ERROR specified multiple times
+    //~^ ERROR specified multiple times
     applicability_b: Applicability,
 }
 
 #[derive(SessionSubdiagnostic)]
 #[suggestion(parser::add_paren, code = "...")]
-//~^ ERROR suggestion without `applicability`
 struct AL {
     #[primary_span]
     span: Span,
     #[applicability]
-//~^ ERROR the `#[applicability]` attribute can only be applied to fields of type `Applicability`
+    //~^ ERROR the `#[applicability]` attribute can only be applied to fields of type `Applicability`
     applicability: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
 #[suggestion(parser::add_paren, code = "...")]
-//~^ ERROR suggestion without `applicability`
 struct AM {
     #[primary_span]
     span: Span,
@@ -448,8 +442,7 @@ struct AP {
 
 #[derive(SessionSubdiagnostic)]
 #[suggestion(parser::add_paren, code = "...")]
-//~^ ERROR suggestion without `applicability`
-//~^^ ERROR suggestion without `#[primary_span]` field
+//~^ ERROR suggestion without `#[primary_span]` field
 struct AR {
     var: String,
 }
@@ -519,3 +512,120 @@ struct AZ {
     #[primary_span]
     span: Span,
 }
+
+#[derive(SessionSubdiagnostic)]
+#[suggestion(parser::add_paren, code = "...")]
+//~^ ERROR suggestion without `#[primary_span]` field
+struct BA {
+    #[suggestion_part]
+    //~^ ERROR `#[suggestion_part]` is not a valid attribute
+    span: Span,
+    #[suggestion_part(code = "...")]
+    //~^ ERROR `#[suggestion_part(...)]` is not a valid attribute
+    span2: Span,
+    #[applicability]
+    applicability: Applicability,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
+//~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields
+//~| ERROR `code` is not a valid nested attribute of a `multipart_suggestion` attribute
+struct BBa {
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+struct BBb {
+    #[suggestion_part]
+    //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
+    span1: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+struct BBc {
+    #[suggestion_part()]
+    //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
+    span1: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren)]
+//~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields
+struct BC {
+    #[primary_span]
+    //~^ ERROR `#[primary_span]` is not a valid attribute
+    span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren)]
+struct BD {
+    #[suggestion_part]
+    //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
+    span1: Span,
+    #[suggestion_part()]
+    //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
+    span2: Span,
+    #[suggestion_part(foo = "bar")]
+    //~^ ERROR `#[suggestion_part(foo = ...)]` is not a valid attribute
+    span4: Span,
+    #[suggestion_part(code = "...")]
+    //~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+    s1: String,
+    #[suggestion_part()]
+    //~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+    s2: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+struct BE {
+    #[suggestion_part(code = "...", code = ",,,")]
+    //~^ ERROR specified multiple times
+    //~| NOTE previously specified here
+    span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+struct BF {
+    #[suggestion_part(code = "(")]
+    first: Span,
+    #[suggestion_part(code = ")")]
+    second: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren)]
+struct BG {
+    #[applicability]
+    appl: Applicability,
+    #[suggestion_part(code = "(")]
+    first: Span,
+    #[suggestion_part(code = ")")]
+    second: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+//~^ NOTE previously specified here
+struct BH {
+    #[applicability]
+    //~^ ERROR specified multiple times
+    appl: Applicability,
+    #[suggestion_part(code = "(")]
+    first: Span,
+    #[suggestion_part(code = ")")]
+    second: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+struct BI {
+    #[suggestion_part(code = "")]
+    spans: Vec<Span>,
+}
index a289c4fffd9365e6882e9bd0a60fff2d420c6988..0a0247e898088b41bcb6592e1a53afb59cc76ec8 100644 (file)
@@ -65,16 +65,16 @@ LL | #[label()]
    | ^^^^^^^^^^
 
 error: `code` is not a valid nested attribute of a `label` attribute
-  --> $DIR/subdiagnostic-derive.rs:137:1
+  --> $DIR/subdiagnostic-derive.rs:137:28
    |
 LL | #[label(parser::add_paren, code = "...")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^
 
 error: `applicability` is not a valid nested attribute of a `label` attribute
-  --> $DIR/subdiagnostic-derive.rs:146:1
+  --> $DIR/subdiagnostic-derive.rs:146:28
    |
 LL | #[label(parser::add_paren, applicability = "machine-applicable")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unsupported type attribute for subdiagnostic enum
   --> $DIR/subdiagnostic-derive.rs:155:1
@@ -100,13 +100,11 @@ error: `#[bar = ...]` is not a valid attribute
 LL |     #[bar = 4]
    |     ^^^^^^^^^^
 
-error: `#[bar("...")]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:205:11
+error: `#[bar(...)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:205:5
    |
 LL |     #[bar("...")]
-   |           ^^^^^
-   |
-   = help: first argument of the attribute should be the diagnostic slug
+   |     ^^^^^^^^^^^^^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:217:5
@@ -163,6 +161,8 @@ error: `#[bar(...)]` is not a valid attribute
    |
 LL |     #[bar("...")]
    |     ^^^^^^^^^^^^^
+   |
+   = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
 error: unexpected unsupported untagged union
   --> $DIR/subdiagnostic-derive.rs:304:1
@@ -174,32 +174,8 @@ LL | |     b: u64
 LL | | }
    | |_^
 
-error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:314:1
-   |
-LL | #[label(parser::add_paren)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:311:1
-   |
-LL | #[label(parser::add_paren)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:314:1
-   |
-LL | #[label(parser::add_paren)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:311:1
-   |
-LL | #[label(parser::add_paren)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: `#[label(parser::add_paren)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:323:28
+  --> $DIR/subdiagnostic-derive.rs:319:28
    |
 LL | #[label(parser::add_paren, parser::add_paren)]
    |                            ^^^^^^^^^^^^^^^^^
@@ -207,133 +183,225 @@ LL | #[label(parser::add_paren, parser::add_paren)]
    = help: a diagnostic slug must be the first argument to the attribute
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:336:5
+  --> $DIR/subdiagnostic-derive.rs:332:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:333:5
+  --> $DIR/subdiagnostic-derive.rs:329:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: subdiagnostic kind not specified
-  --> $DIR/subdiagnostic-derive.rs:342:8
+  --> $DIR/subdiagnostic-derive.rs:338:8
    |
 LL | struct AG {
    |        ^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:379:47
+  --> $DIR/subdiagnostic-derive.rs:375:47
    |
 LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
    |                                               ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:379:33
+  --> $DIR/subdiagnostic-derive.rs:375:33
    |
 LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
    |                                 ^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:397:5
+  --> $DIR/subdiagnostic-derive.rs:393:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:394:5
+  --> $DIR/subdiagnostic-derive.rs:390:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
-  --> $DIR/subdiagnostic-derive.rs:408:5
+  --> $DIR/subdiagnostic-derive.rs:403:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
-error: suggestion without `applicability`
-  --> $DIR/subdiagnostic-derive.rs:403:1
+error: suggestion without `code = "..."`
+  --> $DIR/subdiagnostic-derive.rs:416:1
    |
-LL | / #[suggestion(parser::add_paren, code = "...")]
-LL | |
-LL | | struct AL {
-LL | |     #[primary_span]
-...  |
-LL | |     applicability: Span,
-LL | | }
-   | |_^
+LL | #[suggestion(parser::add_paren)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: suggestion without `applicability`
-  --> $DIR/subdiagnostic-derive.rs:414:1
+error: invalid applicability
+  --> $DIR/subdiagnostic-derive.rs:426:46
+   |
+LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")]
+   |                                              ^^^^^^^^^^^^^^^^^^^^^
+
+error: suggestion without `#[primary_span]` field
+  --> $DIR/subdiagnostic-derive.rs:444:1
    |
 LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
-LL | | struct AM {
-LL | |     #[primary_span]
-LL | |     span: Span,
+LL | | struct AR {
+LL | |     var: String,
 LL | | }
    | |_^
 
-error: suggestion without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:422:1
+error: unsupported type attribute for subdiagnostic enum
+  --> $DIR/subdiagnostic-derive.rs:458:1
+   |
+LL | #[label]
+   | ^^^^^^^^
+
+error: `var` doesn't refer to a field on this type
+  --> $DIR/subdiagnostic-derive.rs:478:39
+   |
+LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+   |                                       ^^^^^^^
+
+error: `var` doesn't refer to a field on this type
+  --> $DIR/subdiagnostic-derive.rs:497:43
+   |
+LL |     #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+   |                                           ^^^^^^^
+
+error: `#[suggestion_part]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:520:5
+   |
+LL |     #[suggestion_part]
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
+
+error: `#[suggestion_part(...)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:523:5
+   |
+LL |     #[suggestion_part(code = "...")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL | / #[suggestion(parser::add_paren)]
+   = help: `#[suggestion_part(...)]` is only valid in multipart suggestions
+
+error: suggestion without `#[primary_span]` field
+  --> $DIR/subdiagnostic-derive.rs:517:1
+   |
+LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
-LL | | struct AN {
-LL | |     #[primary_span]
+LL | | struct BA {
+LL | |     #[suggestion_part]
 ...  |
-LL | |     applicability: Applicability,
+LL | |     var: String,
 LL | | }
    | |_^
 
-error: invalid applicability
-  --> $DIR/subdiagnostic-derive.rs:432:46
+error: `code` is not a valid nested attribute of a `multipart_suggestion` attribute
+  --> $DIR/subdiagnostic-derive.rs:532:43
    |
-LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")]
-   |                                              ^^^^^^^^^^^^^^^^^^^^^
+LL | #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
+   |                                           ^^^^^^^^^^^^
 
-error: suggestion without `applicability`
-  --> $DIR/subdiagnostic-derive.rs:450:1
+error: multipart suggestion without any `#[suggestion_part(...)]` fields
+  --> $DIR/subdiagnostic-derive.rs:532:1
    |
-LL | / #[suggestion(parser::add_paren, code = "...")]
+LL | / #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
 LL | |
 LL | |
-LL | | struct AR {
+LL | | struct BBa {
 LL | |     var: String,
 LL | | }
    | |_^
 
-error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:450:1
+error: `#[suggestion_part(...)]` attribute without `code = "..."`
+  --> $DIR/subdiagnostic-derive.rs:542:5
    |
-LL | / #[suggestion(parser::add_paren, code = "...")]
+LL |     #[suggestion_part]
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: `#[suggestion_part(...)]` attribute without `code = "..."`
+  --> $DIR/subdiagnostic-derive.rs:550:5
+   |
+LL |     #[suggestion_part()]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: `#[primary_span]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:559:5
+   |
+LL |     #[primary_span]
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
+
+error: multipart suggestion without any `#[suggestion_part(...)]` fields
+  --> $DIR/subdiagnostic-derive.rs:556:1
+   |
+LL | / #[multipart_suggestion(parser::add_paren)]
 LL | |
+LL | | struct BC {
+LL | |     #[primary_span]
 LL | |
-LL | | struct AR {
-LL | |     var: String,
+LL | |     span: Span,
 LL | | }
    | |_^
 
-error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:465:1
+error: `#[suggestion_part(...)]` attribute without `code = "..."`
+  --> $DIR/subdiagnostic-derive.rs:567:5
    |
-LL | #[label]
-   | ^^^^^^^^
+LL |     #[suggestion_part]
+   |     ^^^^^^^^^^^^^^^^^^
 
-error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:485:39
+error: `#[suggestion_part(...)]` attribute without `code = "..."`
+  --> $DIR/subdiagnostic-derive.rs:570:5
    |
-LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
-   |                                       ^^^^^^^
+LL |     #[suggestion_part()]
+   |     ^^^^^^^^^^^^^^^^^^^^
 
-error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:504:43
+error: `#[suggestion_part(foo = ...)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:573:23
    |
-LL |     #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
-   |                                           ^^^^^^^
+LL |     #[suggestion_part(foo = "bar")]
+   |                       ^^^^^^^^^^^
+   |
+   = help: `code` is the only valid nested attribute
+
+error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+  --> $DIR/subdiagnostic-derive.rs:576:5
+   |
+LL |     #[suggestion_part(code = "...")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+  --> $DIR/subdiagnostic-derive.rs:579:5
+   |
+LL |     #[suggestion_part()]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: specified multiple times
+  --> $DIR/subdiagnostic-derive.rs:587:37
+   |
+LL |     #[suggestion_part(code = "...", code = ",,,")]
+   |                                     ^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/subdiagnostic-derive.rs:587:23
+   |
+LL |     #[suggestion_part(code = "...", code = ",,,")]
+   |                       ^^^^^^^^^^^^
+
+error: specified multiple times
+  --> $DIR/subdiagnostic-derive.rs:617:5
+   |
+LL |     #[applicability]
+   |     ^^^^^^^^^^^^^^^^
+   |
+note: previously specified here
+  --> $DIR/subdiagnostic-derive.rs:614:43
+   |
+LL | #[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find attribute `foo` in this scope
   --> $DIR/subdiagnostic-derive.rs:63:3
@@ -395,6 +463,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
 LL | #[label(slug)]
    |         ^^^^ not found in `rustc_errors::fluent`
 
-error: aborting due to 52 previous errors
+error: aborting due to 63 previous errors
 
 For more information about this error, try `rustc --explain E0425`.
index 54b7c8bb9c6f81af6fa62276202c17c1c53e73de..851da231a73441708317aabc4c681f92e967f2dc 100644 (file)
@@ -86,7 +86,7 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
 
 // Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed.
 // However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions
-// in these libaries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
+// in these libraries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
 // unwind. So, for this test case we will define the symbol.
 #[lang = "eh_personality"]
 extern fn rust_eh_personality() {}
index ffa331a992c8b42265769f2763721fd1a9c498ff..30ce0f162c7ac55d21b1e362078abbee6f8c22dd 100644 (file)
@@ -73,7 +73,7 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
 
 // Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed.
 // However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions
-// in these libaries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
+// in these libraries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
 // unwind. So, for this test case we will define the symbol.
 #[lang = "eh_personality"]
 extern fn rust_eh_personality() {}
index 162ff1d32bc44b486fc8f0b41e82cc8998e7faef..1845139659db55ff0380b9a57d4f70bebbad5b62 100644 (file)
@@ -106,7 +106,7 @@ error[E0308]: mismatched types
   --> $DIR/type-check-1.rs:60:26
    |
 LL |         asm!("{}", const 0 as *mut u8);
-   |                          ^^^^^^^^^^^^ expected integer, found *-ptr
+   |                          ^^^^^^^^^^^^ expected integer, found `*mut u8`
    |
    = note:     expected type `{integer}`
            found raw pointer `*mut u8`
@@ -133,7 +133,7 @@ error[E0308]: mismatched types
   --> $DIR/type-check-1.rs:78:25
    |
 LL | global_asm!("{}", const 0 as *mut u8);
-   |                         ^^^^^^^^^^^^ expected integer, found *-ptr
+   |                         ^^^^^^^^^^^^ expected integer, found `*mut u8`
    |
    = note:     expected type `{integer}`
            found raw pointer `*mut u8`
index 4a533939931b2c7c7d4fc0ad951ccab0e2dedcb2..d00def571666bdaf38857f9dea57b551b6dcb8fd 100644 (file)
@@ -1,7 +1,7 @@
 #![feature(associated_type_bounds)]
 #![feature(anonymous_lifetime_in_impl_trait)]
 
-// The same thing should happen for constaints in dyn trait.
+// The same thing should happen for constraints in dyn trait.
 fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
 //~^ ERROR missing lifetime specifier
 //~| ERROR mismatched types
index c993e1d27202d5a53ac33f843623d48b8bd24852..00066efccb8dd2229766a28170703ca18a8388ea 100644 (file)
@@ -29,12 +29,14 @@ pub fn f1_uint_uint() {
     f1(2u32, 4u32);
     //~^ ERROR `u32: Foo` is not satisfied
     //~| ERROR `u32: Foo` is not satisfied
+    //~| ERROR `u32: Foo` is not satisfied
 }
 
 pub fn f1_uint_int() {
     f1(2u32, 4i32);
     //~^ ERROR `u32: Foo` is not satisfied
     //~| ERROR `u32: Foo` is not satisfied
+    //~| ERROR `u32: Foo` is not satisfied
 }
 
 pub fn f2_int() {
index 5edd5c864e1357b44b0c6407bef4d309bc3139ec..206f4902410269912d13d6986d1c12add2cb313e 100644 (file)
@@ -31,6 +31,14 @@ note: required by a bound in `f1`
 LL | pub fn f1<T: Foo>(a: T, x: T::A) {}
    |              ^^^ required by this bound in `f1`
 
+error[E0277]: the trait bound `u32: Foo` is not satisfied
+  --> $DIR/associated-types-path-2.rs:29:5
+   |
+LL |     f1(2u32, 4u32);
+   |     ^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u32`
+   |
+   = help: the trait `Foo` is implemented for `i32`
+
 error[E0277]: the trait bound `u32: Foo` is not satisfied
   --> $DIR/associated-types-path-2.rs:29:14
    |
@@ -40,7 +48,7 @@ LL |     f1(2u32, 4u32);
    = help: the trait `Foo` is implemented for `i32`
 
 error[E0277]: the trait bound `u32: Foo` is not satisfied
-  --> $DIR/associated-types-path-2.rs:35:8
+  --> $DIR/associated-types-path-2.rs:36:8
    |
 LL |     f1(2u32, 4i32);
    |     -- ^^^^ the trait `Foo` is not implemented for `u32`
@@ -55,7 +63,15 @@ LL | pub fn f1<T: Foo>(a: T, x: T::A) {}
    |              ^^^ required by this bound in `f1`
 
 error[E0277]: the trait bound `u32: Foo` is not satisfied
-  --> $DIR/associated-types-path-2.rs:35:14
+  --> $DIR/associated-types-path-2.rs:36:5
+   |
+LL |     f1(2u32, 4i32);
+   |     ^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u32`
+   |
+   = help: the trait `Foo` is implemented for `i32`
+
+error[E0277]: the trait bound `u32: Foo` is not satisfied
+  --> $DIR/associated-types-path-2.rs:36:14
    |
 LL |     f1(2u32, 4i32);
    |              ^^^^ the trait `Foo` is not implemented for `u32`
@@ -63,7 +79,7 @@ LL |     f1(2u32, 4i32);
    = help: the trait `Foo` is implemented for `i32`
 
 error[E0308]: mismatched types
-  --> $DIR/associated-types-path-2.rs:41:18
+  --> $DIR/associated-types-path-2.rs:43:18
    |
 LL |     let _: i32 = f2(2i32);
    |            ---   ^^^^^^^^ expected `i32`, found `u32`
@@ -75,7 +91,7 @@ help: you can convert a `u32` to an `i32` and panic if the converted value doesn
 LL |     let _: i32 = f2(2i32).try_into().unwrap();
    |                          ++++++++++++++++++++
 
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.
index 501d2cfaa26b7978b66c585b2d159c71b99dcd54..3f180cf4f1f891ca81f235cb4114acd427a24697 100644 (file)
@@ -11,7 +11,7 @@ LL |     let x: () = <i8 as Foo<'static, 'static,  u8>>::bar::<'static, char>;
    |
    = note: expected unit type `()`
                 found fn item `fn() {<i8 as Foo<'static, 'static, u8>>::bar::<'static, char>}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
 LL |     let x: () = <i8 as Foo<'static, 'static,  u8>>::bar::<'static, char>();
    |                                                                         ++
@@ -29,7 +29,7 @@ LL |     let x: () = <i8 as Foo<'static, 'static,  u32>>::bar::<'static, char>;
    |
    = note: expected unit type `()`
                 found fn item `fn() {<i8 as Foo<'static, 'static>>::bar::<'static, char>}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
 LL |     let x: () = <i8 as Foo<'static, 'static,  u32>>::bar::<'static, char>();
    |                                                                          ++
@@ -47,7 +47,7 @@ LL |     let x: () = <i8 as Foo<'static, 'static,  u8>>::baz;
    |
    = note: expected unit type `()`
                 found fn item `fn() {<i8 as Foo<'static, 'static, u8>>::baz}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
 LL |     let x: () = <i8 as Foo<'static, 'static,  u8>>::baz();
    |                                                        ++
index ae3e862dddd206e5cb81460fe04e88dfc361edfa..16dd29de2c5438d9a7f695f7656e94d88fc17bf7 100644 (file)
@@ -11,7 +11,7 @@ LL |     let x: () = <i8 as Foo<'static, 'static,  u8>>::bar::<'static, char>;
    |
    = note: expected unit type `()`
                 found fn item `fn() {<i8 as Foo<ReStatic, ReStatic, u8>>::bar::<ReStatic, char>}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
 LL |     let x: () = <i8 as Foo<'static, 'static,  u8>>::bar::<'static, char>();
    |                                                                         ++
@@ -29,7 +29,7 @@ LL |     let x: () = <i8 as Foo<'static, 'static,  u32>>::bar::<'static, char>;
    |
    = note: expected unit type `()`
                 found fn item `fn() {<i8 as Foo<ReStatic, ReStatic>>::bar::<ReStatic, char>}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
 LL |     let x: () = <i8 as Foo<'static, 'static,  u32>>::bar::<'static, char>();
    |                                                                          ++
@@ -47,7 +47,7 @@ LL |     let x: () = <i8 as Foo<'static, 'static,  u8>>::baz;
    |
    = note: expected unit type `()`
                 found fn item `fn() {<i8 as Foo<ReStatic, ReStatic, u8>>::baz}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
 LL |     let x: () = <i8 as Foo<'static, 'static,  u8>>::baz();
    |                                                        ++
index c43ce2cadba046672c01a7e664572adae43c80a0..dcbe7765a9e1c4fd3d13f34a8e9b2f982f0a719c 100644 (file)
@@ -2,6 +2,9 @@
 
 // run-pass
 // edition:2018
+// revisions: normal drop-tracking
+// [normal]compile-flags: -Zdrop-tracking=no
+// [drop-tracking]compile-flags: -Zdrop-tracking
 
 #![allow(dead_code)]
 use std::future::Future;
diff --git a/src/test/ui/attributes/register-attr-tool-fail.rs b/src/test/ui/attributes/register-attr-tool-fail.rs
deleted file mode 100644 (file)
index 84736be..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#![feature(register_attr)]
-#![feature(register_tool)]
-
-#![register_attr] //~ ERROR malformed `register_attr` attribute input
-#![register_tool] //~ ERROR malformed `register_tool` attribute input
-
-#![register_attr(a::b)] //~ ERROR `register_attr` only accepts identifiers
-#![register_tool(a::b)] //~ ERROR `register_tool` only accepts identifiers
-
-#![register_attr(attr, attr)] //~ ERROR attribute `attr` was already registered
-#![register_tool(tool, tool)] //~ ERROR tool `tool` was already registered
-
-fn main() {}
diff --git a/src/test/ui/attributes/register-attr-tool-fail.stderr b/src/test/ui/attributes/register-attr-tool-fail.stderr
deleted file mode 100644 (file)
index 8f6977c..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-error: `register_attr` only accepts identifiers
-  --> $DIR/register-attr-tool-fail.rs:7:18
-   |
-LL | #![register_attr(a::b)]
-   |                  ^^^^ not an identifier
-
-error: attribute `attr` was already registered
-  --> $DIR/register-attr-tool-fail.rs:10:24
-   |
-LL | #![register_attr(attr, attr)]
-   |                  ----  ^^^^
-   |                  |
-   |                  already registered here
-
-error: `register_tool` only accepts identifiers
-  --> $DIR/register-attr-tool-fail.rs:8:18
-   |
-LL | #![register_tool(a::b)]
-   |                  ^^^^ not an identifier
-
-error: tool `tool` was already registered
-  --> $DIR/register-attr-tool-fail.rs:11:24
-   |
-LL | #![register_tool(tool, tool)]
-   |                  ----  ^^^^
-   |                  |
-   |                  already registered here
-
-error: malformed `register_attr` attribute input
-  --> $DIR/register-attr-tool-fail.rs:4:1
-   |
-LL | #![register_attr]
-   | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![register_attr(attr1, attr2, ...)]`
-
-error: malformed `register_tool` attribute input
-  --> $DIR/register-attr-tool-fail.rs:5:1
-   |
-LL | #![register_tool]
-   | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![register_tool(tool1, tool2, ...)]`
-
-error: aborting due to 6 previous errors
-
diff --git a/src/test/ui/attributes/register-attr-tool-import.rs b/src/test/ui/attributes/register-attr-tool-import.rs
deleted file mode 100644 (file)
index d3502c7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// edition:2018
-// compile-flags: -Zsave-analysis
-// ~^ Also regression test for #69588
-
-#![feature(register_attr)]
-#![feature(register_tool)]
-
-#![register_attr(attr)]
-#![register_tool(tool)]
-
-use attr as renamed_attr; // OK
-use tool as renamed_tool; // OK
-
-#[renamed_attr] //~ ERROR cannot use an explicitly registered attribute through an import
-#[renamed_tool::attr] //~ ERROR cannot use a tool module through an import
-                      //~| ERROR cannot use a tool module through an import
-fn main() {}
diff --git a/src/test/ui/attributes/register-attr-tool-import.stderr b/src/test/ui/attributes/register-attr-tool-import.stderr
deleted file mode 100644 (file)
index 90b7e16..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-error: cannot use an explicitly registered attribute through an import
-  --> $DIR/register-attr-tool-import.rs:14:3
-   |
-LL | #[renamed_attr]
-   |   ^^^^^^^^^^^^
-   |
-note: the explicitly registered attribute imported here
-  --> $DIR/register-attr-tool-import.rs:11:5
-   |
-LL | use attr as renamed_attr; // OK
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: cannot use a tool module through an import
-  --> $DIR/register-attr-tool-import.rs:15:3
-   |
-LL | #[renamed_tool::attr]
-   |   ^^^^^^^^^^^^
-   |
-note: the tool module imported here
-  --> $DIR/register-attr-tool-import.rs:12:5
-   |
-LL | use tool as renamed_tool; // OK
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: cannot use a tool module through an import
-  --> $DIR/register-attr-tool-import.rs:15:3
-   |
-LL | #[renamed_tool::attr]
-   |   ^^^^^^^^^^^^
-   |
-note: the tool module imported here
-  --> $DIR/register-attr-tool-import.rs:12:5
-   |
-LL | use tool as renamed_tool; // OK
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/ui/attributes/register-attr-tool-prelude.rs b/src/test/ui/attributes/register-attr-tool-prelude.rs
deleted file mode 100644 (file)
index d217a81..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#![feature(register_attr)]
-#![feature(register_tool)]
-
-#![register_attr(attr)]
-#![register_tool(tool)]
-
-#[no_implicit_prelude]
-mod m {
-    #[attr] //~ ERROR cannot find attribute `attr` in this scope
-    #[tool::attr] //~ ERROR failed to resolve: use of undeclared crate or module `tool`
-    fn check() {}
-}
-
-fn main() {}
diff --git a/src/test/ui/attributes/register-attr-tool-prelude.stderr b/src/test/ui/attributes/register-attr-tool-prelude.stderr
deleted file mode 100644 (file)
index 905b661..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0433]: failed to resolve: use of undeclared crate or module `tool`
-  --> $DIR/register-attr-tool-prelude.rs:10:7
-   |
-LL |     #[tool::attr]
-   |       ^^^^ use of undeclared crate or module `tool`
-
-error: cannot find attribute `attr` in this scope
-  --> $DIR/register-attr-tool-prelude.rs:9:7
-   |
-LL |     #[attr]
-   |       ^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/attributes/register-attr-tool-unused.rs b/src/test/ui/attributes/register-attr-tool-unused.rs
deleted file mode 100644 (file)
index 6806146..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#![deny(unused)]
-
-#![feature(register_attr)]
-#![feature(register_tool)]
-
-#[register_attr(attr)] //~ ERROR crate-level attribute should be an inner attribute
-#[register_tool(tool)] //~ ERROR crate-level attribute should be an inner attribute
-fn main() {}
diff --git a/src/test/ui/attributes/register-attr-tool-unused.stderr b/src/test/ui/attributes/register-attr-tool-unused.stderr
deleted file mode 100644 (file)
index 8d2e1b6..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/register-attr-tool-unused.rs:6:1
-   |
-LL | #[register_attr(attr)]
-   | ^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/register-attr-tool-unused.rs:1:9
-   |
-LL | #![deny(unused)]
-   |         ^^^^^^
-   = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]`
-
-error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/register-attr-tool-unused.rs:7:1
-   |
-LL | #[register_tool(tool)]
-   | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/attributes/register-attr-tool.rs b/src/test/ui/attributes/register-attr-tool.rs
deleted file mode 100644 (file)
index ee9da74..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// check-pass
-// compile-flags: --cfg foo
-
-#![feature(register_attr)]
-#![feature(register_tool)]
-
-#![register_attr(attr)]
-#![register_tool(tool)]
-#![register_tool(rustfmt, clippy)] // OK
-#![cfg_attr(foo, register_attr(conditional_attr))]
-#![cfg_attr(foo, register_tool(conditional_tool))]
-
-#[attr]
-#[tool::attr]
-#[rustfmt::attr]
-#[clippy::attr]
-#[conditional_attr]
-#[conditional_tool::attr]
-fn main() {}
diff --git a/src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs b/src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs
new file mode 100644 (file)
index 0000000..e8b4fe7
--- /dev/null
@@ -0,0 +1,31 @@
+#![feature(rustc_private)]
+extern crate libc;
+
+/// So tests don't have to bring libc in scope themselves
+pub enum SignalHandler {
+    Ignore,
+    Default,
+}
+
+/// Helper to assert that [`libc::SIGPIPE`] has the expected signal handler.
+pub fn assert_sigpipe_handler(expected_handler: SignalHandler) {
+    #[cfg(unix)]
+    #[cfg(not(any(
+        target_os = "emscripten",
+        target_os = "fuchsia",
+        target_os = "horizon",
+        target_os = "android",
+    )))]
+    {
+        let prev = unsafe { libc::signal(libc::SIGPIPE, libc::SIG_IGN) };
+
+        let expected = match expected_handler {
+            SignalHandler::Ignore => libc::SIG_IGN,
+            SignalHandler::Default => libc::SIG_DFL,
+        };
+        assert_eq!(prev, expected);
+
+        // Unlikely to matter, but restore the old value anyway
+        unsafe { libc::signal(libc::SIGPIPE, prev); };
+    }
+}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-crate.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-crate.rs
new file mode 100644 (file)
index 0000000..d6d020c
--- /dev/null
@@ -0,0 +1,4 @@
+#![feature(unix_sigpipe)]
+#![unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute cannot be used at crate level
+
+fn main() {}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-crate.stderr b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-crate.stderr
new file mode 100644 (file)
index 0000000..a1fb4d6
--- /dev/null
@@ -0,0 +1,13 @@
+error: `unix_sigpipe` attribute cannot be used at crate level
+  --> $DIR/unix_sigpipe-crate.rs:2:1
+   |
+LL | #![unix_sigpipe = "inherit"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[unix_sigpipe = "inherit"]
+   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.rs
new file mode 100644 (file)
index 0000000..294cb38
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "sig_ign"]
+#[unix_sigpipe = "inherit"] //~ error: multiple `unix_sigpipe` attributes
+fn main() {}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.stderr b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-duplicates.stderr
new file mode 100644 (file)
index 0000000..2362c17
--- /dev/null
@@ -0,0 +1,14 @@
+error: multiple `unix_sigpipe` attributes
+  --> $DIR/unix_sigpipe-duplicates.rs:4:1
+   |
+LL | #[unix_sigpipe = "inherit"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/unix_sigpipe-duplicates.rs:3:1
+   |
+LL | #[unix_sigpipe = "sig_ign"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-error.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-error.rs
new file mode 100644 (file)
index 0000000..0a42a5b
--- /dev/null
@@ -0,0 +1,13 @@
+// run-pass
+// aux-build:sigpipe-utils.rs
+
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "sig_ign"]
+fn main() {
+    extern crate sigpipe_utils;
+
+    // #[unix_sigpipe = "sig_ign"] is active, so the legacy behavior of ignoring
+    // SIGPIPE shall be in effect
+    sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
+}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-inherit.rs
new file mode 100644 (file)
index 0000000..4f86480
--- /dev/null
@@ -0,0 +1,14 @@
+// run-pass
+// aux-build:sigpipe-utils.rs
+
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "inherit"]
+fn main() {
+    extern crate sigpipe_utils;
+
+    // #[unix_sigpipe = "inherit"] is active, so SIGPIPE shall NOT be ignored,
+    // instead the default handler shall be installed. (We assume that the
+    // process that runs these tests have the default handler.)
+    sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
+}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-list.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-list.rs
new file mode 100644 (file)
index 0000000..b5ebc07
--- /dev/null
@@ -0,0 +1,4 @@
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe(inherit)] //~ error: malformed `unix_sigpipe` attribute input
+fn main() {}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-list.stderr b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-list.stderr
new file mode 100644 (file)
index 0000000..59a87e1
--- /dev/null
@@ -0,0 +1,15 @@
+error: malformed `unix_sigpipe` attribute input
+  --> $DIR/unix_sigpipe-list.rs:3:1
+   |
+LL | #[unix_sigpipe(inherit)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: the following are the possible correct uses
+   |
+LL | #[unix_sigpipe = "inherit|sig_ign|sig_dfl"]
+   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | #[unix_sigpipe]
+   | ~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.rs
new file mode 100644 (file)
index 0000000..cde6719
--- /dev/null
@@ -0,0 +1,6 @@
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
+fn f() {}
+
+fn main() {}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.stderr b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-main-fn.stderr
new file mode 100644 (file)
index 0000000..c4b8111
--- /dev/null
@@ -0,0 +1,8 @@
+error: `unix_sigpipe` attribute can only be used on `fn main()`
+  --> $DIR/unix_sigpipe-non-main-fn.rs:3:1
+   |
+LL | #[unix_sigpipe = "inherit"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.rs
new file mode 100644 (file)
index 0000000..16f7276
--- /dev/null
@@ -0,0 +1,8 @@
+#![feature(unix_sigpipe)]
+
+mod m {
+    #[unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute can only be used on root `fn main()`
+    fn main() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.stderr b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-non-root-main.stderr
new file mode 100644 (file)
index 0000000..a04f605
--- /dev/null
@@ -0,0 +1,8 @@
+error: `unix_sigpipe` attribute can only be used on root `fn main()`
+  --> $DIR/unix_sigpipe-non-root-main.rs:4:5
+   |
+LL |     #[unix_sigpipe = "inherit"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-not-used.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-not-used.rs
new file mode 100644 (file)
index 0000000..100b4ce
--- /dev/null
@@ -0,0 +1,9 @@
+// run-pass
+// aux-build:sigpipe-utils.rs
+
+fn main() {
+    extern crate sigpipe_utils;
+
+    // SIGPIPE shall be ignored since #[unix_sigpipe = "..."] is not used
+    sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
+}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-only-feature.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-only-feature.rs
new file mode 100644 (file)
index 0000000..b5adc2e
--- /dev/null
@@ -0,0 +1,13 @@
+// run-pass
+// aux-build:sigpipe-utils.rs
+
+#![feature(unix_sigpipe)]
+
+fn main() {
+    extern crate sigpipe_utils;
+
+    // Only #![feature(unix_sigpipe)] is enabled, not #[unix_sigpipe = "..."].
+    // This shall not change any behavior, so we still expect SIGPIPE to be
+    // ignored
+    sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Ignore);
+}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-rustc_main.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-rustc_main.rs
new file mode 100644 (file)
index 0000000..6befb9e
--- /dev/null
@@ -0,0 +1,15 @@
+// run-pass
+// aux-build:sigpipe-utils.rs
+
+#![feature(unix_sigpipe)]
+#![feature(rustc_attrs)]
+
+#[unix_sigpipe = "sig_dfl"]
+#[rustc_main]
+fn rustc_main() {
+    extern crate sigpipe_utils;
+
+    // #[unix_sigpipe = "sig_dfl"] is active, so SIGPIPE handler shall be
+    // SIG_DFL. Note that we have a #[rustc_main], but it should still work.
+    sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
+}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-sig_dfl.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-sig_dfl.rs
new file mode 100644 (file)
index 0000000..238c0d5
--- /dev/null
@@ -0,0 +1,13 @@
+// run-pass
+// aux-build:sigpipe-utils.rs
+
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "sig_dfl"]
+fn main() {
+    extern crate sigpipe_utils;
+
+    // #[unix_sigpipe = "sig_dfl"] is active, so SIGPIPE shall NOT be ignored, instead
+    // the default handler shall be installed
+    sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default);
+}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-start.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-start.rs
new file mode 100644 (file)
index 0000000..64fd5ec
--- /dev/null
@@ -0,0 +1,6 @@
+#![feature(start)]
+#![feature(unix_sigpipe)]
+
+#[start]
+#[unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
+fn custom_start(argc: isize, argv: *const *const u8) -> isize { 0 }
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-start.stderr b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-start.stderr
new file mode 100644 (file)
index 0000000..2c9ce47
--- /dev/null
@@ -0,0 +1,8 @@
+error: `unix_sigpipe` attribute can only be used on `fn main()`
+  --> $DIR/unix_sigpipe-start.rs:5:1
+   |
+LL | #[unix_sigpipe = "inherit"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-struct.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-struct.rs
new file mode 100644 (file)
index 0000000..a5e47cf
--- /dev/null
@@ -0,0 +1,6 @@
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "inherit"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
+struct S;
+
+fn main() {}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-struct.stderr b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-struct.stderr
new file mode 100644 (file)
index 0000000..c56ee60
--- /dev/null
@@ -0,0 +1,8 @@
+error: `unix_sigpipe` attribute can only be used on `fn main()`
+  --> $DIR/unix_sigpipe-struct.rs:3:1
+   |
+LL | #[unix_sigpipe = "inherit"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.rs
new file mode 100644 (file)
index 0000000..4ec25de
--- /dev/null
@@ -0,0 +1,4 @@
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe = "wrong"] //~ error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+fn main() {}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.stderr b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe-wrong.stderr
new file mode 100644 (file)
index 0000000..a66e45a
--- /dev/null
@@ -0,0 +1,8 @@
+error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+  --> $DIR/unix_sigpipe-wrong.rs:3:1
+   |
+LL | #[unix_sigpipe = "wrong"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe.rs b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe.rs
new file mode 100644 (file)
index 0000000..7bf1c73
--- /dev/null
@@ -0,0 +1,4 @@
+#![feature(unix_sigpipe)]
+
+#[unix_sigpipe] //~ error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+fn main() {}
diff --git a/src/test/ui/attributes/unix_sigpipe/unix_sigpipe.stderr b/src/test/ui/attributes/unix_sigpipe/unix_sigpipe.stderr
new file mode 100644 (file)
index 0000000..1b1eda8
--- /dev/null
@@ -0,0 +1,8 @@
+error: valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+  --> $DIR/unix_sigpipe.rs:3:1
+   |
+LL | #[unix_sigpipe]
+   | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 5477a5762a8fd0fc424ff3fbb5ffd11605c1d175..a334bd8562593d9f4550968b107579a0d982a0f6 100644 (file)
@@ -5,6 +5,11 @@ LL |     if foo == y {}
    |        --- ^^ - _
    |        |
    |        for<'r> fn(&'r i32) -> &'r i32 {foo}
+   |
+help: use parentheses to call this function
+   |
+LL |     if foo(/* &i32 */) == y {}
+   |           ++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs b/src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs
new file mode 100644 (file)
index 0000000..5244592
--- /dev/null
@@ -0,0 +1,8 @@
+fn main() {
+    let mut vec: Vec<i32> = Vec::new();
+    let closure = move || {
+        vec.clear();
+        let mut iter = vec.iter();
+        move || { iter.next() } //~ ERROR captured variable cannot escape `FnMut` closure bod
+    };
+}
diff --git a/src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr b/src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr
new file mode 100644 (file)
index 0000000..78ca090
--- /dev/null
@@ -0,0 +1,18 @@
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs:6:9
+   |
+LL |     let mut vec: Vec<i32> = Vec::new();
+   |         ------- variable defined here
+LL |     let closure = move || {
+   |                         - inferred to be a `FnMut` closure
+LL |         vec.clear();
+   |         --- variable captured here
+LL |         let mut iter = vec.iter();
+LL |         move || { iter.next() }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
+   |
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
+
+error: aborting due to previous error
+
index 3d395d1f264a0d8407b3c17ca2e3cc08188ba12b..da238205b402f1562159a05fc91c7d64dd062e86 100644 (file)
@@ -131,13 +131,13 @@ fn coerce_index_op() {
     let mut i = I(10);
     i[i[3]] = 4;
     //~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
-    // Shoud be accepted with g2p
+    // Should be accepted with g2p
 
     i[3] = i[4];
 
     i[i[3]] = i[4];
     //~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
-    // Shoud be accepted with g2p
+    // Should be accepted with g2p
 }
 
 fn main() {
index e0f4afa75276dbc3d98549ec145eb7735d98467d..0463e22b3c2d16bc8555d1d18d1d51481d0c5261 100644 (file)
@@ -40,6 +40,6 @@ fn main() {
     //
     // (At least in theory; part of the reason this test fails is that
     // the constructed MIR throws in extra &mut reborrows which
-    // flummoxes our attmpt to delay the activation point here.)
+    // flummoxes our attempt to delay the activation point here.)
     delay.push(2);
 }
index bdfbc3d54a2c58ec3d8af494a8d5751132cabcc9..8fadcc1f9f06c2261e590c528922e5d8cc482e61 100644 (file)
@@ -1,2 +1,2 @@
-error: invalid `--check-cfg` argument: `names("NOT_IDENT")` (`names()` arguments must be simple identifers)
+error: invalid `--check-cfg` argument: `names("NOT_IDENT")` (`names()` arguments must be simple identifiers)
 
index b25882baaf3e634d135217138a34a074b588297f..061d3f0e971c32e724fbee8cfb02b6fe9f3f18b8 100644 (file)
@@ -1,2 +1,2 @@
-error: invalid `--check-cfg` argument: `values("NOT_IDENT")` (`values()` first argument must be a simple identifer)
+error: invalid `--check-cfg` argument: `values("NOT_IDENT")` (`values()` first argument must be a simple identifier)
 
index 93131b2ac4e4d47999a4f761a9953b9cfc64c9e0..f97e60daf43a88afbefcbd5046ff5a3725666cdb 100644 (file)
@@ -68,7 +68,7 @@ fn arrays_5() {
         arr[1] += 10;
     };
 
-    // c will capture `arr` completely, therefore we cannot borrow other indecies
+    // c will capture `arr` completely, therefore we cannot borrow other indices
     // into the array.
     println!("{:#?}", &arr[3..2]);
     //~^ ERROR: cannot borrow `arr` as immutable because it is also borrowed as mutable
index 3ed780f51c73b6b6f4a54130faccad04c9afbdfc..f23670f63acb7d0f5f63a68797a6d8c0192bf94a 100644 (file)
@@ -31,7 +31,7 @@ struct Foo { x: u8, y: u8 }
     c();
 }
 
-// `String`, `u16` are not aligned at a one byte boundry and are thus affected by repr(packed).
+// `String`, `u16` are not aligned at a one byte boundary and are thus affected by repr(packed).
 //
 // Here we test that the closure doesn't capture a reference point to `foo.x` but
 // rather capture `foo` entirely.
index 2c828aed528bfcb98c09731835fb5c1dc968a091..f8752fe1cec0407a18b7021cbcaa9087f96fc523 100644 (file)
@@ -1,8 +1,8 @@
 // edition:2021
 // run-pass
 
-// Test that ByValue captures compile sucessefully especially when the captures are
-// derefenced within the closure.
+// Test that ByValue captures compile successfully especially when the captures are
+// dereferenced within the closure.
 
 #[derive(Debug, Default)]
 struct SomeLargeType;
index 88a9816a05263b4024f4f18b299c2fb52da371aa..03400e0ee8d56fdd8bacc323eca72dbb49c25a31 100644 (file)
@@ -1,7 +1,7 @@
 // edition:2021
 // run-pass
 
-// Tests that if a closure uses indivual fields of the same object
+// Tests that if a closure uses individual fields of the same object
 // then that case is handled properly.
 
 #![allow(unused)]
index b8e464031813bd42a71e8966570c7fe8e96827ab..624e0ff22568d73227054e1605896a23014ff689 100644 (file)
@@ -1,10 +1,10 @@
 // edition:2021
 // run-pass
 
-// Test that closures can catpure paths that are more precise than just one level
+// Test that closures can capture paths that are more precise than just one level
 // from the root variable.
 //
-// If the closures can handle such precison we should be able to mutate one path in the closure
+// If the closures can handle such precision we should be able to mutate one path in the closure
 // while being able to mutate another path outside the closure, where the two paths are disjoint
 // after applying two projections on the root variable.
 
index 11a324d8a34e361c7da8db413e55b22ba87ad153..bd8addd37812a10edab027e12855701a8e98dd2d 100644 (file)
@@ -3,7 +3,7 @@
 
 #![allow(unused)]
 
-// If the closures can handle such precison we should be able to read one path in the closure
+// If the closures can handle such precision we should be able to read one path in the closure
 // while being able mutate another path outside the closure, where the two paths are disjoint
 // after applying two projections on the root variable.
 
index bb784774b8cd439180a05d2a6e12e15db57b6982..a85335438a9fbd301c40d0aa003ed7e499028017 100644 (file)
@@ -5,7 +5,7 @@
 // that is captured by the closure
 
 // More specifically we test that the if the mutable reference isn't root variable of a capture
-// but rather accessed while acessing the precise capture.
+// but rather accessed while accessing the precise capture.
 
 fn mut_tuple() {
     let mut t = (10, 10);
index f81d7cfaa654bc9efe1976840968d2a86e8786fe..30733871b855f0fadf41a883c777fa476f208a30 100644 (file)
@@ -1,5 +1,5 @@
 // test for issue 84128
-// missing suggestion for similar ADT type with diffetent generic paramenter
+// missing suggestion for similar ADT type with diffetent generic parameter
 // on closure ReturnNoExpression
 
 struct Foo<T>(T);
diff --git a/src/test/ui/coercion/issue-101066.rs b/src/test/ui/coercion/issue-101066.rs
new file mode 100644 (file)
index 0000000..b658ed1
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+use std::convert::TryFrom;
+
+pub trait FieldElement {
+    type Integer: TryFrom<usize, Error = std::num::TryFromIntError>;
+
+    fn valid_integer_try_from<N>(i: N) -> Result<Self::Integer, ()>
+    where
+        Self::Integer: TryFrom<N>,
+    {
+        Self::Integer::try_from(i).map_err(|_| ())
+    }
+}
+
+fn main() {}
index 91d8e4f381a368af580596eacf6a6bd236212725..69a0b486d689f8585b3dfd953e1f07bab7b56fc4 100644 (file)
@@ -18,7 +18,7 @@ fn main() {
     let exe = me.file_name().unwrap();
     let cwd = me.parent().unwrap();
     eprintln!("cwd={:?}", cwd);
-    // Change directory to where the exectuable is located, since this test
+    // Change directory to where the executable is located, since this test
     // fundamentally needs to use relative paths. In some cases (like
     // remote-test-server), the current_dir can be somewhere else, so make
     // sure it is something we can use. We assume we can write to this
index b1b359619dcfabb83144f4b2f563f4bef0f6d7b6..d955b4f9651daa4906530e94bb19a0278ac331af 100644 (file)
@@ -2,15 +2,22 @@ error[E0107]: this associated function takes 0 generic arguments but 1 generic a
   --> $DIR/invalid-const-arg-for-type-param.rs:6:23
    |
 LL |     let _: u32 = 5i32.try_into::<32>().unwrap();
-   |                       ^^^^^^^^------ help: remove these generics
-   |                       |
-   |                       expected 0 generic arguments
+   |                       ^^^^^^^^ expected 0 generic arguments
    |
 note: associated function defined here, with 0 generic parameters
   --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
    |
 LL |     fn try_into(self) -> Result<T, Self::Error>;
    |        ^^^^^^^^
+help: consider moving this generic argument to the `TryInto` trait, which takes up to 1 argument
+   |
+LL |     let _: u32 = TryInto::<32>::try_into(5i32).unwrap();
+   |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: remove these generics
+   |
+LL -     let _: u32 = 5i32.try_into::<32>().unwrap();
+LL +     let _: u32 = 5i32.try_into().unwrap();
+   |
 
 error[E0599]: no method named `f` found for struct `S` in the current scope
   --> $DIR/invalid-const-arg-for-type-param.rs:9:7
index c488a663fbb002167bc811f735dc594ed21c798f..73c9301011d58693e52f12d50925c538d706d58f 100644 (file)
@@ -1,5 +1,5 @@
 // regression test for #83466- tests that generic arg mismatch errors between
-// consts and types are not supressed when there are explicit late bound lifetimes
+// consts and types are not suppressed when there are explicit late bound lifetimes
 
 struct S;
 impl S {
index f3bf9c496da7b2aa12aca64b2d53dd8ec7aa7349..82a3c92e66fdf08eb11440a71186f5d66bed67cb 100644 (file)
@@ -55,9 +55,10 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:27:1
    |
 LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾─ALLOC_ID─╼ 04 00 00 00                         │ ╾──╼....
            }
@@ -170,9 +171,10 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:57:1
    |
 LL | pub static R5: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾ALLOC_ID─╼ 04 00 00 00                         │ ╾──╼....
            }
index 5f2821a91937baa712e7ed4d81449b244cce8b5e..f88746af9769d9dac28b853d7eeaa145a34b2c3a 100644 (file)
@@ -55,9 +55,10 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:27:1
    |
 LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾───────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
            }
@@ -170,9 +171,10 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/forbidden_slices.rs:57:1
    |
 LL | pub static R5: &[u8] = unsafe {
-   | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾──────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
            }
index 82afa70309da04a8ec8c3428150fafc39ff18519..12d5b7bd6bbc270a6b2998806b99a0149c9d7f19 100644 (file)
@@ -7,6 +7,8 @@ LL |     const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:30:43
@@ -16,6 +18,8 @@ LL |     const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:34:45
@@ -25,6 +29,8 @@ LL |     const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uin
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:38:45
@@ -34,6 +40,8 @@ LL |     const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uin
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:42:45
@@ -43,6 +51,8 @@ LL |     const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uin
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:46:47
@@ -58,6 +68,8 @@ LL |     const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:54:45
@@ -67,6 +79,8 @@ LL |     const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:58:45
@@ -76,6 +90,8 @@ LL |     const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:62:45
@@ -85,6 +101,8 @@ LL |     const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-pointer-values-in-various-types.rs:66:47
@@ -100,6 +118,8 @@ LL |     const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.flo
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:74:45
@@ -109,6 +129,8 @@ LL |     const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.flo
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:78:47
@@ -118,6 +140,8 @@ LL |     const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.t
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:82:47
@@ -127,6 +151,8 @@ LL |     const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.c
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:86:39
@@ -136,6 +162,8 @@ LL |     const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:90:41
@@ -145,6 +173,8 @@ LL |     const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:94:41
@@ -154,6 +184,8 @@ LL |     const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:98:41
@@ -163,6 +195,8 @@ LL |     const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:102:43
@@ -172,6 +206,8 @@ LL |     const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_12
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:106:39
@@ -181,6 +217,8 @@ LL |     const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:110:41
@@ -190,6 +228,8 @@ LL |     const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:114:41
@@ -199,6 +239,8 @@ LL |     const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:118:41
@@ -208,6 +250,8 @@ LL |     const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:122:43
@@ -217,6 +261,8 @@ LL |     const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:126:41
@@ -226,6 +272,8 @@ LL |     const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:130:41
@@ -235,6 +283,8 @@ LL |     const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:134:43
@@ -244,6 +294,8 @@ LL |     const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/const-pointer-values-in-various-types.rs:138:43
@@ -253,6 +305,8 @@ LL |     const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.charact
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error: aborting due to 29 previous errors
 
@@ -267,6 +321,8 @@ LL |     const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -278,6 +334,8 @@ LL |     const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -289,6 +347,8 @@ LL |     const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uin
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -300,6 +360,8 @@ LL |     const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uin
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -311,6 +373,8 @@ LL |     const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uin
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -322,6 +386,8 @@ LL |     const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -333,6 +399,8 @@ LL |     const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -344,6 +412,8 @@ LL |     const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -355,6 +425,8 @@ LL |     const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -366,6 +438,8 @@ LL |     const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.flo
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -377,6 +451,8 @@ LL |     const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.flo
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -388,6 +464,8 @@ LL |     const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.t
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -399,6 +477,8 @@ LL |     const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.c
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -410,6 +490,8 @@ LL |     const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -421,6 +503,8 @@ LL |     const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -432,6 +516,8 @@ LL |     const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -443,6 +529,8 @@ LL |     const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -454,6 +542,8 @@ LL |     const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_12
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -465,6 +555,8 @@ LL |     const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -476,6 +568,8 @@ LL |     const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -487,6 +581,8 @@ LL |     const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -498,6 +594,8 @@ LL |     const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -509,6 +607,8 @@ LL |     const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -520,6 +620,8 @@ LL |     const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -531,6 +633,8 @@ LL |     const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -542,6 +646,8 @@ LL |     const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -553,4 +659,6 @@ LL |     const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.charact
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
index b007dda246de333b5c7fce8f338e5210d4d88e6f..75e50a27b3a83f5fcc1e1d3f9cb60910b119e810 100644 (file)
@@ -10,6 +10,8 @@ LL |         *(ptr as *mut u8) = 123;
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error: aborting due to previous error
 
@@ -26,4 +28,6 @@ LL |         *(ptr as *mut u8) = 123;
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
index 0e3743588100983b534c15dd97e7602469a258b0..30935e41549bf2654444adf607a476de4c9e9a14 100644 (file)
@@ -7,6 +7,8 @@ LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error: could not evaluate constant pattern
   --> $DIR/ref_to_int_match.rs:7:14
@@ -32,4 +34,6 @@ LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
index 0e3743588100983b534c15dd97e7602469a258b0..30935e41549bf2654444adf607a476de4c9e9a14 100644 (file)
@@ -7,6 +7,8 @@ LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error: could not evaluate constant pattern
   --> $DIR/ref_to_int_match.rs:7:14
@@ -32,4 +34,6 @@ LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
index 1e80dd7c765daedcf5aeda0ab15dc509d351f13a..752fd01f33805ee6ae19741b45a06e9ccd51f3ad 100644 (file)
@@ -18,6 +18,8 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/ub-enum.rs:30:1
@@ -27,6 +29,8 @@ LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:43:1
@@ -47,6 +51,8 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/ub-enum.rs:49:1
@@ -56,6 +62,8 @@ LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:59:42
@@ -71,6 +79,8 @@ LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:82:1
@@ -130,6 +140,8 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -141,6 +153,8 @@ LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -152,6 +166,8 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -163,6 +179,8 @@ LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -174,4 +192,6 @@ LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
index a6208f30c22a068204c2ab161c9025fe8a0afc37..3f1546a2786cac77cf847503b112c91182a53639 100644 (file)
@@ -18,6 +18,8 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/ub-enum.rs:30:1
@@ -27,6 +29,8 @@ LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:43:1
@@ -47,6 +51,8 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/ub-enum.rs:49:1
@@ -56,6 +62,8 @@ LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/ub-enum.rs:59:42
@@ -71,6 +79,8 @@ LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:82:1
@@ -130,6 +140,8 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -141,6 +153,8 @@ LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -152,6 +166,8 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -163,6 +179,8 @@ LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -174,4 +192,6 @@ LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
index 0e8744e790f6bdf95fb6cd99d31ac255b34a2d22..d8dc6d057a73d94675516cccc12ee55d876d3740 100644 (file)
@@ -93,7 +93,7 @@ enum UninhDiscriminant {
 //~^ ERROR is undefined behavior
 
 // All variants are uninhabited but also have data.
-// Use `0` as constant to make behavior endianess-independent.
+// Use `0` as constant to make behavior endianness-independent.
 const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
 //~^ ERROR evaluation of constant value failed
 const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
index 25560d8003d436f11463656bb9388a49611ee609..3e93219c86dc1542d587fbb3bbb141943a30d231 100644 (file)
@@ -51,6 +51,8 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/ub-ref-ptr.rs:35:39
@@ -60,6 +62,8 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/ub-ref-ptr.rs:35:38
@@ -78,6 +82,8 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/ub-ref-ptr.rs:41:85
@@ -168,6 +174,8 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -179,6 +187,8 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -201,6 +211,8 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
index 8c86ddbfa5f9b92764fd0ab89923a32ae855dda0..bc2aa12a2f31e6e20c243549f2756409d32b1df2 100644 (file)
@@ -51,6 +51,8 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/ub-ref-ptr.rs:35:39
@@ -60,6 +62,8 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/ub-ref-ptr.rs:35:38
@@ -78,6 +82,8 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/ub-ref-ptr.rs:41:85
@@ -168,6 +174,8 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -179,6 +187,8 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -201,6 +211,8 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
index 09a877400d0a36b74501d84efac1c87b418f6144..4cd974e7bf97783c31a111866392eb29dcac816c 100644 (file)
@@ -29,6 +29,8 @@ LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/ub-wide-ptr.rs:46:1
@@ -38,6 +40,8 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:49:1
@@ -108,6 +112,8 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:80:1
@@ -128,6 +134,8 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:88:1
@@ -315,6 +323,8 @@ LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -326,6 +336,8 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -337,6 +349,8 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -348,6 +362,8 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
index 79fa7a83e84459db7e6d7137f088d5a1d51fbda9..1d84b7bce1410abb01ac8b745ddbe950397bf4bc 100644 (file)
@@ -29,6 +29,8 @@ LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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/ub-wide-ptr.rs:46:1
@@ -38,6 +40,8 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:49:1
@@ -108,6 +112,8 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:80:1
@@ -128,6 +134,8 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:88:1
@@ -315,6 +323,8 @@ LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -326,6 +336,8 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -337,6 +349,8 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -348,6 +362,8 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
index 97c9e1505197f72c9f8554b6a133bff6bd8afa67..86fbadb946d53d0f2c46a1df0e4c3479e9b1f6c3 100644 (file)
 
 const INVALID_PTR_IN_INT: () = unsafe {
     let _x: usize = transmute(&3u8);
-    //[with_flag]~^ ERROR: evaluation of constant value failed
-    //[with_flag]~| invalid value
+    //[with_flag]~^ ERROR: any use of this value will cause an error
+    //[with_flag]~| previously accepted
 };
 
 const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe {
     let x: &[u8] = &[0; 32];
     let _x: (usize, usize) = transmute(x);
-    //[with_flag]~^ ERROR: evaluation of constant value failed
-    //[with_flag]~| invalid value
+    //[with_flag]~^ ERROR: any use of this value will cause an error
+    //[with_flag]~| previously accepted
 };
 
 const UNALIGNED_PTR: () = unsafe {
index b940a77f8a5090e5bad204970493e587f1e1f2ff..793725d3b80fcdbcd41f3baa77bbed2fb3d9d7ef 100644 (file)
@@ -4,17 +4,33 @@ error[E0080]: evaluation of constant value failed
 LL |     let _x: bool = transmute(3u8);
    |                    ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean
 
-error[E0080]: evaluation of constant value failed
+error: any use of this value will cause an error
   --> $DIR/detect-extra-ub.rs:15:21
    |
+LL | const INVALID_PTR_IN_INT: () = unsafe {
+   | ----------------------------
 LL |     let _x: usize = transmute(&3u8);
-   |                     ^^^^^^^^^^^^^^^ constructing invalid value: encountered (potentially part of) a pointer, but expected an integer
+   |                     ^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
-error[E0080]: evaluation of constant value failed
+error: any use of this value will cause an error
   --> $DIR/detect-extra-ub.rs:22:30
    |
+LL | const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe {
+   | ------------------------------------------
+LL |     let x: &[u8] = &[0; 32];
 LL |     let _x: (usize, usize) = transmute(x);
-   |                              ^^^^^^^^^^^^ constructing invalid value at .0: encountered (potentially part of) a pointer, but expected an integer
+   |                              ^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/detect-extra-ub.rs:28:20
@@ -49,7 +65,6 @@ LL | const UNALIGNED_READ: () = {
 LL |     INNER;
    |     ^^^^^ referenced constant has errors
    |
-   = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
@@ -57,6 +72,37 @@ error: aborting due to 6 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/detect-extra-ub.rs:15:21
+   |
+LL | const INVALID_PTR_IN_INT: () = unsafe {
+   | ----------------------------
+LL |     let _x: usize = transmute(&3u8);
+   |                     ^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/detect-extra-ub.rs:22:30
+   |
+LL | const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe {
+   | ------------------------------------------
+LL |     let x: &[u8] = &[0; 32];
+LL |     let _x: (usize, usize) = transmute(x);
+   |                              ^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
+
+Future breakage diagnostic:
 error: any use of this value will cause an error
   --> $DIR/detect-extra-ub.rs:34:5
    |
index c810c8a7848c7d17bff33c4bea80d372f49c13f5..2776e2b6fa21f8a13b820be41dd3fe25c383852a 100644 (file)
@@ -2,9 +2,10 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/issue-83182.rs:5:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered a pointer in `str`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 8, align: 4) {
                ╾─alloc4──╼ 01 00 00 00                         │ ╾──╼....
            }
index 5fc2c934474dc37f3c26d176056c838f632e868f..9e884ce12890b379b1c96115ddc767b05bd694b5 100644 (file)
@@ -2,9 +2,10 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/issue-83182.rs:5:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered a pointer in `str`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: the raw bytes of the constant (size: 16, align: 8) {
                ╾───────alloc4────────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
            }
index 292765843048c80022419bb76dcfdf133a1a13e5..2536d2f08f288864cdcad95ded56a105f2fc8f2f 100644 (file)
@@ -4,5 +4,4 @@
 struct MyStr(str);
 const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
 //~^ ERROR: it is undefined behavior to use this value
-//~| constructing invalid value at .<deref>.0: encountered a pointer in `str`
 fn main() {}
index 2b23626e3d709087e3e14002e6be9612de053c6e..29e0ea950264046dfe1025f4694fa6f68091f6ef 100644 (file)
@@ -1,4 +1,5 @@
 // error-pattern unable to turn pointer into raw bytes
+// normalize-stderr-test: "alloc[0-9]+\+0x[a-z0-9]+" -> "ALLOC"
 #![feature(const_ptr_read)]
 
 const C: () = unsafe {
index afcf11bd5f2479826fe774d35988eba465de8d23..0f0539e09799eff4404dae2947cfdab95ca62507 100644 (file)
@@ -4,12 +4,12 @@ error: any use of this value will cause an error
 LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |         |
-   |         unable to turn pointer into raw bytes
+   |         unable to copy parts of a pointer from memory at ALLOC
    |         inside `std::ptr::read::<u8>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |         inside `ptr::const_ptr::<impl *const u8>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |         inside `C` at $DIR/issue-miri-1910.rs:7:5
+   |         inside `C` at $DIR/issue-miri-1910.rs:8:5
    |
-  ::: $DIR/issue-miri-1910.rs:4:1
+  ::: $DIR/issue-miri-1910.rs:5:1
    |
 LL | const C: () = unsafe {
    | -----------
@@ -17,6 +17,8 @@ LL | const C: () = unsafe {
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error: aborting due to previous error
 
@@ -27,12 +29,12 @@ error: any use of this value will cause an error
 LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |         |
-   |         unable to turn pointer into raw bytes
+   |         unable to copy parts of a pointer from memory at ALLOC
    |         inside `std::ptr::read::<u8>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |         inside `ptr::const_ptr::<impl *const u8>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |         inside `C` at $DIR/issue-miri-1910.rs:7:5
+   |         inside `C` at $DIR/issue-miri-1910.rs:8:5
    |
-  ::: $DIR/issue-miri-1910.rs:4:1
+  ::: $DIR/issue-miri-1910.rs:5:1
    |
 LL | const C: () = unsafe {
    | -----------
@@ -40,4 +42,6 @@ LL | const C: () = unsafe {
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
index 13e6af36e0200225f5277c4937d5e10c196e636e..6a19b294585ae038bf6edfc87a432e6996dde9d7 100644 (file)
@@ -8,7 +8,7 @@
 static PTR_INT_CAST: () = {
     let x = &0 as *const _ as usize;
     //~^ ERROR could not evaluate static initializer
-    //~| "exposing pointers" needs an rfc before being allowed inside constants
+    //~| exposing pointers
     let _v = x == x;
 };
 
@@ -19,4 +19,7 @@
     //~| unable to turn pointer into raw bytes
 };
 
+// I'd love to test pointer comparison, but that is not possible since
+// their `PartialEq` impl is non-`const`.
+
 fn main() {}
index 00cff23fb3fbe4471c490bdd82afa3a4424fc7b8..e0c4fa17585a9127836073e2203222feddde3a26 100644 (file)
@@ -2,13 +2,16 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/ptr_arith.rs:9:13
    |
 LL |     let x = &0 as *const _ as usize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^ "exposing pointers" needs an rfc before being allowed inside constants
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ exposing pointers is not possible at compile-time
 
 error[E0080]: could not evaluate static initializer
   --> $DIR/ptr_arith.rs:17:14
    |
 LL |     let _v = x + 0;
    |              ^ unable to turn pointer into raw bytes
+   |
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 warning: skipping const checks
    |
index 67b9fec4a0e11e0392b26562a6bdc56d59e080d0..1d47f243f01cdeb6c4b5b7cdf3cc0ee12c34918c 100644 (file)
@@ -27,6 +27,8 @@ LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) +
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = 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
@@ -36,6 +38,8 @@ LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error: aborting due to 4 previous errors
 
@@ -50,6 +54,8 @@ LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) +
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 Future breakage diagnostic:
 error: any use of this value will cause an error
@@ -61,4 +67,6 @@ LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4
    = note: `#[deny(const_err)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = help: this code performed an operation that depends on the underlying bytes representing a pointer
+   = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
index b92449c6e0aff6776e77d51a8efcc9a96e22b265..128087f1e375522297267296a093509774bb30e1 100644 (file)
@@ -10,10 +10,6 @@ LL |     let _y = x.clone();
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
            candidate #1: `Clone`
-help: one of the expressions' fields has a method of the same name
-   |
-LL |     let _y = x.i.clone();
-   |                ++
 
 error: aborting due to previous error
 
index 01f862ed516e9d9ef25735436c67c6e8891cc65b..0d6f4d0209f71b200e4cf1f224ecd2b7c7208add 100644 (file)
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/dst-bad-coercions.rs:14:17
    |
 LL |     let y: &S = x;
-   |            --   ^ expected `&S`, found *-ptr
+   |            --   ^ expected `&S`, found `*const S`
    |            |
    |            expected due to this
    |
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
   --> $DIR/dst-bad-coercions.rs:15:21
    |
 LL |     let y: &dyn T = x;
-   |            ------   ^ expected `&dyn T`, found *-ptr
+   |            ------   ^ expected `&dyn T`, found `*const S`
    |            |
    |            expected due to this
    |
@@ -24,7 +24,7 @@ error[E0308]: mismatched types
   --> $DIR/dst-bad-coercions.rs:19:17
    |
 LL |     let y: &S = x;
-   |            --   ^ expected `&S`, found *-ptr
+   |            --   ^ expected `&S`, found `*mut S`
    |            |
    |            expected due to this
    |
@@ -35,7 +35,7 @@ error[E0308]: mismatched types
   --> $DIR/dst-bad-coercions.rs:20:21
    |
 LL |     let y: &dyn T = x;
-   |            ------   ^ expected `&dyn T`, found *-ptr
+   |            ------   ^ expected `&dyn T`, found `*mut S`
    |            |
    |            expected due to this
    |
index d62c2cb403fe850bd91393e0dec15bdbe23af0eb..2cd8731141af752a8b65559c9155948f6b47eeb2 100644 (file)
@@ -1,5 +1,7 @@
 // check-pass
 
+#![feature(let_chains)]
+
 #[cfg(FALSE)]
 fn foo() {
     #[attr]
index 070a5b201286d4e2c15c9787f0c78addeb074493..a8b2a283039fd2fbf320285c38d376c856e3e028 100644 (file)
@@ -4,6 +4,7 @@
 fn a() {
     if let x = 1 && i = 2 {}
     //~^ ERROR cannot find value `i` in this scope
+    //~| ERROR `let` expressions in this position are unstable
     //~| ERROR mismatched types
     //~| ERROR `let` expressions are not supported here
 }
index 9f7a21c7d1ad96fee744617a8a4f5adcbeec2b5f..60d286fedf58ab8f463df319e40770afd8eb7596 100644 (file)
@@ -13,7 +13,7 @@ LL |     if let x = 1 && i = 2 {}
    |                     ^ not found in this scope
 
 error[E0425]: cannot find value `i` in this scope
-  --> $DIR/bad-if-let-suggestion.rs:12:9
+  --> $DIR/bad-if-let-suggestion.rs:13:9
    |
 LL | fn a() {
    | ------ similarly named function `a` defined here
@@ -22,7 +22,7 @@ LL |     if (i + j) = i {}
    |         ^ help: a function with a similar name exists: `a`
 
 error[E0425]: cannot find value `j` in this scope
-  --> $DIR/bad-if-let-suggestion.rs:12:13
+  --> $DIR/bad-if-let-suggestion.rs:13:13
    |
 LL | fn a() {
    | ------ similarly named function `a` defined here
@@ -31,7 +31,7 @@ LL |     if (i + j) = i {}
    |             ^ help: a function with a similar name exists: `a`
 
 error[E0425]: cannot find value `i` in this scope
-  --> $DIR/bad-if-let-suggestion.rs:12:18
+  --> $DIR/bad-if-let-suggestion.rs:13:18
    |
 LL | fn a() {
    | ------ similarly named function `a` defined here
@@ -40,7 +40,7 @@ LL |     if (i + j) = i {}
    |                  ^ help: a function with a similar name exists: `a`
 
 error[E0425]: cannot find value `x` in this scope
-  --> $DIR/bad-if-let-suggestion.rs:19:8
+  --> $DIR/bad-if-let-suggestion.rs:20:8
    |
 LL | fn a() {
    | ------ similarly named function `a` defined here
@@ -48,13 +48,22 @@ LL | fn a() {
 LL |     if x[0] = 1 {}
    |        ^ help: a function with a similar name exists: `a`
 
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/bad-if-let-suggestion.rs:5:8
+   |
+LL |     if let x = 1 && i = 2 {}
+   |        ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
 error[E0308]: mismatched types
   --> $DIR/bad-if-let-suggestion.rs:5:8
    |
 LL |     if let x = 1 && i = 2 {}
    |        ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0308, E0425.
+Some errors have detailed explanations: E0308, E0425, E0658.
 For more information about an error, try `rustc --explain E0308`.
index 72cb4cc843cc42b746e5f30127a4d0913256ce3b..d76c697fe737d907019fdeeb7d2ddba4b01b8438 100644 (file)
@@ -13,10 +13,10 @@ LL | trait NonObjectSafe1: Sized {}
    |       this trait cannot be made into an object...
 
 error[E0038]: the trait `NonObjectSafe2` cannot be made into an object
-  --> $DIR/feature-gate-object_safe_for_dispatch.rs:22:36
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:22:45
    |
 LL | fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 {
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `NonObjectSafe2` cannot be made into an object
+   |                                             ^^^^^^^^^^^^^^^^^^ `NonObjectSafe2` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/feature-gate-object_safe_for_dispatch.rs:7:8
@@ -50,10 +50,10 @@ LL |     fn foo<T>(&self);
    = help: consider moving `foo` to another trait
 
 error[E0038]: the trait `NonObjectSafe4` cannot be made into an object
-  --> $DIR/feature-gate-object_safe_for_dispatch.rs:31:35
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:31:47
    |
 LL | fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> {
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `NonObjectSafe4` cannot be made into an object
+   |                                               ^^^^^^^^^^^^^^^^^^ `NonObjectSafe4` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/feature-gate-object_safe_for_dispatch.rs:15:22
diff --git a/src/test/ui/feature-gates/feature-gate-register_attr.rs b/src/test/ui/feature-gates/feature-gate-register_attr.rs
deleted file mode 100644 (file)
index 36dce2a..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#![register_attr(attr)] //~ ERROR the `#[register_attr]` attribute is an experimental feature
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-register_attr.stderr b/src/test/ui/feature-gates/feature-gate-register_attr.stderr
deleted file mode 100644 (file)
index 8ca3845..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: the `#[register_attr]` attribute is an experimental feature
-  --> $DIR/feature-gate-register_attr.rs:1:1
-   |
-LL | #![register_attr(attr)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #66080 <https://github.com/rust-lang/rust/issues/66080> for more information
-   = help: add `#![feature(register_attr)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-unix_sigpipe.rs b/src/test/ui/feature-gates/feature-gate-unix_sigpipe.rs
new file mode 100644 (file)
index 0000000..46dc3f6
--- /dev/null
@@ -0,0 +1,4 @@
+#![crate_type = "bin"]
+
+#[unix_sigpipe = "inherit"] //~ the `#[unix_sigpipe]` attribute is an experimental feature
+fn main () {}
diff --git a/src/test/ui/feature-gates/feature-gate-unix_sigpipe.stderr b/src/test/ui/feature-gates/feature-gate-unix_sigpipe.stderr
new file mode 100644 (file)
index 0000000..cf32844
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: the `#[unix_sigpipe]` attribute is an experimental feature
+  --> $DIR/feature-gate-unix_sigpipe.rs:3:1
+   |
+LL | #[unix_sigpipe = "inherit"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #97889 <https://github.com/rust-lang/rust/issues/97889> for more information
+   = help: add `#![feature(unix_sigpipe)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
index b7757740d9e34de53ca83755350cb841b114ea17..0f7520ef7f8a95a80644466eedf36a0a5902a143 100644 (file)
@@ -18,11 +18,8 @@ LL |     foo(*x);
    |         ^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)`
+   = note: all function arguments must have a statically known size
    = help: unsized fn params are gated as an unstable feature
-help: function arguments must have a statically known size, borrowed types always have a known size
-   |
-LL |     foo(&*x);
-   |         +
 
 error: aborting due to 2 previous errors
 
index 84f4cc7f4ccd81213009e336dd0088001f6ef57c..f00cb05c9ebc378b7c9135d5b15254926fc3e8b1 100644 (file)
@@ -94,4 +94,6 @@ fn main() {
     // doesn't exist.
     println!("{:.*}");
     //~^ ERROR 2 positional arguments in format string, but no arguments were given
+    println!("{:.0$}");
+    //~^ ERROR 1 positional argument in format string, but no arguments were given
 }
index 5439ee173985b7298424fd28cd99195662e4cf61..dbb4bc6d9370e9f377cb1cc8e241e9f070ba6589 100644 (file)
@@ -273,6 +273,17 @@ LL |     println!("{:.*}");
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
 
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/ifmt-bad-arg.rs:97:15
+   |
+LL |     println!("{:.0$}");
+   |               ^^---^
+   |                 |
+   |                 this precision flag expects an `usize` argument at position 0, but no arguments were given
+   |
+   = note: positional arguments are zero-based
+   = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
+
 error[E0425]: cannot find value `foo` in this scope
   --> $DIR/ifmt-bad-arg.rs:27:18
    |
@@ -339,7 +350,7 @@ LL |     pub fn from_usize(x: &usize) -> ArgumentV1<'_> {
    |            ^^^^^^^^^^
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 37 previous errors
+error: aborting due to 38 previous errors
 
 Some errors have detailed explanations: E0308, E0425.
 For more information about an error, try `rustc --explain E0308`.
index 096440225b99907c57b1f73d35043c2198a12e3e..df838cb11810578e8ec10274324269c48750cf43 100644 (file)
@@ -6,14 +6,10 @@ LL |     let x = f == g;
    |             |
    |             fn() {f}
    |
-help: you might have forgotten to call this function
+help: use parentheses to call these
    |
-LL |     let x = f() == g;
-   |              ++
-help: you might have forgotten to call this function
-   |
-LL |     let x = f == g();
-   |                   ++
+LL |     let x = f() == g();
+   |              ++     ++
 
 error[E0308]: mismatched types
   --> $DIR/fn-compare-mismatch.rs:4:18
index ea88e401bed8737e755b53c36a7abc6fdb9ba499..2a674d3c1d23dea4ee5f1859c779a48fd02bb183 100644 (file)
@@ -8,6 +8,10 @@ LL |     let _: () = Box::new(|_: isize| {}) as Box<dyn FnOnce(isize)>;
    |
    = note: expected unit type `()`
                  found struct `Box<dyn FnOnce(isize)>`
+help: use parentheses to call this trait object
+   |
+LL |     let _: () = (Box::new(|_: isize| {}) as Box<dyn FnOnce(isize)>)(/* isize */);
+   |                 +                                                 ++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/fn-trait-formatting.rs:10:17
@@ -19,6 +23,10 @@ LL |     let _: () = Box::new(|_: isize, isize| {}) as Box<dyn Fn(isize, isize)>
    |
    = note: expected unit type `()`
                  found struct `Box<dyn Fn(isize, isize)>`
+help: use parentheses to call this trait object
+   |
+LL |     let _: () = (Box::new(|_: isize, isize| {}) as Box<dyn Fn(isize, isize)>)(/* isize */, /* isize */);
+   |                 +                                                           +++++++++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/fn-trait-formatting.rs:14:17
index 3d2bcb8ad3550922d568c46c90673cf16ef72f8f..49a514a8b4e3461007e609d85d42a5522cdb4a81 100644 (file)
@@ -1,16 +1,28 @@
 // This test case checks the behavior of typeck::check::method::suggest::is_fn on Ty::Error.
+
+struct Foo;
+
+trait Bar {
+    //~^ NOTE `Bar` defines an item `bar`, perhaps you need to implement it
+    //~| NOTE `Bar` defines an item `bar`, perhaps you need to implement it
+    fn bar(&self) {}
+}
+
+impl Bar for Foo {}
+
 fn main() {
     let arc = std::sync::Arc::new(oops);
     //~^ ERROR cannot find value `oops` in this scope
     //~| NOTE not found
-    // The error "note: this is a function, perhaps you wish to call it" MUST NOT appear.
-    arc.blablabla();
-    //~^ ERROR no method named `blablabla`
+    arc.bar();
+    //~^ ERROR no method named `bar`
     //~| NOTE method not found
-    let arc2 = std::sync::Arc::new(|| 1);
-    // The error "note: this is a function, perhaps you wish to call it" SHOULD appear
-    arc2.blablabla();
-    //~^ ERROR no method named `blablabla`
+    //~| HELP items from traits can only be used if the trait is implemented and in scope
+
+    let arc2 = std::sync::Arc::new(|| Foo);
+    arc2.bar();
+    //~^ ERROR no method named `bar`
     //~| NOTE method not found
-    //~| NOTE this is a function, perhaps you wish to call it
+    //~| HELP items from traits can only be used if the trait is implemented and in scope
+    //~| HELP use parentheses to call this closure
 }
index 06e29daef456ce7802d8eb0ad7111b461ce1c6bc..2296666219eef2fbb284e11e7699db91b4adb20d 100644 (file)
@@ -1,22 +1,38 @@
 error[E0425]: cannot find value `oops` in this scope
-  --> $DIR/fn-help-with-err.rs:3:35
+  --> $DIR/fn-help-with-err.rs:14:35
    |
 LL |     let arc = std::sync::Arc::new(oops);
    |                                   ^^^^ not found in this scope
 
-error[E0599]: no method named `blablabla` found for struct `Arc<_>` in the current scope
-  --> $DIR/fn-help-with-err.rs:7:9
+error[E0599]: no method named `bar` found for struct `Arc<_>` in the current scope
+  --> $DIR/fn-help-with-err.rs:17:9
    |
-LL |     arc.blablabla();
-   |         ^^^^^^^^^ method not found in `Arc<_>`
+LL |     arc.bar();
+   |         ^^^ method not found in `Arc<_>`
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `Bar` defines an item `bar`, perhaps you need to implement it
+  --> $DIR/fn-help-with-err.rs:5:1
+   |
+LL | trait Bar {
+   | ^^^^^^^^^
 
-error[E0599]: no method named `blablabla` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:38]>` in the current scope
-  --> $DIR/fn-help-with-err.rs:12:10
+error[E0599]: no method named `bar` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:22:36: 22:38]>` in the current scope
+  --> $DIR/fn-help-with-err.rs:23:10
+   |
+LL |     arc2.bar();
+   |          ^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:22:36: 22:38]>`
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `Bar` defines an item `bar`, perhaps you need to implement it
+  --> $DIR/fn-help-with-err.rs:5:1
+   |
+LL | trait Bar {
+   | ^^^^^^^^^
+help: use parentheses to call this closure
    |
-LL |     arc2.blablabla();
-   |     ---- ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:38]>`
-   |     |
-   |     this is a function, perhaps you wish to call it
+LL |     arc2().bar();
+   |         ++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/generic-associated-types/issue-101020.rs b/src/test/ui/generic-associated-types/issue-101020.rs
new file mode 100644 (file)
index 0000000..51cabe2
--- /dev/null
@@ -0,0 +1,37 @@
+#![feature(generic_associated_types)]
+
+pub trait LendingIterator {
+    type Item<'a>
+    where
+        Self: 'a;
+
+    fn consume<F>(self, _f: F)
+    where
+        Self: Sized,
+        for<'a> Self::Item<'a>: FuncInput<'a, Self::Item<'a>>,
+    {
+    }
+}
+
+impl<I: LendingIterator + ?Sized> LendingIterator for &mut I {
+    type Item<'a> = I::Item<'a> where Self: 'a;
+}
+struct EmptyIter;
+impl LendingIterator for EmptyIter {
+    type Item<'a> = &'a mut () where Self:'a;
+}
+pub trait FuncInput<'a, F>
+where
+    F: Foo<Self>,
+    Self: Sized,
+{
+}
+impl<'a, T, F: 'a> FuncInput<'a, F> for T where F: Foo<T> {}
+trait Foo<T> {}
+
+fn map_test() {
+    (&mut EmptyIter).consume(());
+    //~^ ERROR the trait bound `for<'a> &'a mut (): Foo<&'a mut ()>` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-101020.stderr b/src/test/ui/generic-associated-types/issue-101020.stderr
new file mode 100644 (file)
index 0000000..7fde89e
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `for<'a> &'a mut (): Foo<&'a mut ()>` is not satisfied
+  --> $DIR/issue-101020.rs:33:5
+   |
+LL |     (&mut EmptyIter).consume(());
+   |     ^^^^^^^^^^^^^^^^ ------- required by a bound introduced by this call
+   |     |
+   |     the trait `for<'a> Foo<&'a mut ()>` is not implemented for `&'a mut ()`
+   |
+note: required for `&'a mut ()` to implement `for<'a> FuncInput<'a, &'a mut ()>`
+  --> $DIR/issue-101020.rs:29:20
+   |
+LL | impl<'a, T, F: 'a> FuncInput<'a, F> for T where F: Foo<T> {}
+   |                    ^^^^^^^^^^^^^^^^     ^
+note: required by a bound in `LendingIterator::consume`
+  --> $DIR/issue-101020.rs:11:33
+   |
+LL |     fn consume<F>(self, _f: F)
+   |        ------- required by a bound in this
+...
+LL |         for<'a> Self::Item<'a>: FuncInput<'a, Self::Item<'a>>,
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `LendingIterator::consume`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 850d83be6845dc44b1e54c876cd8264d960a2d2c..f412ba84c6ba02cca01525873b048664ae5d7a55 100644 (file)
@@ -1,4 +1,4 @@
-// Test for diagnostics when we have mismatched lifetime due to implict 'static lifetime in GATs
+// Test for diagnostics when we have mismatched lifetime due to implicit 'static lifetime in GATs
 
 // check-fail
 
diff --git a/src/test/ui/impl-trait/issue-100075-2.rs b/src/test/ui/impl-trait/issue-100075-2.rs
new file mode 100644 (file)
index 0000000..cf059af
--- /dev/null
@@ -0,0 +1,8 @@
+fn opaque<T>(t: T) -> impl Sized {
+    //~^ ERROR cannot resolve opaque type
+    //~| WARNING function cannot return without recursing
+    opaque(Some(t))
+}
+
+#[allow(dead_code)]
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-100075-2.stderr b/src/test/ui/impl-trait/issue-100075-2.stderr
new file mode 100644 (file)
index 0000000..5a1f1a9
--- /dev/null
@@ -0,0 +1,24 @@
+warning: function cannot return without recursing
+  --> $DIR/issue-100075-2.rs:1:1
+   |
+LL | fn opaque<T>(t: T) -> impl Sized {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+...
+LL |     opaque(Some(t))
+   |     --------------- recursive call site
+   |
+   = note: `#[warn(unconditional_recursion)]` on by default
+   = help: a `loop` may express intention better if this is on purpose
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/issue-100075-2.rs:1:23
+   |
+LL | fn opaque<T>(t: T) -> impl Sized {
+   |                       ^^^^^^^^^^ recursive opaque type
+...
+LL |     opaque(Some(t))
+   |     --------------- returning here with type `impl Sized`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/src/test/ui/impl-trait/issue-100075.rs b/src/test/ui/impl-trait/issue-100075.rs
new file mode 100644 (file)
index 0000000..ea30abb
--- /dev/null
@@ -0,0 +1,21 @@
+trait Marker {}
+impl<T> Marker for T {}
+
+fn maybe<T>(
+    _t: T,
+) -> Option<
+    //removing the line below makes it compile
+    &'static T,
+> {
+    None
+}
+
+fn _g<T>(t: &'static T) -> &'static impl Marker {
+    //~^ ERROR cannot resolve opaque type
+    if let Some(t) = maybe(t) {
+        return _g(t);
+    }
+    todo!()
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-100075.stderr b/src/test/ui/impl-trait/issue-100075.stderr
new file mode 100644 (file)
index 0000000..267ecfd
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0720]: cannot resolve opaque type
+  --> $DIR/issue-100075.rs:13:37
+   |
+LL | fn _g<T>(t: &'static T) -> &'static impl Marker {
+   |                                     ^^^^^^^^^^^ recursive opaque type
+...
+LL |         return _g(t);
+   |                ----- returning here with type `&impl Marker`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/src/test/ui/impl-trait/issue-99914.rs b/src/test/ui/impl-trait/issue-99914.rs
new file mode 100644 (file)
index 0000000..4324a02
--- /dev/null
@@ -0,0 +1,13 @@
+// edition:2021
+
+fn main() {}
+
+struct Error;
+struct Okay;
+
+fn foo(t: Result<Okay, Error>) {
+    t.and_then(|t| -> _ { bar(t) });
+    //~^ ERROR mismatched types
+}
+
+async fn bar(t: Okay) {}
diff --git a/src/test/ui/impl-trait/issue-99914.stderr b/src/test/ui/impl-trait/issue-99914.stderr
new file mode 100644 (file)
index 0000000..074d5d5
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-99914.rs:9:27
+   |
+LL |     t.and_then(|t| -> _ { bar(t) });
+   |                           ^^^^^^ expected enum `Result`, found opaque type
+   |
+note: while checking the return type of the `async fn`
+  --> $DIR/issue-99914.rs:13:23
+   |
+LL | async fn bar(t: Okay) {}
+   |                       ^ checked the `Output` of this `async fn`, found opaque type
+   = note:     expected enum `Result<_, Error>`
+           found opaque type `impl Future<Output = ()>`
+help: try wrapping the expression in `Ok`
+   |
+LL |     t.and_then(|t| -> _ { Ok(bar(t)) });
+   |                           +++      +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 365ecd9fcfa1d7e859145588bb7ffd68a55a834f..687dbe65e6c381405950d54d0b13db584eac5bc7 100644 (file)
@@ -21,10 +21,10 @@ LL |     fn foo() -> Self where Self: Sized;
    |                      +++++++++++++++++
 
 error[E0038]: the trait `NotObjectSafe` cannot be made into an object
-  --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:28:13
+  --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:28:17
    |
 LL | fn cat() -> Box<dyn NotObjectSafe> {
-   |             ^^^^^^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object
+   |                 ^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8
index 2a328a0e6f54d821803307daab761b96385aa7a8..c10a856d83ba8758303350e2694ff012f8445c3b 100644 (file)
@@ -11,7 +11,7 @@ LL | fn opaque() -> impl Fn() -> i32 {
    |
    = note:     expected type `i32`
            found opaque type `impl Fn() -> i32`
-help: use parentheses to call this closure
+help: use parentheses to call this opaque type
    |
 LL |     opaque()()
    |             ++
index 403cf970bcb0a52a49336c0ecf0dd2dcc2ff433a..cdb130d600c5ef2167ac509dff06e39965a91632 100644 (file)
@@ -97,7 +97,7 @@ pub fn main() {
     // ever hands f_A off to instances of GaspA, and thus one should
     // be able to prove the invariant that f_A is *only* invoked from
     // from an instance of GaspA (either via the GaspA drop
-    // implementation or the E drop implementaton). Yet the old (bad)
+    // implementation or the E drop implementation). Yet the old (bad)
     // behavior allowed a call to f_A to leak in while we are tearing
     // down a value of type GaspB.
 }
index 208b340d0641067309f2545dff511e8851662e9d..b5a2b2f55a6d4905af0425b580efa1406101b0a9 100644 (file)
@@ -10,10 +10,6 @@ LL |     let _d = c.clone();
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
            candidate #1: `Clone`
-help: one of the expressions' fields has a method of the same name
-   |
-LL |     let _d = c.x.clone();
-   |                ++
 
 error: aborting due to previous error
 
index a66289a1cf8eb6b79d50ce92911b31f3c7b3ff2f..9ee7654a0885d836fb6c42292af24c1827807681 100644 (file)
@@ -13,8 +13,8 @@ LL | fn test() -> Foo { Foo }
              found fn item `fn(u32) -> Foo {Foo}`
 help: use parentheses to instantiate this tuple struct
    |
-LL | fn test() -> Foo { Foo(_) }
-   |                       +++
+LL | fn test() -> Foo { Foo(/* u32 */) }
+   |                       +++++++++++
 
 error: aborting due to previous error
 
index 8e19f14009a0ea92e0498c5f81d2a1c0ff012fe2..b10273f14bd0338c4a2a6c2c4831e7c92519af7d 100644 (file)
@@ -2,9 +2,7 @@ error[E0599]: no method named `f` found for fn pointer `fn(&u8)` in the current
   --> $DIR/issue-57362-1.rs:20:7
    |
 LL |     a.f();
-   |     - ^ method not found in `fn(&u8)`
-   |     |
-   |     this is a function, perhaps you wish to call it
+   |       ^ method not found in `fn(&u8)`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Trait` defines an item `f`, perhaps you need to implement it
index bb6843a19586e8643c3a13d17f480b93ffe1b95f..e5368ddf1e5760b88b1b071a3319af0939110b6d 100644 (file)
@@ -6,7 +6,7 @@ LL |     foo > 12;
    |     |
    |     fn() -> i32 {foo}
    |
-help: you might have forgotten to call this function
+help: use parentheses to call this function
    |
 LL |     foo() > 12;
    |        ++
@@ -28,10 +28,10 @@ LL |     bar > 13;
    |     |
    |     fn(i64) -> i64 {bar}
    |
-help: you might have forgotten to call this function
+help: use parentheses to call this function
    |
-LL |     bar( /* arguments */ ) > 13;
-   |        +++++++++++++++++++
+LL |     bar(/* i64 */) > 13;
+   |        +++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/issue-59488.rs:18:11
@@ -50,14 +50,10 @@ LL |     foo > foo;
    |     |
    |     fn() -> i32 {foo}
    |
-help: you might have forgotten to call this function
+help: use parentheses to call these
    |
-LL |     foo() > foo;
-   |        ++
-help: you might have forgotten to call this function
-   |
-LL |     foo > foo();
-   |              ++
+LL |     foo() > foo();
+   |        ++      ++
 
 error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}`
   --> $DIR/issue-59488.rs:25:9
index c6e6ea1e096af76068f6be6627d27cd95e66cd24..9239385e6436904b5235e8bc657dfa283c9b4077 100644 (file)
@@ -8,11 +8,6 @@ LL |     assert_eq!(a, 0);
    |     {integer}
    |
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you might have forgotten to call this function
-  --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
-   |
-LL |                 if !(*left_val() == *right_val) {
-   |                               ++
 
 error[E0308]: mismatched types
   --> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5
@@ -21,7 +16,7 @@ LL |     assert_eq!(a, 0);
    |     ^^^^^^^^^^^^^^^^ expected fn item, found integer
    |
    = note: expected fn item `fn() -> i32 {a}`
-                 found type `i32`
+                 found type `{integer}`
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: `fn() -> i32 {a}` doesn't implement `Debug`
index c4addaccefc1045ec2045563331e1dd0e7fc5326..80c77edae9eb1fb0c6f3dfa69ebca00780b27857 100644 (file)
@@ -1,12 +1,15 @@
 fn main() {
     let _ = Iterator::next(&mut ());
     //~^ ERROR `()` is not an iterator
+    //~| ERROR `()` is not an iterator
+    //~| ERROR `()` is not an iterator
 
     for _ in false {}
     //~^ ERROR `bool` is not an iterator
 
     let _ = Iterator::next(&mut ());
     //~^ ERROR `()` is not an iterator
+    //~| ERROR `()` is not an iterator
 
     other()
 }
@@ -16,9 +19,12 @@ pub fn other() {
 
     let _ = Iterator::next(&mut ());
     //~^ ERROR `()` is not an iterator
+    //~| ERROR `()` is not an iterator
+    //~| ERROR `()` is not an iterator
 
     let _ = Iterator::next(&mut ());
     //~^ ERROR `()` is not an iterator
+    //~| ERROR `()` is not an iterator
 
     for _ in false {}
     //~^ ERROR `bool` is not an iterator
index 53b610c172392f2bed4cb7831c47c1ac15023012..3256e57d4361b2a2856486dd40ed29db8177ba01 100644 (file)
@@ -8,8 +8,16 @@ LL |     let _ = Iterator::next(&mut ());
    |
    = help: the trait `Iterator` is not implemented for `()`
 
+error[E0277]: `()` is not an iterator
+  --> $DIR/issue-28098.rs:2:13
+   |
+LL |     let _ = Iterator::next(&mut ());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
 error[E0277]: `bool` is not an iterator
-  --> $DIR/issue-28098.rs:5:14
+  --> $DIR/issue-28098.rs:7:14
    |
 LL |     for _ in false {}
    |              ^^^^^ `bool` is not an iterator
@@ -18,7 +26,7 @@ LL |     for _ in false {}
    = note: required for `bool` to implement `IntoIterator`
 
 error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:8:28
+  --> $DIR/issue-28098.rs:10:28
    |
 LL |     let _ = Iterator::next(&mut ());
    |             -------------- ^^^^^^^ `()` is not an iterator
@@ -28,7 +36,23 @@ LL |     let _ = Iterator::next(&mut ());
    = help: the trait `Iterator` is not implemented for `()`
 
 error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:17:28
+  --> $DIR/issue-28098.rs:10:13
+   |
+LL |     let _ = Iterator::next(&mut ());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `()` is not an iterator
+  --> $DIR/issue-28098.rs:2:13
+   |
+LL |     let _ = Iterator::next(&mut ());
+   |             ^^^^^^^^^^^^^^ `()` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `()` is not an iterator
+  --> $DIR/issue-28098.rs:20:28
    |
 LL |     let _ = Iterator::next(&mut ());
    |             -------------- ^^^^^^^ `()` is not an iterator
@@ -38,7 +62,15 @@ LL |     let _ = Iterator::next(&mut ());
    = help: the trait `Iterator` is not implemented for `()`
 
 error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:20:28
+  --> $DIR/issue-28098.rs:20:13
+   |
+LL |     let _ = Iterator::next(&mut ());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `()` is not an iterator
+  --> $DIR/issue-28098.rs:25:28
    |
 LL |     let _ = Iterator::next(&mut ());
    |             -------------- ^^^^^^^ `()` is not an iterator
@@ -47,8 +79,16 @@ LL |     let _ = Iterator::next(&mut ());
    |
    = help: the trait `Iterator` is not implemented for `()`
 
+error[E0277]: `()` is not an iterator
+  --> $DIR/issue-28098.rs:25:13
+   |
+LL |     let _ = Iterator::next(&mut ());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
 error[E0277]: `bool` is not an iterator
-  --> $DIR/issue-28098.rs:23:14
+  --> $DIR/issue-28098.rs:29:14
    |
 LL |     for _ in false {}
    |              ^^^^^ `bool` is not an iterator
@@ -56,6 +96,14 @@ LL |     for _ in false {}
    = help: the trait `Iterator` is not implemented for `bool`
    = note: required for `bool` to implement `IntoIterator`
 
-error: aborting due to 6 previous errors
+error[E0277]: `()` is not an iterator
+  --> $DIR/issue-28098.rs:20:13
+   |
+LL |     let _ = Iterator::next(&mut ());
+   |             ^^^^^^^^^^^^^^ `()` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `()`
+
+error: aborting due to 12 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index ffbe89a14e3bbd4501f66355ca5a5c8b018d328c..6d12db8d13730a860153df747af5df481c2d3c9c 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 //! This snippet causes the type length to blowup exponentially,
-//! so check that we don't accidentially exceed the type length limit.
+//! so check that we don't accidentally exceed the type length limit.
 // FIXME: Once the size of iterator adaptors is further reduced,
 // increase the complexity of this test.
 use std::collections::VecDeque;
index c66037e9a73ae6d01acbe5e466208575ff956df7..b4fc3317487d29c8a4844726c6d5479cfa62d52e 100644 (file)
@@ -5,7 +5,7 @@
 // If you turn off deduplicate diagnostics (which rustc turns on by default but
 // compiletest turns off when it runs ui tests), then the errors are
 // (unfortunately) repeated here because the checking is done as we read in the
-// errors, and curretly that happens two or three different times, depending on
+// errors, and currently that happens two or three different times, depending on
 // compiler flags.
 //
 // I decided avoiding the redundant output was not worth the time in engineering
diff --git a/src/test/ui/lint/let_underscore/let_underscore_drop.rs b/src/test/ui/lint/let_underscore/let_underscore_drop.rs
new file mode 100644 (file)
index 0000000..f298871
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+#![warn(let_underscore_drop)]
+
+struct NontrivialDrop;
+
+impl Drop for NontrivialDrop {
+    fn drop(&mut self) {
+        println!("Dropping!");
+    }
+}
+
+fn main() {
+    let _ = NontrivialDrop; //~WARNING non-binding let on a type that implements `Drop`
+}
diff --git a/src/test/ui/lint/let_underscore/let_underscore_drop.stderr b/src/test/ui/lint/let_underscore/let_underscore_drop.stderr
new file mode 100644 (file)
index 0000000..7b7de20
--- /dev/null
@@ -0,0 +1,22 @@
+warning: non-binding let on a type that implements `Drop`
+  --> $DIR/let_underscore_drop.rs:13:5
+   |
+LL |     let _ = NontrivialDrop;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/let_underscore_drop.rs:2:9
+   |
+LL | #![warn(let_underscore_drop)]
+   |         ^^^^^^^^^^^^^^^^^^^
+help: consider binding to an unused variable to avoid immediately dropping the value
+   |
+LL |     let _unused = NontrivialDrop;
+   |         ~~~~~~~
+help: consider immediately dropping the value
+   |
+LL |     drop(NontrivialDrop);
+   |     ~~~~~              +
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/let_underscore/let_underscore_lock.rs b/src/test/ui/lint/let_underscore/let_underscore_lock.rs
new file mode 100644 (file)
index 0000000..7423862
--- /dev/null
@@ -0,0 +1,7 @@
+// check-fail
+use std::sync::{Arc, Mutex};
+
+fn main() {
+    let data = Arc::new(Mutex::new(0));
+    let _ = data.lock().unwrap(); //~ERROR non-binding let on a synchronization lock
+}
diff --git a/src/test/ui/lint/let_underscore/let_underscore_lock.stderr b/src/test/ui/lint/let_underscore/let_underscore_lock.stderr
new file mode 100644 (file)
index 0000000..fb58af0
--- /dev/null
@@ -0,0 +1,20 @@
+error: non-binding let on a synchronization lock
+  --> $DIR/let_underscore_lock.rs:6:9
+   |
+LL |     let _ = data.lock().unwrap();
+   |         ^   ^^^^^^^^^^^^^^^^^^^^ this binding will immediately drop the value assigned to it
+   |         |
+   |         this lock is not assigned to a binding and is immediately dropped
+   |
+   = note: `#[deny(let_underscore_lock)]` on by default
+help: consider binding to an unused variable to avoid immediately dropping the value
+   |
+LL |     let _unused = data.lock().unwrap();
+   |         ~~~~~~~
+help: consider immediately dropping the value
+   |
+LL |     drop(data.lock().unwrap());
+   |     ~~~~~                    +
+
+error: aborting due to previous error
+
index 5cd323c01db8cb8234339c3c51c7974300c313a6..dae258407ebb0801cbf888343495196370ff1ca4 100644 (file)
@@ -100,6 +100,18 @@ fn main() {
         let _val: [bool; 2] = mem::zeroed();
         let _val: [bool; 2] = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
 
+        let _val: i32 = mem::zeroed();
+        let _val: i32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
+        let _val: f32 = mem::zeroed();
+        let _val: f32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
+        let _val: *const () = mem::zeroed();
+        let _val: *const () = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
+        let _val: *const [()] = mem::zeroed();
+        let _val: *const [()] = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
         // Transmute-from-0
         let _val: &'static i32 = mem::transmute(0usize); //~ ERROR: does not permit zero-initialization
         let _val: &'static [i32] = mem::transmute((0usize, 0usize)); //~ ERROR: does not permit zero-initialization
@@ -114,13 +126,12 @@ fn main() {
         let _val: Option<&'static i32> = mem::zeroed();
         let _val: Option<fn()> = mem::zeroed();
         let _val: MaybeUninit<&'static i32> = mem::zeroed();
-        let _val: i32 = mem::zeroed();
         let _val: bool = MaybeUninit::zeroed().assume_init();
         let _val: [bool; 0] = MaybeUninit::uninit().assume_init();
         let _val: [!; 0] = MaybeUninit::zeroed().assume_init();
+
         // Some things that happen to work due to rustc implementation details,
         // but are not guaranteed to keep working.
-        let _val: i32 = mem::uninitialized();
         let _val: OneFruit = mem::uninitialized();
     }
 }
index 88121a1836da4144c10a71df9e31da7d3cc3e736..b46042e7be43f8100e3ea3f68426ba2bb53ad051 100644 (file)
@@ -97,7 +97,7 @@ LL |         let _val: (i32, !) = mem::uninitialized();
    |                              this code causes undefined behavior when executed
    |                              help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
-   = note: the `!` type has no valid value
+   = note: integers must not be uninitialized
 
 error: the type `Void` does not permit zero-initialization
   --> $DIR/uninitialized-zeroed.rs:57:26
@@ -414,8 +414,52 @@ LL |         let _val: [bool; 2] = mem::uninitialized();
    |
    = note: booleans must be either `true` or `false`
 
+error: the type `i32` does not permit being left uninitialized
+  --> $DIR/uninitialized-zeroed.rs:104:25
+   |
+LL |         let _val: i32 = mem::uninitialized();
+   |                         ^^^^^^^^^^^^^^^^^^^^
+   |                         |
+   |                         this code causes undefined behavior when executed
+   |                         help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+   = note: integers must not be uninitialized
+
+error: the type `f32` does not permit being left uninitialized
+  --> $DIR/uninitialized-zeroed.rs:107:25
+   |
+LL |         let _val: f32 = mem::uninitialized();
+   |                         ^^^^^^^^^^^^^^^^^^^^
+   |                         |
+   |                         this code causes undefined behavior when executed
+   |                         help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+   = note: floats must not be uninitialized
+
+error: the type `*const ()` does not permit being left uninitialized
+  --> $DIR/uninitialized-zeroed.rs:110:31
+   |
+LL |         let _val: *const () = mem::uninitialized();
+   |                               ^^^^^^^^^^^^^^^^^^^^
+   |                               |
+   |                               this code causes undefined behavior when executed
+   |                               help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+   = note: raw pointers must not be uninitialized
+
+error: the type `*const [()]` does not permit being left uninitialized
+  --> $DIR/uninitialized-zeroed.rs:113:33
+   |
+LL |         let _val: *const [()] = mem::uninitialized();
+   |                                 ^^^^^^^^^^^^^^^^^^^^
+   |                                 |
+   |                                 this code causes undefined behavior when executed
+   |                                 help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+   = note: raw pointers must not be uninitialized
+
 error: the type `&i32` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:104:34
+  --> $DIR/uninitialized-zeroed.rs:116:34
    |
 LL |         let _val: &'static i32 = mem::transmute(0usize);
    |                                  ^^^^^^^^^^^^^^^^^^^^^^
@@ -426,7 +470,7 @@ LL |         let _val: &'static i32 = mem::transmute(0usize);
    = note: references must be non-null
 
 error: the type `&[i32]` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:105:36
+  --> $DIR/uninitialized-zeroed.rs:117:36
    |
 LL |         let _val: &'static [i32] = mem::transmute((0usize, 0usize));
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -437,7 +481,7 @@ LL |         let _val: &'static [i32] = mem::transmute((0usize, 0usize));
    = note: references must be non-null
 
 error: the type `NonZeroU32` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:106:32
+  --> $DIR/uninitialized-zeroed.rs:118:32
    |
 LL |         let _val: NonZeroU32 = mem::transmute(0);
    |                                ^^^^^^^^^^^^^^^^^
@@ -448,7 +492,7 @@ LL |         let _val: NonZeroU32 = mem::transmute(0);
    = note: `std::num::NonZeroU32` must be non-null
 
 error: the type `NonNull<i32>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:109:34
+  --> $DIR/uninitialized-zeroed.rs:121:34
    |
 LL |         let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -459,7 +503,7 @@ LL |         let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `NonNull<i32>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:110:34
+  --> $DIR/uninitialized-zeroed.rs:122:34
    |
 LL |         let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -470,7 +514,7 @@ LL |         let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `bool` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:111:26
+  --> $DIR/uninitialized-zeroed.rs:123:26
    |
 LL |         let _val: bool = MaybeUninit::uninit().assume_init();
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -480,5 +524,5 @@ LL |         let _val: bool = MaybeUninit::uninit().assume_init();
    |
    = note: booleans must be either `true` or `false`
 
-error: aborting due to 39 previous errors
+error: aborting due to 43 previous errors
 
index c2827c7e37fcb7b1c95243d176db79060a1f2368..635050f376c8a73c50f2eb946648600e9bfbd34e 100644 (file)
@@ -1,5 +1,6 @@
 struct Bug<A = [(); (let a = (), 1).1]> {
     //~^ `let` expressions are not supported here
+    //~| `let` expressions in this position are unstable [E0658]
     //~| expected expression, found `let` statement
     a: A
 }
index bd4654edf4b343a520be7cbfe0aca675eefdb463..4a0fcce31d7c7b0a6f208a5b2abb65fb69db26f1 100644 (file)
@@ -12,5 +12,15 @@ LL | struct Bug<A = [(); (let a = (), 1).1]> {
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-error: aborting due to 2 previous errors
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/issue-92893.rs:1:22
+   |
+LL | struct Bug<A = [(); (let a = (), 1).1]> {
+   |                      ^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/mir/issue-99866.rs b/src/test/ui/mir/issue-99866.rs
new file mode 100644 (file)
index 0000000..d39ae6e
--- /dev/null
@@ -0,0 +1,25 @@
+// check-pass
+pub trait Backend {
+    type DescriptorSetLayout;
+}
+
+pub struct Back;
+
+impl Backend for Back {
+    type DescriptorSetLayout = u32;
+}
+
+pub struct HalSetLayouts {
+    vertex_layout: <Back as Backend>::DescriptorSetLayout,
+}
+
+impl HalSetLayouts {
+    pub fn iter<DSL>(self) -> DSL
+    where
+        Back: Backend<DescriptorSetLayout = DSL>,
+    {
+        self.vertex_layout
+    }
+}
+
+fn main() {}
index 21e7b5070af62f403f33bcaa8ce8992f9ca49e17..6498a5195719493dea0b0b46241c39d744f7c4ab 100644 (file)
@@ -4,6 +4,7 @@
 
 // See `mir_drop_order.rs` for more information
 
+#![feature(let_chains)]
 #![allow(irrefutable_let_patterns)]
 
 use std::cell::RefCell;
index c25e2687b752a54a22828e06073b841ca401aa6f..5cef64bb1692619b49e1de466d21568d67570bda 100644 (file)
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL | fn function(t: &mut dyn Trait) {
    |                                - help: try adding a return type: `-> *mut dyn Trait`
 LL |     t as *mut dyn Trait
-   |     ^^^^^^^^^^^^^^^^^^^ expected `()`, found *-ptr
+   |     ^^^^^^^^^^^^^^^^^^^ expected `()`, found `*mut dyn Trait`
    |
    = note: expected unit type `()`
             found raw pointer `*mut dyn Trait`
diff --git a/src/test/ui/mismatched_types/normalize-fn-sig.rs b/src/test/ui/mismatched_types/normalize-fn-sig.rs
new file mode 100644 (file)
index 0000000..1a2093c
--- /dev/null
@@ -0,0 +1,16 @@
+trait Foo {
+    type Bar;
+}
+
+impl<T> Foo for T {
+    type Bar = i32;
+}
+
+fn foo<T>(_: <T as Foo>::Bar, _: &'static <T as Foo>::Bar) {}
+
+fn needs_i32_ref_fn(_: fn(&'static i32, i32)) {}
+
+fn main() {
+    needs_i32_ref_fn(foo::<()>);
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/mismatched_types/normalize-fn-sig.stderr b/src/test/ui/mismatched_types/normalize-fn-sig.stderr
new file mode 100644 (file)
index 0000000..6c55f29
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+  --> $DIR/normalize-fn-sig.rs:14:22
+   |
+LL |     needs_i32_ref_fn(foo::<()>);
+   |     ---------------- ^^^^^^^^^ expected `&i32`, found `i32`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected fn pointer `fn(&'static i32, i32)`
+                 found fn item `fn(i32, &'static i32) {foo::<()>}`
+note: function defined here
+  --> $DIR/normalize-fn-sig.rs:11:4
+   |
+LL | fn needs_i32_ref_fn(_: fn(&'static i32, i32)) {}
+   |    ^^^^^^^^^^^^^^^^ ------------------------
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/modules/auxiliary/dummy_lib.rs b/src/test/ui/modules/auxiliary/dummy_lib.rs
new file mode 100644 (file)
index 0000000..ef805c1
--- /dev/null
@@ -0,0 +1,2 @@
+#[allow(dead_code)]
+pub struct Dummy;
diff --git a/src/test/ui/modules/special_module_name.rs b/src/test/ui/modules/special_module_name.rs
new file mode 100644 (file)
index 0000000..15c59b2
--- /dev/null
@@ -0,0 +1,8 @@
+mod lib;
+//~^ WARN found module declaration for lib.rs
+//~| ERROR file not found for module `lib`
+mod main;
+//~^ WARN found module declaration for main.rs
+//~| ERROR file not found for module `main`
+
+fn main() {}
diff --git a/src/test/ui/modules/special_module_name.stderr b/src/test/ui/modules/special_module_name.stderr
new file mode 100644 (file)
index 0000000..8b3da29
--- /dev/null
@@ -0,0 +1,37 @@
+error[E0583]: file not found for module `lib`
+  --> $DIR/special_module_name.rs:1:1
+   |
+LL | mod lib;
+   | ^^^^^^^^
+   |
+   = help: to create the module `lib`, create file "$DIR/lib.rs" or "$DIR/lib/mod.rs"
+
+error[E0583]: file not found for module `main`
+  --> $DIR/special_module_name.rs:4:1
+   |
+LL | mod main;
+   | ^^^^^^^^^
+   |
+   = help: to create the module `main`, create file "$DIR/main.rs" or "$DIR/main/mod.rs"
+
+warning: found module declaration for lib.rs
+  --> $DIR/special_module_name.rs:1:1
+   |
+LL | mod lib;
+   | ^^^^^^^^
+   |
+   = note: `#[warn(special_module_name)]` on by default
+   = note: lib.rs is the root of this crate's library target
+   = help: to refer to it from other targets, use the library's name as the path
+
+warning: found module declaration for main.rs
+  --> $DIR/special_module_name.rs:4:1
+   |
+LL | mod main;
+   | ^^^^^^^^^
+   |
+   = note: a binary crate cannot be used as library
+
+error: aborting due to 2 previous errors; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0583`.
diff --git a/src/test/ui/modules/special_module_name_ignore.rs b/src/test/ui/modules/special_module_name_ignore.rs
new file mode 100644 (file)
index 0000000..07cea9b
--- /dev/null
@@ -0,0 +1,9 @@
+// run-pass
+
+#[path = "auxiliary/dummy_lib.rs"]
+mod lib;
+
+#[path = "auxiliary/dummy_lib.rs"]
+mod main;
+
+fn main() {}
index 35052da6760b64ecfe443cbc67eed82304b30aba..f88355bb285f39a8e7eba473b62142fc53612578 100644 (file)
@@ -3,7 +3,7 @@
 //
 // This particular test case currently fails as the inference to `()` rather
 // than `!` happens as a result of an `as` cast, which is not currently tracked.
-// Crater did not find many cases of this occuring, but it is included for
+// Crater did not find many cases of this occurring, but it is included for
 // awareness.
 //
 // revisions: nofallback fallback
index 4cd1e406f94400dc4b81b6b56b01126f983eb4ac..ad3eb248351d4c18cefe473f2adff2137212bf48 100644 (file)
@@ -53,7 +53,7 @@ impl<F> R<F> { fn new(f: F) -> Self { R { w: 0, f } } }
 // * local/field: Is the structure in a local or a field
 // * fully/partial/void: Are we fully initializing it before using any part?
 //                       Is whole type empty due to a void component?
-// * init/reinit: First initialization, or did we previously inititalize and then move out?
+// * init/reinit: First initialization, or did we previously initialize and then move out?
 // * struct/tuple: Is this a struct or a (X, Y).
 //
 // As a shorthand for the cases above, adding a numeric summary to
index c4cf20389ac8d9e127c7b229bfb9267d889a326a..696bf61cefde04f818610fc389a9aca0dea6ef25 100644 (file)
@@ -1,7 +1,7 @@
 #![allow(dead_code)]
 
 // This tests the various kinds of assignments there are. Polonius used to generate `killed`
-// facts only on simple assigments, but not projections, incorrectly causing errors to be emitted
+// facts only on simple assignments, but not projections, incorrectly causing errors to be emitted
 // for code accepted by NLL. They are all variations from example code in the NLL RFC.
 
 // check-pass
index 15e22e946da8a1da79630526c7f82f0fff9b02cb..0c696163a26c5cba2737b6bf51ae504c1e84af26 100644 (file)
@@ -10,14 +10,6 @@ LL |     let _y = x.clone();
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
            candidate #1: `Clone`
-help: one of the expressions' fields has a method of the same name
-   |
-LL |     let _y = x.i.clone();
-   |                ++
-help: one of the expressions' fields has a method of the same name
-   |
-LL |     let _y = x.j.x.clone();
-   |                ++++
 
 error: aborting due to previous error
 
index 9dd144fee24a68550116fb5ebf82292c0cc3607b..5f94c9284ea6699c1443b8dfcf4cca166cae45b2 100644 (file)
@@ -1,8 +1,8 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-associated-consts.rs:12:30
+  --> $DIR/object-safety-associated-consts.rs:12:31
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                              ^^^^^^^^ `Bar` cannot be made into an object
+   |                               ^^^^^^^ `Bar` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/object-safety-associated-consts.rs:9:11
index 89c4f8ced79f6ce77c9ee6fd5fb5eb1939566329..29ffb5448427d42ee4a0358728cc922b8640fb8b 100644 (file)
@@ -1,8 +1,8 @@
 error[E0038]: the trait `X` cannot be made into an object
-  --> $DIR/object-safety-bounds.rs:7:11
+  --> $DIR/object-safety-bounds.rs:7:15
    |
 LL | fn f() -> Box<dyn X<U = u32>> {
-   |           ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |               ^^^^^^^^^^^^^^ `X` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/object-safety-bounds.rs:4:13
index 345950f1ae670cb473598f10e32a51c4d7d09d94..45810375263978b9d7664b3d150c1af8789e151d 100644 (file)
@@ -1,8 +1,8 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-generics.rs:18:30
+  --> $DIR/object-safety-generics.rs:18:31
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                              ^^^^^^^^ `Bar` cannot be made into an object
+   |                               ^^^^^^^ `Bar` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/object-safety-generics.rs:10:8
@@ -14,10 +14,10 @@ LL |     fn bar<T>(&self, t: T);
    = help: consider moving `bar` to another trait
 
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-generics.rs:24:39
+  --> $DIR/object-safety-generics.rs:24:40
    |
 LL | fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar {
-   |                                       ^^^^^^^^ `Bar` cannot be made into an object
+   |                                        ^^^^^^^ `Bar` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/object-safety-generics.rs:10:8
index f91c9b9856055778e20bbf4ae4d39fa5f1fe1caf..de430a89bf82b6ff7a985ee23590df1c3ecedf07 100644 (file)
@@ -1,8 +1,8 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-mentions-Self.rs:22:30
+  --> $DIR/object-safety-mentions-Self.rs:22:31
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                              ^^^^^^^^ `Bar` cannot be made into an object
+   |                               ^^^^^^^ `Bar` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/object-safety-mentions-Self.rs:11:22
@@ -14,10 +14,10 @@ LL |     fn bar(&self, x: &Self);
    = help: consider moving `bar` to another trait
 
 error[E0038]: the trait `Baz` cannot be made into an object
-  --> $DIR/object-safety-mentions-Self.rs:28:30
+  --> $DIR/object-safety-mentions-Self.rs:28:31
    |
 LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
-   |                              ^^^^^^^^ `Baz` cannot be made into an object
+   |                               ^^^^^^^ `Baz` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/object-safety-mentions-Self.rs:15:22
index bd8cf4e30f7fac064a778bc6e2ff4bb796f56931..1b025229e543ee159e20be60d78f98415137c361 100644 (file)
@@ -1,8 +1,8 @@
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/object-safety-no-static.rs:12:18
+  --> $DIR/object-safety-no-static.rs:12:22
    |
 LL | fn diverges() -> Box<dyn Foo> {
-   |                  ^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |                      ^^^^^^^ `Foo` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/object-safety-no-static.rs:9:8
index 71236c8e3843805cc6980a4a65d8284f4a0d59a3..b019264128e7668e926b564822291774e196f15b 100644 (file)
@@ -1,8 +1,8 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-sized-2.rs:14:30
+  --> $DIR/object-safety-sized-2.rs:14:31
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                              ^^^^^^^^ `Bar` cannot be made into an object
+   |                               ^^^^^^^ `Bar` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/object-safety-sized-2.rs:9:18
index 94b06ee934d44bf69368786b98bbb12c66d9f918..97481312142fb7959cb44bda0c7044c315658a0a 100644 (file)
@@ -1,8 +1,8 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-sized.rs:12:30
+  --> $DIR/object-safety-sized.rs:12:31
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                              ^^^^^^^^ `Bar` cannot be made into an object
+   |                               ^^^^^^^ `Bar` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/object-safety-sized.rs:8:13
index 79c40f650db810daf1f9197fdcd46d4a2f05311e..a32fd4566231db60224c29803608766b650b5ac8 100644 (file)
@@ -32,8 +32,14 @@ fn index(&self, _index: Bar<usize>) -> &i32 {
 fn main() {
     Index::index(&[] as &[i32], 2u32);
     //~^ ERROR E0277
+    //~| ERROR E0277
+    //~| ERROR E0277
     Index::index(&[] as &[i32], Foo(2u32));
     //~^ ERROR E0277
+    //~| ERROR E0277
+    //~| ERROR E0277
     Index::index(&[] as &[i32], Bar(2u32));
     //~^ ERROR E0277
+    //~| ERROR E0277
+    //~| ERROR E0277
 }
index d47a398412fe4e7b37ffe5db36e74818506f83ea..d628b159a66d2067c1808cd20a7f4cbddfed58f8 100644 (file)
@@ -11,8 +11,19 @@ LL |     Index::index(&[] as &[i32], 2u32);
              <[i32] as Index<Bar<usize>>>
              <[i32] as Index<Foo<usize>>>
 
+error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
+  --> $DIR/multiple-impls.rs:33:5
+   |
+LL |     Index::index(&[] as &[i32], 2u32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait message
+   |
+   = help: the trait `Index<u32>` is not implemented for `[i32]`
+   = help: the following other types implement trait `Index<Idx>`:
+             <[i32] as Index<Bar<usize>>>
+             <[i32] as Index<Foo<usize>>>
+
 error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
-  --> $DIR/multiple-impls.rs:35:33
+  --> $DIR/multiple-impls.rs:37:33
    |
 LL |     Index::index(&[] as &[i32], Foo(2u32));
    |     ------------                ^^^^^^^^^ on impl for Foo
@@ -24,8 +35,19 @@ LL |     Index::index(&[] as &[i32], Foo(2u32));
              <[i32] as Index<Bar<usize>>>
              <[i32] as Index<Foo<usize>>>
 
+error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
+  --> $DIR/multiple-impls.rs:37:5
+   |
+LL |     Index::index(&[] as &[i32], Foo(2u32));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Foo
+   |
+   = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]`
+   = help: the following other types implement trait `Index<Idx>`:
+             <[i32] as Index<Bar<usize>>>
+             <[i32] as Index<Foo<usize>>>
+
 error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
-  --> $DIR/multiple-impls.rs:37:33
+  --> $DIR/multiple-impls.rs:41:33
    |
 LL |     Index::index(&[] as &[i32], Bar(2u32));
    |     ------------                ^^^^^^^^^ on impl for Bar
@@ -37,6 +59,50 @@ LL |     Index::index(&[] as &[i32], Bar(2u32));
              <[i32] as Index<Bar<usize>>>
              <[i32] as Index<Foo<usize>>>
 
-error: aborting due to 3 previous errors
+error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
+  --> $DIR/multiple-impls.rs:41:5
+   |
+LL |     Index::index(&[] as &[i32], Bar(2u32));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Bar
+   |
+   = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]`
+   = help: the following other types implement trait `Index<Idx>`:
+             <[i32] as Index<Bar<usize>>>
+             <[i32] as Index<Foo<usize>>>
+
+error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
+  --> $DIR/multiple-impls.rs:33:5
+   |
+LL |     Index::index(&[] as &[i32], 2u32);
+   |     ^^^^^^^^^^^^ trait message
+   |
+   = help: the trait `Index<u32>` is not implemented for `[i32]`
+   = help: the following other types implement trait `Index<Idx>`:
+             <[i32] as Index<Bar<usize>>>
+             <[i32] as Index<Foo<usize>>>
+
+error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
+  --> $DIR/multiple-impls.rs:37:5
+   |
+LL |     Index::index(&[] as &[i32], Foo(2u32));
+   |     ^^^^^^^^^^^^ on impl for Foo
+   |
+   = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]`
+   = help: the following other types implement trait `Index<Idx>`:
+             <[i32] as Index<Bar<usize>>>
+             <[i32] as Index<Foo<usize>>>
+
+error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
+  --> $DIR/multiple-impls.rs:41:5
+   |
+LL |     Index::index(&[] as &[i32], Bar(2u32));
+   |     ^^^^^^^^^^^^ on impl for Bar
+   |
+   = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]`
+   = help: the following other types implement trait `Index<Idx>`:
+             <[i32] as Index<Bar<usize>>>
+             <[i32] as Index<Foo<usize>>>
+
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index b03e1f7c6a8dfbb8d76b0865b245e48301d5cb18..d0537810ce11e4a099509e5f74fec4b999f7061f 100644 (file)
@@ -21,4 +21,6 @@ fn index(&self, index: usize) -> &i32 {
 fn main() {
     Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
     //~^ ERROR E0277
+    //~| ERROR E0277
+    //~| ERROR E0277
 }
index 01315b854098ee4dee9d1c06703ce4cc3477dfac..2253c5992a64a346cf88b15d91cbb3954ae9c2aa 100644 (file)
@@ -9,6 +9,24 @@ LL |     Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
    = help: the trait `Index<u32>` is not implemented for `[i32]`
    = help: the trait `Index<usize>` is implemented for `[i32]`
 
-error: aborting due to previous error
+error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
+  --> $DIR/on-impl.rs:22:5
+   |
+LL |     Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice
+   |
+   = help: the trait `Index<u32>` is not implemented for `[i32]`
+   = help: the trait `Index<usize>` is implemented for `[i32]`
+
+error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
+  --> $DIR/on-impl.rs:22:5
+   |
+LL |     Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
+   |     ^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice
+   |
+   = help: the trait `Index<u32>` is not implemented for `[i32]`
+   = help: the trait `Index<usize>` is implemented for `[i32]`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index 84552f2e7331580a306292e947c733dadbf775b9..156285e0f9fc97356f5251ab7ff4254ce6dc4b73 100644 (file)
@@ -1,5 +1,5 @@
 // Here we test that rest patterns, i.e. `..`, are not allowed
-// outside of slice (+ ident patterns witin those), tuple,
+// outside of slice (+ ident patterns within those), tuple,
 // and tuple struct patterns and that duplicates are caught in these contexts.
 
 #![feature(box_patterns)]
diff --git a/src/test/ui/privacy/access_levels.rs b/src/test/ui/privacy/access_levels.rs
new file mode 100644 (file)
index 0000000..d51d2b5
--- /dev/null
@@ -0,0 +1,49 @@
+#![feature(rustc_attrs)]
+
+#[rustc_access_level] mod outer { //~ ERROR None
+    #[rustc_access_level] pub mod inner { //~ ERROR Some(Exported)
+        #[rustc_access_level]
+        extern "C" { //~ ERROR Some(Exported)
+            #[rustc_access_level] static a: u8; //~ ERROR None
+            #[rustc_access_level] pub fn b(); //~ ERROR Some(Exported)
+        }
+        #[rustc_access_level]
+        pub trait Trait { //~ ERROR Some(Exported)
+            #[rustc_access_level] const A: i32; //~ ERROR Some(Exported)
+            #[rustc_access_level] type B; //~ ERROR Some(Exported)
+        }
+
+        #[rustc_access_level]
+        pub struct Struct { //~ ERROR Some(Exported)
+            #[rustc_access_level] a: u8, //~ ERROR None
+            #[rustc_access_level] pub b: u8, //~ ERROR Some(Exported)
+        }
+
+        #[rustc_access_level]
+        pub union Union { //~ ERROR Some(Exported)
+            #[rustc_access_level] a: u8, //~ ERROR None
+            #[rustc_access_level] pub b: u8, //~ ERROR Some(Exported)
+        }
+
+        #[rustc_access_level]
+        pub enum Enum { //~ ERROR Some(Exported)
+            #[rustc_access_level] A( //~ ERROR Some(Exported)
+                #[rustc_access_level] Struct, //~ ERROR Some(Exported)
+                #[rustc_access_level] Union,  //~ ERROR Some(Exported)
+            ),
+        }
+    }
+
+    #[rustc_access_level] macro_rules! none_macro { //~ ERROR None
+        () => {};
+    }
+
+    #[macro_export]
+    #[rustc_access_level] macro_rules! public_macro { //~ ERROR Some(Public)
+        () => {};
+    }
+}
+
+pub use outer::inner;
+
+fn main() {}
diff --git a/src/test/ui/privacy/access_levels.stderr b/src/test/ui/privacy/access_levels.stderr
new file mode 100644 (file)
index 0000000..f326293
--- /dev/null
@@ -0,0 +1,125 @@
+error: None
+  --> $DIR/access_levels.rs:3:23
+   |
+LL | #[rustc_access_level] mod outer {
+   |                       ^^^^^^^^^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:4:27
+   |
+LL |     #[rustc_access_level] pub mod inner {
+   |                           ^^^^^^^^^^^^^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:6:9
+   |
+LL | /         extern "C" {
+LL | |             #[rustc_access_level] static a: u8;
+LL | |             #[rustc_access_level] pub fn b();
+LL | |         }
+   | |_________^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:11:9
+   |
+LL |         pub trait Trait {
+   |         ^^^^^^^^^^^^^^^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:17:9
+   |
+LL |         pub struct Struct {
+   |         ^^^^^^^^^^^^^^^^^
+
+error: None
+  --> $DIR/access_levels.rs:18:35
+   |
+LL |             #[rustc_access_level] a: u8,
+   |                                   ^^^^^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:19:35
+   |
+LL |             #[rustc_access_level] pub b: u8,
+   |                                   ^^^^^^^^^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:23:9
+   |
+LL |         pub union Union {
+   |         ^^^^^^^^^^^^^^^
+
+error: None
+  --> $DIR/access_levels.rs:24:35
+   |
+LL |             #[rustc_access_level] a: u8,
+   |                                   ^^^^^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:25:35
+   |
+LL |             #[rustc_access_level] pub b: u8,
+   |                                   ^^^^^^^^^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:29:9
+   |
+LL |         pub enum Enum {
+   |         ^^^^^^^^^^^^^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:30:35
+   |
+LL |             #[rustc_access_level] A(
+   |                                   ^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:31:39
+   |
+LL |                 #[rustc_access_level] Struct,
+   |                                       ^^^^^^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:32:39
+   |
+LL |                 #[rustc_access_level] Union,
+   |                                       ^^^^^
+
+error: None
+  --> $DIR/access_levels.rs:37:27
+   |
+LL |     #[rustc_access_level] macro_rules! none_macro {
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Some(Public)
+  --> $DIR/access_levels.rs:42:27
+   |
+LL |     #[rustc_access_level] macro_rules! public_macro {
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:12:35
+   |
+LL |             #[rustc_access_level] const A: i32;
+   |                                   ^^^^^^^^^^^^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:13:35
+   |
+LL |             #[rustc_access_level] type B;
+   |                                   ^^^^^^
+
+error: None
+  --> $DIR/access_levels.rs:7:35
+   |
+LL |             #[rustc_access_level] static a: u8;
+   |                                   ^^^^^^^^^^^^
+
+error: Some(Exported)
+  --> $DIR/access_levels.rs:8:35
+   |
+LL |             #[rustc_access_level] pub fn b();
+   |                                   ^^^^^^^^^^
+
+error: aborting due to 20 previous errors
+
index 8c1a9dc80265e17e87eb0b3be1f707ce43592649..6103acb7b6bd9ef82e9f3c7cc73f5605f434448a 100644 (file)
@@ -9,7 +9,7 @@
 
 // FIXME: This don't work when crate-type is specified by attribute
 // `#![crate_type = "proc-macro"]`, not by `--crate-type=proc-macro`
-// command line flag. This is beacuse the list of `cfg` symbols is generated
+// command line flag. This is because the list of `cfg` symbols is generated
 // before attributes are parsed. See rustc_interface::util::add_configuration
 #[cfg(target_feature = "crt-static")]
 compile_error!("crt-static is enabled");
diff --git a/src/test/ui/proc-macro/expand-to-unstable-2.rs b/src/test/ui/proc-macro/expand-to-unstable-2.rs
deleted file mode 100644 (file)
index 4160e54..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// aux-build:derive-unstable-2.rs
-
-#![feature(register_attr)]
-
-#![register_attr(rustc_foo)]
-
-#[macro_use]
-extern crate derive_unstable_2;
-
-#[derive(Unstable)]
-//~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
-
-struct A;
-
-fn main() {
-    foo();
-}
diff --git a/src/test/ui/proc-macro/expand-to-unstable-2.stderr b/src/test/ui/proc-macro/expand-to-unstable-2.stderr
deleted file mode 100644 (file)
index 8b16ffb..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-error: attributes starting with `rustc` are reserved for use by the `rustc` compiler
-  --> $DIR/expand-to-unstable-2.rs:10:10
-   |
-LL | #[derive(Unstable)]
-   |          ^^^^^^^^
-   |
-   = note: this error originates in the derive macro `Unstable` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
index 2e3c704da43924cfdea8bf27a712641e77cc2c7f..1000c9c755ffc255bff7cad35dc9df29fd2a0bb1 100644 (file)
@@ -1,3 +1,4 @@
+// gate-test-custom_inner_attributes
 // compile-flags: -Z span-debug --error-format human
 // aux-build:test-macros.rs
 // edition:2018
index 4da8751ef7fe904f96374e03b8c031e9be105ece..a332e143a79f1d0de39c2cea8364ed1cf4b6cf38 100644 (file)
@@ -1,23 +1,23 @@
 error: expected non-macro inner attribute, found attribute macro `print_attr`
-  --> $DIR/inner-attrs.rs:63:12
+  --> $DIR/inner-attrs.rs:64:12
    |
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_attr`
-  --> $DIR/inner-attrs.rs:67:12
+  --> $DIR/inner-attrs.rs:68:12
    |
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_attr`
-  --> $DIR/inner-attrs.rs:71:12
+  --> $DIR/inner-attrs.rs:72:12
    |
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_attr`
-  --> $DIR/inner-attrs.rs:75:12
+  --> $DIR/inner-attrs.rs:76:12
    |
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
index eaa8882d6a6cb6d60365cba92c941b67791ce09c..490fc02f510372d0380b458ab125cfe3aaab6c9d 100644 (file)
@@ -2,7 +2,7 @@ PRINT-ATTR_ARGS INPUT (DISPLAY): first
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "first",
-        span: $DIR/inner-attrs.rs:16:25: 16:30 (#0),
+        span: $DIR/inner-attrs.rs:17:25: 17:30 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(second)] fn foo()
@@ -11,40 +11,40 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:17:1: 17:2 (#0),
+        span: $DIR/inner-attrs.rs:18:1: 18:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_target_and_args",
-                span: $DIR/inner-attrs.rs:17:3: 17:24 (#0),
+                span: $DIR/inner-attrs.rs:18:3: 18:24 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "second",
-                        span: $DIR/inner-attrs.rs:17:25: 17:31 (#0),
+                        span: $DIR/inner-attrs.rs:18:25: 18:31 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:17:24: 17:32 (#0),
+                span: $DIR/inner-attrs.rs:18:24: 18:32 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:17:2: 17:33 (#0),
+        span: $DIR/inner-attrs.rs:18:2: 18:33 (#0),
     },
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
+        span: $DIR/inner-attrs.rs:19:1: 19:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
+        span: $DIR/inner-attrs.rs:19:4: 19:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
+        span: $DIR/inner-attrs.rs:19:7: 19:9 (#0),
     },
     Group {
         delimiter: Brace,
@@ -52,72 +52,72 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
+                span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
+                span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
+                        span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "third",
-                                span: $DIR/inner-attrs.rs:19:30: 19:35 (#0),
+                                span: $DIR/inner-attrs.rs:20:30: 20:35 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:19:29: 19:36 (#0),
+                        span: $DIR/inner-attrs.rs:20:29: 20:36 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:19:7: 19:37 (#0),
+                span: $DIR/inner-attrs.rs:20:7: 20:37 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
+                span: $DIR/inner-attrs.rs:21:5: 21:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
+                span: $DIR/inner-attrs.rs:21:6: 21:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
+                        span: $DIR/inner-attrs.rs:21:8: 21:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "fourth",
-                                span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
+                                span: $DIR/inner-attrs.rs:21:30: 21:36 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:20:29: 20:37 (#0),
+                        span: $DIR/inner-attrs.rs:21:29: 21:37 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:20:7: 20:38 (#0),
+                span: $DIR/inner-attrs.rs:21:7: 21:38 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
+        span: $DIR/inner-attrs.rs:19:10: 22:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): second
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "second",
-        span: $DIR/inner-attrs.rs:17:25: 17:31 (#0),
+        span: $DIR/inner-attrs.rs:18:25: 18:31 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn foo()
@@ -125,16 +125,16 @@ PRINT-ATTR INPUT (DISPLAY): fn foo()
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
+        span: $DIR/inner-attrs.rs:19:1: 19:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
+        span: $DIR/inner-attrs.rs:19:4: 19:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
+        span: $DIR/inner-attrs.rs:19:7: 19:9 (#0),
     },
     Group {
         delimiter: Brace,
@@ -142,88 +142,88 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
+                span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
+                span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
+                        span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "third",
-                                span: $DIR/inner-attrs.rs:19:30: 19:35 (#0),
+                                span: $DIR/inner-attrs.rs:20:30: 20:35 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:19:29: 19:36 (#0),
+                        span: $DIR/inner-attrs.rs:20:29: 20:36 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:19:7: 19:37 (#0),
+                span: $DIR/inner-attrs.rs:20:7: 20:37 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
+                span: $DIR/inner-attrs.rs:21:5: 21:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
+                span: $DIR/inner-attrs.rs:21:6: 21:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
+                        span: $DIR/inner-attrs.rs:21:8: 21:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "fourth",
-                                span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
+                                span: $DIR/inner-attrs.rs:21:30: 21:36 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:20:29: 20:37 (#0),
+                        span: $DIR/inner-attrs.rs:21:29: 21:37 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:20:7: 20:38 (#0),
+                span: $DIR/inner-attrs.rs:21:7: 21:38 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
+        span: $DIR/inner-attrs.rs:19:10: 22:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): third
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "third",
-        span: $DIR/inner-attrs.rs:19:30: 19:35 (#0),
+        span: $DIR/inner-attrs.rs:20:30: 20:35 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn foo() { #! [print_target_and_args(fourth)] }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
+        span: $DIR/inner-attrs.rs:19:1: 19:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
+        span: $DIR/inner-attrs.rs:19:4: 19:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
+        span: $DIR/inner-attrs.rs:19:7: 19:9 (#0),
     },
     Group {
         delimiter: Brace,
@@ -231,70 +231,70 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
+                span: $DIR/inner-attrs.rs:21:5: 21:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
+                span: $DIR/inner-attrs.rs:21:6: 21:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
+                        span: $DIR/inner-attrs.rs:21:8: 21:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "fourth",
-                                span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
+                                span: $DIR/inner-attrs.rs:21:30: 21:36 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:20:29: 20:37 (#0),
+                        span: $DIR/inner-attrs.rs:21:29: 21:37 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:20:7: 20:38 (#0),
+                span: $DIR/inner-attrs.rs:21:7: 21:38 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
+        span: $DIR/inner-attrs.rs:19:10: 22:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): fourth
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fourth",
-        span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
+        span: $DIR/inner-attrs.rs:21:30: 21:36 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn foo() {}
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
+        span: $DIR/inner-attrs.rs:19:1: 19:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
+        span: $DIR/inner-attrs.rs:19:4: 19:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
+        span: $DIR/inner-attrs.rs:19:7: 19:9 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
+        span: $DIR/inner-attrs.rs:19:10: 22:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): mod_first
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod_first",
-        span: $DIR/inner-attrs.rs:23:25: 23:34 (#0),
+        span: $DIR/inner-attrs.rs:24:25: 24:34 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(mod_second)] mod inline_mod
@@ -306,35 +306,35 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:24:1: 24:2 (#0),
+        span: $DIR/inner-attrs.rs:25:1: 25:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_target_and_args",
-                span: $DIR/inner-attrs.rs:24:3: 24:24 (#0),
+                span: $DIR/inner-attrs.rs:25:3: 25:24 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "mod_second",
-                        span: $DIR/inner-attrs.rs:24:25: 24:35 (#0),
+                        span: $DIR/inner-attrs.rs:25:25: 25:35 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:24:24: 24:36 (#0),
+                span: $DIR/inner-attrs.rs:25:24: 25:36 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:24:2: 24:37 (#0),
+        span: $DIR/inner-attrs.rs:25:2: 25:37 (#0),
     },
     Ident {
         ident: "mod",
-        span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
+        span: $DIR/inner-attrs.rs:26:1: 26:4 (#0),
     },
     Ident {
         ident: "inline_mod",
-        span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
+        span: $DIR/inner-attrs.rs:26:5: 26:15 (#0),
     },
     Group {
         delimiter: Brace,
@@ -342,72 +342,72 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+                span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+                span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+                        span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_third",
-                                span: $DIR/inner-attrs.rs:26:30: 26:39 (#0),
+                                span: $DIR/inner-attrs.rs:27:30: 27:39 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:26:29: 26:40 (#0),
+                        span: $DIR/inner-attrs.rs:27:29: 27:40 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:26:7: 26:41 (#0),
+                span: $DIR/inner-attrs.rs:27:7: 27:41 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
+                span: $DIR/inner-attrs.rs:28:5: 28:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
+                span: $DIR/inner-attrs.rs:28:6: 28:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
+                        span: $DIR/inner-attrs.rs:28:8: 28:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_fourth",
-                                span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
+                                span: $DIR/inner-attrs.rs:28:30: 28:40 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:27:29: 27:41 (#0),
+                        span: $DIR/inner-attrs.rs:28:29: 28:41 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:27:7: 27:42 (#0),
+                span: $DIR/inner-attrs.rs:28:7: 28:42 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
+        span: $DIR/inner-attrs.rs:26:16: 29:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): mod_second
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod_second",
-        span: $DIR/inner-attrs.rs:24:25: 24:35 (#0),
+        span: $DIR/inner-attrs.rs:25:25: 25:35 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): mod inline_mod
@@ -418,11 +418,11 @@ PRINT-ATTR INPUT (DISPLAY): mod inline_mod
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod",
-        span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
+        span: $DIR/inner-attrs.rs:26:1: 26:4 (#0),
     },
     Ident {
         ident: "inline_mod",
-        span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
+        span: $DIR/inner-attrs.rs:26:5: 26:15 (#0),
     },
     Group {
         delimiter: Brace,
@@ -430,83 +430,83 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+                span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+                span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+                        span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_third",
-                                span: $DIR/inner-attrs.rs:26:30: 26:39 (#0),
+                                span: $DIR/inner-attrs.rs:27:30: 27:39 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:26:29: 26:40 (#0),
+                        span: $DIR/inner-attrs.rs:27:29: 27:40 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:26:7: 26:41 (#0),
+                span: $DIR/inner-attrs.rs:27:7: 27:41 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
+                span: $DIR/inner-attrs.rs:28:5: 28:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
+                span: $DIR/inner-attrs.rs:28:6: 28:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
+                        span: $DIR/inner-attrs.rs:28:8: 28:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_fourth",
-                                span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
+                                span: $DIR/inner-attrs.rs:28:30: 28:40 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:27:29: 27:41 (#0),
+                        span: $DIR/inner-attrs.rs:28:29: 28:41 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:27:7: 27:42 (#0),
+                span: $DIR/inner-attrs.rs:28:7: 28:42 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
+        span: $DIR/inner-attrs.rs:26:16: 29:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): mod_third
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod_third",
-        span: $DIR/inner-attrs.rs:26:30: 26:39 (#0),
+        span: $DIR/inner-attrs.rs:27:30: 27:39 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): mod inline_mod { #! [print_target_and_args(mod_fourth)] }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod",
-        span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
+        span: $DIR/inner-attrs.rs:26:1: 26:4 (#0),
     },
     Ident {
         ident: "inline_mod",
-        span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
+        span: $DIR/inner-attrs.rs:26:5: 26:15 (#0),
     },
     Group {
         delimiter: Brace,
@@ -514,58 +514,58 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
+                span: $DIR/inner-attrs.rs:28:5: 28:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
+                span: $DIR/inner-attrs.rs:28:6: 28:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
+                        span: $DIR/inner-attrs.rs:28:8: 28:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_fourth",
-                                span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
+                                span: $DIR/inner-attrs.rs:28:30: 28:40 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:27:29: 27:41 (#0),
+                        span: $DIR/inner-attrs.rs:28:29: 28:41 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:27:7: 27:42 (#0),
+                span: $DIR/inner-attrs.rs:28:7: 28:42 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
+        span: $DIR/inner-attrs.rs:26:16: 29:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): mod_fourth
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod_fourth",
-        span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
+        span: $DIR/inner-attrs.rs:28:30: 28:40 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): mod inline_mod {}
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod",
-        span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
+        span: $DIR/inner-attrs.rs:26:1: 26:4 (#0),
     },
     Ident {
         ident: "inline_mod",
-        span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
+        span: $DIR/inner-attrs.rs:26:5: 26:15 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
+        span: $DIR/inner-attrs.rs:26:16: 29:2 (#0),
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): struct MyDerivePrint
@@ -576,63 +576,63 @@ PRINT-DERIVE INPUT (DISPLAY): struct MyDerivePrint
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: $DIR/inner-attrs.rs:35:1: 35:7 (#0),
+        span: $DIR/inner-attrs.rs:36:1: 36:7 (#0),
     },
     Ident {
         ident: "MyDerivePrint",
-        span: $DIR/inner-attrs.rs:35:8: 35:21 (#0),
+        span: $DIR/inner-attrs.rs:36:8: 36:21 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "field",
-                span: $DIR/inner-attrs.rs:36:5: 36:10 (#0),
+                span: $DIR/inner-attrs.rs:37:5: 37:10 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:36:10: 36:11 (#0),
+                span: $DIR/inner-attrs.rs:37:10: 37:11 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "u8",
-                        span: $DIR/inner-attrs.rs:36:13: 36:15 (#0),
+                        span: $DIR/inner-attrs.rs:37:13: 37:15 (#0),
                     },
                     Punct {
                         ch: ';',
                         spacing: Alone,
-                        span: $DIR/inner-attrs.rs:36:15: 36:16 (#0),
+                        span: $DIR/inner-attrs.rs:37:15: 37:16 (#0),
                     },
                     Group {
                         delimiter: Brace,
                         stream: TokenStream [
                             Ident {
                                 ident: "match",
-                                span: $DIR/inner-attrs.rs:37:9: 37:14 (#0),
+                                span: $DIR/inner-attrs.rs:38:9: 38:14 (#0),
                             },
                             Ident {
                                 ident: "true",
-                                span: $DIR/inner-attrs.rs:37:15: 37:19 (#0),
+                                span: $DIR/inner-attrs.rs:38:15: 38:19 (#0),
                             },
                             Group {
                                 delimiter: Brace,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "_",
-                                        span: $DIR/inner-attrs.rs:38:13: 38:14 (#0),
+                                        span: $DIR/inner-attrs.rs:39:13: 39:14 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/inner-attrs.rs:38:15: 38:17 (#0),
+                                        span: $DIR/inner-attrs.rs:39:15: 39:17 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:38:15: 38:17 (#0),
+                                        span: $DIR/inner-attrs.rs:39:15: 39:17 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
@@ -640,69 +640,69 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/inner-attrs.rs:39:17: 39:18 (#0),
+                                                span: $DIR/inner-attrs.rs:40:17: 40:18 (#0),
                                             },
                                             Punct {
                                                 ch: '!',
                                                 spacing: Alone,
-                                                span: $DIR/inner-attrs.rs:39:18: 39:19 (#0),
+                                                span: $DIR/inner-attrs.rs:40:18: 40:19 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "rustc_dummy",
-                                                        span: $DIR/inner-attrs.rs:39:41: 39:52 (#0),
+                                                        span: $DIR/inner-attrs.rs:40:41: 40:52 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "third",
-                                                                span: $DIR/inner-attrs.rs:39:53: 39:58 (#0),
+                                                                span: $DIR/inner-attrs.rs:40:53: 40:58 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/inner-attrs.rs:39:52: 39:59 (#0),
+                                                        span: $DIR/inner-attrs.rs:40:52: 40:59 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/inner-attrs.rs:39:17: 39:18 (#0),
+                                                span: $DIR/inner-attrs.rs:40:17: 40:18 (#0),
                                             },
                                             Ident {
                                                 ident: "true",
-                                                span: $DIR/inner-attrs.rs:40:17: 40:21 (#0),
+                                                span: $DIR/inner-attrs.rs:41:17: 41:21 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:38:18: 41:14 (#0),
+                                        span: $DIR/inner-attrs.rs:39:18: 42:14 (#0),
                                     },
                                 ],
-                                span: $DIR/inner-attrs.rs:37:20: 42:10 (#0),
+                                span: $DIR/inner-attrs.rs:38:20: 43:10 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/inner-attrs.rs:42:10: 42:11 (#0),
+                                span: $DIR/inner-attrs.rs:43:10: 43:11 (#0),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "0",
                                 suffix: None,
-                                span: $DIR/inner-attrs.rs:43:9: 43:10 (#0),
+                                span: $DIR/inner-attrs.rs:44:9: 44:10 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:36:17: 44:6 (#0),
+                        span: $DIR/inner-attrs.rs:37:17: 45:6 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:36:12: 44:7 (#0),
+                span: $DIR/inner-attrs.rs:37:12: 45:7 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:35:22: 45:2 (#0),
+        span: $DIR/inner-attrs.rs:36:22: 46:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "tuple_attrs",
-        span: $DIR/inner-attrs.rs:48:29: 48:40 (#0),
+        span: $DIR/inner-attrs.rs:49:29: 49:40 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): (3, 4, { #! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ;
@@ -714,23 +714,23 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "3",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:49:9: 49:10 (#0),
+                span: $DIR/inner-attrs.rs:50:9: 50:10 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:49:10: 49:11 (#0),
+                span: $DIR/inner-attrs.rs:50:10: 50:11 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "4",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:49:12: 49:13 (#0),
+                span: $DIR/inner-attrs.rs:50:12: 50:13 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:49:13: 49:14 (#0),
+                span: $DIR/inner-attrs.rs:50:13: 50:14 (#0),
             },
             Group {
                 delimiter: Brace,
@@ -738,85 +738,85 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                     Punct {
                         ch: '#',
                         spacing: Joint,
-                        span: $DIR/inner-attrs.rs:50:13: 50:14 (#0),
+                        span: $DIR/inner-attrs.rs:51:13: 51:14 (#0),
                     },
                     Punct {
                         ch: '!',
                         spacing: Alone,
-                        span: $DIR/inner-attrs.rs:50:14: 50:15 (#0),
+                        span: $DIR/inner-attrs.rs:51:14: 51:15 (#0),
                     },
                     Group {
                         delimiter: Bracket,
                         stream: TokenStream [
                             Ident {
                                 ident: "cfg_attr",
-                                span: $DIR/inner-attrs.rs:50:16: 50:24 (#0),
+                                span: $DIR/inner-attrs.rs:51:16: 51:24 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "not",
-                                        span: $DIR/inner-attrs.rs:50:25: 50:28 (#0),
+                                        span: $DIR/inner-attrs.rs:51:25: 51:28 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "FALSE",
-                                                span: $DIR/inner-attrs.rs:50:29: 50:34 (#0),
+                                                span: $DIR/inner-attrs.rs:51:29: 51:34 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:50:28: 50:35 (#0),
+                                        span: $DIR/inner-attrs.rs:51:28: 51:35 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:50:35: 50:36 (#0),
+                                        span: $DIR/inner-attrs.rs:51:35: 51:36 (#0),
                                     },
                                     Ident {
                                         ident: "rustc_dummy",
-                                        span: $DIR/inner-attrs.rs:50:37: 50:48 (#0),
+                                        span: $DIR/inner-attrs.rs:51:37: 51:48 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "innermost",
-                                                span: $DIR/inner-attrs.rs:50:49: 50:58 (#0),
+                                                span: $DIR/inner-attrs.rs:51:49: 51:58 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:50:48: 50:59 (#0),
+                                        span: $DIR/inner-attrs.rs:51:48: 51:59 (#0),
                                     },
                                 ],
-                                span: $DIR/inner-attrs.rs:50:24: 50:60 (#0),
+                                span: $DIR/inner-attrs.rs:51:24: 51:60 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:50:15: 50:61 (#0),
+                        span: $DIR/inner-attrs.rs:51:15: 51:61 (#0),
                     },
                     Literal {
                         kind: Integer,
                         symbol: "5",
                         suffix: None,
-                        span: $DIR/inner-attrs.rs:51:13: 51:14 (#0),
+                        span: $DIR/inner-attrs.rs:52:13: 52:14 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:49:15: 52:10 (#0),
+                span: $DIR/inner-attrs.rs:50:15: 53:10 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:48:43: 53:6 (#0),
+        span: $DIR/inner-attrs.rs:49:43: 54:6 (#0),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:53:6: 53:7 (#0),
+        span: $DIR/inner-attrs.rs:54:6: 54:7 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "tuple_attrs",
-        span: $DIR/inner-attrs.rs:55:29: 55:40 (#0),
+        span: $DIR/inner-attrs.rs:56:29: 56:40 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): (3, 4, { #! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ;
@@ -828,23 +828,23 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "3",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:56:9: 56:10 (#0),
+                span: $DIR/inner-attrs.rs:57:9: 57:10 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:56:10: 56:11 (#0),
+                span: $DIR/inner-attrs.rs:57:10: 57:11 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "4",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:56:12: 56:13 (#0),
+                span: $DIR/inner-attrs.rs:57:12: 57:13 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:56:13: 56:14 (#0),
+                span: $DIR/inner-attrs.rs:57:13: 57:14 (#0),
             },
             Group {
                 delimiter: Brace,
@@ -852,105 +852,105 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                     Punct {
                         ch: '#',
                         spacing: Joint,
-                        span: $DIR/inner-attrs.rs:57:13: 57:14 (#0),
+                        span: $DIR/inner-attrs.rs:58:13: 58:14 (#0),
                     },
                     Punct {
                         ch: '!',
                         spacing: Alone,
-                        span: $DIR/inner-attrs.rs:57:14: 57:15 (#0),
+                        span: $DIR/inner-attrs.rs:58:14: 58:15 (#0),
                     },
                     Group {
                         delimiter: Bracket,
                         stream: TokenStream [
                             Ident {
                                 ident: "cfg_attr",
-                                span: $DIR/inner-attrs.rs:57:16: 57:24 (#0),
+                                span: $DIR/inner-attrs.rs:58:16: 58:24 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "not",
-                                        span: $DIR/inner-attrs.rs:57:25: 57:28 (#0),
+                                        span: $DIR/inner-attrs.rs:58:25: 58:28 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "FALSE",
-                                                span: $DIR/inner-attrs.rs:57:29: 57:34 (#0),
+                                                span: $DIR/inner-attrs.rs:58:29: 58:34 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:57:28: 57:35 (#0),
+                                        span: $DIR/inner-attrs.rs:58:28: 58:35 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:57:35: 57:36 (#0),
+                                        span: $DIR/inner-attrs.rs:58:35: 58:36 (#0),
                                     },
                                     Ident {
                                         ident: "rustc_dummy",
-                                        span: $DIR/inner-attrs.rs:57:37: 57:48 (#0),
+                                        span: $DIR/inner-attrs.rs:58:37: 58:48 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "innermost",
-                                                span: $DIR/inner-attrs.rs:57:49: 57:58 (#0),
+                                                span: $DIR/inner-attrs.rs:58:49: 58:58 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:57:48: 57:59 (#0),
+                                        span: $DIR/inner-attrs.rs:58:48: 58:59 (#0),
                                     },
                                 ],
-                                span: $DIR/inner-attrs.rs:57:24: 57:60 (#0),
+                                span: $DIR/inner-attrs.rs:58:24: 58:60 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:57:15: 57:61 (#0),
+                        span: $DIR/inner-attrs.rs:58:15: 58:61 (#0),
                     },
                     Literal {
                         kind: Integer,
                         symbol: "5",
                         suffix: None,
-                        span: $DIR/inner-attrs.rs:58:13: 58:14 (#0),
+                        span: $DIR/inner-attrs.rs:59:13: 59:14 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:56:15: 59:10 (#0),
+                span: $DIR/inner-attrs.rs:57:15: 60:10 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:55:43: 60:6 (#0),
+        span: $DIR/inner-attrs.rs:56:43: 61:6 (#0),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:60:6: 60:7 (#0),
+        span: $DIR/inner-attrs.rs:61:6: 61:7 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): tenth
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "tenth",
-        span: $DIR/inner-attrs.rs:82:42: 82:47 (#0),
+        span: $DIR/inner-attrs.rs:83:42: 83:47 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn weird_extern() {}
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:81:5: 81:7 (#0),
+        span: $DIR/inner-attrs.rs:82:5: 82:7 (#0),
     },
     Ident {
         ident: "weird_extern",
-        span: $DIR/inner-attrs.rs:81:8: 81:20 (#0),
+        span: $DIR/inner-attrs.rs:82:8: 82:20 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:81:20: 81:22 (#0),
+        span: $DIR/inner-attrs.rs:82:20: 82:22 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:81:23: 83:6 (#0),
+        span: $DIR/inner-attrs.rs:82:23: 84:6 (#0),
     },
 ]
diff --git a/src/test/ui/proc-macro/issue-41211.rs b/src/test/ui/proc-macro/issue-41211.rs
deleted file mode 100644 (file)
index 072a63b..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// aux-build:test-macros.rs
-
-// FIXME: https://github.com/rust-lang/rust/issues/41430
-// This is a temporary regression test for the ICE reported in #41211
-
-#![feature(custom_inner_attributes)]
-#![feature(register_attr)]
-
-#![register_attr(identity_attr)]
-
-#![identity_attr]
-//~^ ERROR `identity_attr` is ambiguous
-extern crate test_macros;
-use test_macros::identity_attr;
-
-fn main() {}
diff --git a/src/test/ui/proc-macro/issue-41211.stderr b/src/test/ui/proc-macro/issue-41211.stderr
deleted file mode 100644 (file)
index 60cd36a..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0659]: `identity_attr` is ambiguous
-  --> $DIR/issue-41211.rs:11:4
-   |
-LL | #![identity_attr]
-   |    ^^^^^^^^^^^^^ ambiguous name
-   |
-   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
-note: `identity_attr` could refer to the attribute macro imported here
-  --> $DIR/issue-41211.rs:14:5
-   |
-LL | use test_macros::identity_attr;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: use `crate::identity_attr` to refer to this attribute macro unambiguously
-note: `identity_attr` could also refer to the explicitly registered attribute defined here
-  --> $DIR/issue-41211.rs:9:18
-   |
-LL | #![register_attr(identity_attr)]
-   |                  ^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0659`.
index bdd1ae91f7d764e9ad8a894dc951be9035932470..a8f7a41c4428495bd821ae66fc46d8726c2b93fd 100644 (file)
@@ -5,7 +5,7 @@
 // by the function.
 //
 // This works today, which precludes changing things so that closures
-// follow the same lifetime-elision rules used elsehwere. See
+// follow the same lifetime-elision rules used elsewhere. See
 // rust-lang/rust#56537
 
 // check-pass
index 3c62782a89799c87d196784c13107c297d3fbbfd..5c2459a59036de4b2498813792a9bfc314b7a4e2 100644 (file)
@@ -22,6 +22,10 @@ enum D {
     Unit,
 }
 
+enum E {
+    TupleWithFields(()),
+}
+
 fn main() {
     // Only variants without fields are suggested (and others mentioned in a note) where an enum
     // is used rather than a variant.
@@ -34,6 +38,8 @@ fn main() {
     //~^ ERROR expected value, found enum `C`
     D.foo();
     //~^ ERROR expected value, found enum `D`
+    E.foo();
+    //~^ ERROR expected value, found enum `E`
 
     // Only tuple variants are suggested in calls or tuple struct pattern matching.
 
index 59bb98a340a5f894803cdf0d2fab79e10a48d67a..a2ca46f0ce964d1cdfbbc4edc4edda39432555fc 100644 (file)
@@ -1,5 +1,5 @@
 error[E0423]: expected value, found enum `A`
-  --> $DIR/issue-73427.rs:29:5
+  --> $DIR/issue-73427.rs:33:5
    |
 LL |     A.foo();
    |     ^
@@ -23,7 +23,7 @@ LL |     (A::Tuple()).foo();
    |     ~~~~~~~~~~~~
 LL |     A::Unit.foo();
    |     ~~~~~~~
-help: the following enum variants are available
+help: alternatively, the following enum variants are also available
    |
 LL |     (A::StructWithFields { /* fields */ }).foo();
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -31,7 +31,7 @@ LL |     (A::TupleWithFields(/* fields */)).foo();
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0423]: expected value, found enum `B`
-  --> $DIR/issue-73427.rs:31:5
+  --> $DIR/issue-73427.rs:35:5
    |
 LL |     B.foo();
    |     ^
@@ -52,7 +52,7 @@ LL |     (B::TupleWithFields(/* fields */)).foo();
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0423]: expected value, found enum `C`
-  --> $DIR/issue-73427.rs:33:5
+  --> $DIR/issue-73427.rs:37:5
    |
 LL |     C.foo();
    |     ^
@@ -70,7 +70,7 @@ help: you might have meant to use the following enum variant
    |
 LL |     C::Unit.foo();
    |     ~~~~~~~
-help: the following enum variants are available
+help: alternatively, the following enum variants are also available
    |
 LL |     (C::StructWithFields { /* fields */ }).foo();
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -78,7 +78,7 @@ LL |     (C::TupleWithFields(/* fields */)).foo();
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0423]: expected value, found enum `D`
-  --> $DIR/issue-73427.rs:35:5
+  --> $DIR/issue-73427.rs:39:5
    |
 LL |     D.foo();
    |     ^
@@ -95,13 +95,37 @@ help: you might have meant to use the following enum variant
    |
 LL |     D::Unit.foo();
    |     ~~~~~~~
-help: the following enum variant is available
+help: alternatively, the following enum variant is available
    |
 LL |     (D::TupleWithFields(/* fields */)).foo();
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+error[E0423]: expected value, found enum `E`
+  --> $DIR/issue-73427.rs:41:5
+   |
+LL |     E.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:25:1
+   |
+LL | / enum E {
+LL | |     TupleWithFields(()),
+LL | | }
+   | |_^
+help: the following enum variant is available
+   |
+LL |     (E::TupleWithFields(/* fields */)).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: consider importing one of these items instead
+   |
+LL | use std::f32::consts::E;
+   |
+LL | use std::f64::consts::E;
+   |
+
 error[E0423]: expected function, tuple struct or tuple variant, found enum `A`
-  --> $DIR/issue-73427.rs:40:13
+  --> $DIR/issue-73427.rs:46:13
    |
 LL |     let x = A(3);
    |             ^
@@ -126,7 +150,7 @@ LL |     let x = A::TupleWithFields(3);
    |             ~~~~~~~~~~~~~~~~~~
 
 error[E0532]: expected tuple struct or tuple variant, found enum `A`
-  --> $DIR/issue-73427.rs:42:12
+  --> $DIR/issue-73427.rs:48:12
    |
 LL |     if let A(3) = x { }
    |            ^
@@ -150,7 +174,7 @@ LL |     if let A::Tuple(3) = x { }
 LL |     if let A::TupleWithFields(3) = x { }
    |            ~~~~~~~~~~~~~~~~~~
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
 Some errors have detailed explanations: E0423, E0532.
 For more information about an error, try `rustc --explain E0423`.
index f885ac2151d6126e520a9d498d971b658c9a153c..a369dc6db52812a9ad4cfa408ecb2548669974e1 100644 (file)
@@ -19,7 +19,7 @@ help: you might have meant to use the following enum variant
    |
 LL |         m::Z::Unit;
    |         ~~~~~~~~~~
-help: the following enum variants are available
+help: alternatively, the following enum variants are also available
    |
 LL |         (m::Z::Fn(/* fields */));
    |         ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -47,7 +47,7 @@ help: you might have meant to use the following enum variant
    |
 LL |         m::Z::Unit;
    |         ~~~~~~~~~~
-help: the following enum variants are available
+help: alternatively, the following enum variants are also available
    |
 LL |         (m::Z::Fn(/* fields */));
    |         ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -89,7 +89,7 @@ help: you might have meant to use the following enum variant
    |
 LL |     let _: E = E::Unit;
    |                ~~~~~~~
-help: the following enum variants are available
+help: alternatively, the following enum variants are also available
    |
 LL |     let _: E = (E::Fn(/* fields */));
    |                ~~~~~~~~~~~~~~~~~~~~~
@@ -143,7 +143,7 @@ help: you might have meant to use the following enum variant
    |
 LL |     let _: E = E::Unit;
    |                ~~~~~~~
-help: the following enum variants are available
+help: alternatively, the following enum variants are also available
    |
 LL |     let _: E = (E::Fn(/* fields */));
    |                ~~~~~~~~~~~~~~~~~~~~~
@@ -203,7 +203,7 @@ help: you might have meant to use the following enum variant
    |
 LL |     let _: Z = m::Z::Unit;
    |                ~~~~~~~~~~
-help: the following enum variants are available
+help: alternatively, the following enum variants are also available
    |
 LL |     let _: Z = (m::Z::Fn(/* fields */));
    |                ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -329,8 +329,8 @@ LL |         let _: Z = Z::Fn;
            found fn item `fn(u8) -> Z {Z::Fn}`
 help: use parentheses to instantiate this tuple variant
    |
-LL |         let _: Z = Z::Fn(_);
-   |                         +++
+LL |         let _: Z = Z::Fn(/* u8 */);
+   |                         ++++++++++
 
 error[E0618]: expected function, found enum variant `Z::Unit`
   --> $DIR/privacy-enum-ctor.rs:31:17
@@ -364,8 +364,8 @@ LL |     let _: E = m::E::Fn;
            found fn item `fn(u8) -> E {E::Fn}`
 help: use parentheses to instantiate this tuple variant
    |
-LL |     let _: E = m::E::Fn(_);
-   |                        +++
+LL |     let _: E = m::E::Fn(/* u8 */);
+   |                        ++++++++++
 
 error[E0618]: expected function, found enum variant `m::E::Unit`
   --> $DIR/privacy-enum-ctor.rs:47:16
@@ -399,8 +399,8 @@ LL |     let _: E = E::Fn;
            found fn item `fn(u8) -> E {E::Fn}`
 help: use parentheses to instantiate this tuple variant
    |
-LL |     let _: E = E::Fn(_);
-   |                     +++
+LL |     let _: E = E::Fn(/* u8 */);
+   |                     ++++++++++
 
 error[E0618]: expected function, found enum variant `E::Unit`
   --> $DIR/privacy-enum-ctor.rs:55:16
index 0fe50932b4bbc0c5724bb43fe231db4260c31d5b..f0105e08e27c3ef12c8883f7bcdde5bda14c5a90 100644 (file)
@@ -8,35 +8,49 @@ fn _if_let_guard() {
         //~^ ERROR `if let` guards are experimental
 
         () if (let 0 = 1) => {}
-        //~^ ERROR expected expression, found `let` statement
+        //~^ ERROR `let` expressions in this position are unstable
+        //~| ERROR expected expression, found `let` statement
 
         () if (((let 0 = 1))) => {}
-        //~^ ERROR expected expression, found `let` statement
+        //~^ ERROR `let` expressions in this position are unstable
+        //~| ERROR expected expression, found `let` statement
 
         () if true && let 0 = 1 => {}
         //~^ ERROR `if let` guards are experimental
+        //~| ERROR `let` expressions in this position are unstable
 
         () if let 0 = 1 && true => {}
         //~^ ERROR `if let` guards are experimental
+        //~| ERROR `let` expressions in this position are unstable
 
         () if (let 0 = 1) && true => {}
-        //~^ ERROR expected expression, found `let` statement
+        //~^ ERROR `let` expressions in this position are unstable
+        //~| ERROR expected expression, found `let` statement
 
         () if true && (let 0 = 1) => {}
-        //~^ ERROR expected expression, found `let` statement
+        //~^ ERROR `let` expressions in this position are unstable
+        //~| ERROR expected expression, found `let` statement
 
         () if (let 0 = 1) && (let 0 = 1) => {}
-        //~^ ERROR expected expression, found `let` statement
+        //~^ ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR expected expression, found `let` statement
         //~| ERROR expected expression, found `let` statement
 
         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
         //~^ ERROR `if let` guards are experimental
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
         //~| ERROR expected expression, found `let` statement
         //~| ERROR expected expression, found `let` statement
         //~| ERROR expected expression, found `let` statement
 
         () if let Range { start: _, end: _ } = (true..true) && false => {}
         //~^ ERROR `if let` guards are experimental
+        //~| ERROR `let` expressions in this position are unstable
 
         _ => {}
     }
@@ -52,9 +66,11 @@ macro_rules! use_expr {
         }
     }
     use_expr!((let 0 = 1 && 0 == 0));
-    //~^ ERROR expected expression, found `let` statement
+    //~^ ERROR `let` expressions in this position are unstable
+    //~| ERROR expected expression, found `let` statement
     use_expr!((let 0 = 1));
-    //~^ ERROR expected expression, found `let` statement
+    //~^ ERROR `let` expressions in this position are unstable
+    //~| ERROR expected expression, found `let` statement
     match () {
         #[cfg(FALSE)]
         () if let 0 = 1 => {}
index 35db84a6cb79ab55cdd6373f7dc827f6adb7461f..e017d04a5c933f987ba2f7a5f37a88ebbc553b0a 100644 (file)
@@ -5,67 +5,67 @@ LL |         () if (let 0 = 1) => {}
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:13:18
+  --> $DIR/feature-gate.rs:14:18
    |
 LL |         () if (((let 0 = 1))) => {}
    |                  ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:22:16
+  --> $DIR/feature-gate.rs:26:16
    |
 LL |         () if (let 0 = 1) && true => {}
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:25:24
+  --> $DIR/feature-gate.rs:30:24
    |
 LL |         () if true && (let 0 = 1) => {}
    |                        ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:28:16
+  --> $DIR/feature-gate.rs:34:16
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:28:31
+  --> $DIR/feature-gate.rs:34:31
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |                               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:32:42
+  --> $DIR/feature-gate.rs:40:42
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                                          ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:32:55
+  --> $DIR/feature-gate.rs:40:55
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                                                       ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:32:68
+  --> $DIR/feature-gate.rs:40:68
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                                                                    ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:54:16
+  --> $DIR/feature-gate.rs:68:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:56:16
+  --> $DIR/feature-gate.rs:71:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
 
 error: no rules expected the token `let`
-  --> $DIR/feature-gate.rs:64:15
+  --> $DIR/feature-gate.rs:80:15
    |
 LL |     macro_rules! use_expr {
    |     --------------------- when calling this macro
@@ -84,7 +84,7 @@ LL |         () if let 0 = 1 => {}
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:16:12
+  --> $DIR/feature-gate.rs:18:12
    |
 LL |         () if true && let 0 = 1 => {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -94,7 +94,7 @@ LL |         () if true && let 0 = 1 => {}
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:19:12
+  --> $DIR/feature-gate.rs:22:12
    |
 LL |         () if let 0 = 1 && true => {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +104,7 @@ LL |         () if let 0 = 1 && true => {}
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:32:12
+  --> $DIR/feature-gate.rs:40:12
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -114,7 +114,7 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:38:12
+  --> $DIR/feature-gate.rs:51:12
    |
 LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -124,7 +124,7 @@ LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:60:12
+  --> $DIR/feature-gate.rs:76:12
    |
 LL |         () if let 0 = 1 => {}
    |            ^^^^^^^^^^^^
@@ -133,6 +133,150 @@ LL |         () if let 0 = 1 => {}
    = help: add `#![feature(if_let_guard)]` to the crate attributes to enable
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
-error: aborting due to 18 previous errors
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:10:16
+   |
+LL |         () if (let 0 = 1) => {}
+   |                ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:14:18
+   |
+LL |         () if (((let 0 = 1))) => {}
+   |                  ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:18:23
+   |
+LL |         () if true && let 0 = 1 => {}
+   |                       ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:22:15
+   |
+LL |         () if let 0 = 1 && true => {}
+   |               ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:26:16
+   |
+LL |         () if (let 0 = 1) && true => {}
+   |                ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:30:24
+   |
+LL |         () if true && (let 0 = 1) => {}
+   |                        ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:34:16
+   |
+LL |         () if (let 0 = 1) && (let 0 = 1) => {}
+   |                ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:34:31
+   |
+LL |         () if (let 0 = 1) && (let 0 = 1) => {}
+   |                               ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:40:15
+   |
+LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
+   |               ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:40:28
+   |
+LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
+   |                            ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:40:42
+   |
+LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
+   |                                          ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:40:55
+   |
+LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
+   |                                                       ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:40:68
+   |
+LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
+   |                                                                    ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:51:15
+   |
+LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:68:16
+   |
+LL |     use_expr!((let 0 = 1 && 0 == 0));
+   |                ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:71:16
+   |
+LL |     use_expr!((let 0 = 1));
+   |                ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error: aborting due to 34 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/allowed-syntax.rs b/src/test/ui/rfc-2497-if-let-chains/allowed-syntax.rs
deleted file mode 100644 (file)
index ffe0499..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// check-pass
-
-#![allow(irrefutable_let_patterns)]
-
-use std::ops::Range;
-
-fn _if() {
-    if let 0 = 1 {}
-
-    if true && let 0 = 1 {}
-
-    if let 0 = 1 && true {}
-
-    if let Range { start: _, end: _ } = (true..true) && false {}
-
-    if let 1 = 1 && let true = { true } && false {
-    }
-}
-
-fn _while() {
-    while let 0 = 1 {}
-
-    while true && let 0 = 1 {}
-
-    while let 0 = 1 && true {}
-
-    while let Range { start: _, end: _ } = (true..true) && false {}
-}
-
-fn main() {}
index 82164bda4897db4a25329048ca47046ab27ff417..d851fac8e644fdac9dc70743538ff83ffc1322e1 100644 (file)
@@ -1,5 +1,6 @@
 // run-pass
 
+#![feature(let_chains)]
 #![allow(irrefutable_let_patterns)]
 
 fn main() {
index e8f1ff9c3fdd251b50bf73993c4dd33126f775e4..2a9a5472b2e5703e753ab40c3a976fa666d2b41a 100644 (file)
@@ -17,6 +17,8 @@
 //
 // To that end, we check some positions which is not part of the language above.
 
+#![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
+
 #![allow(irrefutable_let_patterns)]
 
 use std::ops::Range;
@@ -102,12 +104,6 @@ macro_rules! use_expr {
     //~^ ERROR `let` expressions are not supported here
     //~| ERROR `let` expressions are not supported here
     //~| ERROR expected expression, found `let` statement
-    use_expr!(true && let 0 = 1);
-    //~^ ERROR expected expression, found `let` statement
-
-    macro_rules! noop_expr { ($e:expr) => {}; }
-    noop_expr!((let 0 = 1));
-    //~^ ERROR expected expression, found `let` statement
 }
 
 fn nested_within_if_expr() {
@@ -481,7 +477,4 @@ fn with_parenthesis() {
         ([1, 2, 3][let _ = ()])
         //~^ ERROR expected expression, found `let` statement
     }
-
-    #[cfg(FALSE)] (let 0 = 1);
-    //~^ ERROR expected expression, found `let` statement
 }
index d5d82166a4ac4c5104cec8c2560ec370aa824def..fce0cdfe0d569bb9f0208bd837836537a9102139 100644 (file)
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:27:9
+  --> $DIR/disallowed-positions.rs:29:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:31:11
+  --> $DIR/disallowed-positions.rs:33:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:35:9
+  --> $DIR/disallowed-positions.rs:37:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:39:17
+  --> $DIR/disallowed-positions.rs:41:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:43:9
+  --> $DIR/disallowed-positions.rs:45:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:43:24
+  --> $DIR/disallowed-positions.rs:45:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:51:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:49:48
+  --> $DIR/disallowed-positions.rs:51:48
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:49:61
+  --> $DIR/disallowed-positions.rs:51:61
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                             ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:59:12
+  --> $DIR/disallowed-positions.rs:61:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:63:14
+  --> $DIR/disallowed-positions.rs:65:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:67:12
+  --> $DIR/disallowed-positions.rs:69:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:71:20
+  --> $DIR/disallowed-positions.rs:73:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:75:12
+  --> $DIR/disallowed-positions.rs:77:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:75:27
+  --> $DIR/disallowed-positions.rs:77:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:81:38
+  --> $DIR/disallowed-positions.rs:83:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:81:51
+  --> $DIR/disallowed-positions.rs:83:51
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:81:64
+  --> $DIR/disallowed-positions.rs:83:64
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:114:9
+  --> $DIR/disallowed-positions.rs:110:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:119:9
+  --> $DIR/disallowed-positions.rs:115:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:122:9
+  --> $DIR/disallowed-positions.rs:118:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:126:9
+  --> $DIR/disallowed-positions.rs:122:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:136:9
+  --> $DIR/disallowed-positions.rs:132:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:142:16
+  --> $DIR/disallowed-positions.rs:138:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:145:17
+  --> $DIR/disallowed-positions.rs:141:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:148:25
+  --> $DIR/disallowed-positions.rs:144:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:151:25
+  --> $DIR/disallowed-positions.rs:147:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:156:12
+  --> $DIR/disallowed-positions.rs:152:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:161:15
+  --> $DIR/disallowed-positions.rs:157:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:165:11
+  --> $DIR/disallowed-positions.rs:161:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:169:9
+  --> $DIR/disallowed-positions.rs:165:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:200:19
+  --> $DIR/disallowed-positions.rs:196:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:206:12
+  --> $DIR/disallowed-positions.rs:202:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:211:12
+  --> $DIR/disallowed-positions.rs:207:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:214:12
+  --> $DIR/disallowed-positions.rs:210:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:218:12
+  --> $DIR/disallowed-positions.rs:214:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:228:12
+  --> $DIR/disallowed-positions.rs:224:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:234:19
+  --> $DIR/disallowed-positions.rs:230:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:237:20
+  --> $DIR/disallowed-positions.rs:233:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:240:28
+  --> $DIR/disallowed-positions.rs:236:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:243:28
+  --> $DIR/disallowed-positions.rs:239:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:248:15
+  --> $DIR/disallowed-positions.rs:244:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:253:18
+  --> $DIR/disallowed-positions.rs:249:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:257:14
+  --> $DIR/disallowed-positions.rs:253:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:261:12
+  --> $DIR/disallowed-positions.rs:257:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:292:22
+  --> $DIR/disallowed-positions.rs:288:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:308:6
+  --> $DIR/disallowed-positions.rs:304:6
    |
 LL |     &let 0 = 0;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:312:6
+  --> $DIR/disallowed-positions.rs:308:6
    |
 LL |     !let 0 = 0;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:315:6
+  --> $DIR/disallowed-positions.rs:311:6
    |
 LL |     *let 0 = 0;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:319:6
+  --> $DIR/disallowed-positions.rs:315:6
    |
 LL |     -let 0 = 0;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:329:6
+  --> $DIR/disallowed-positions.rs:325:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:335:13
+  --> $DIR/disallowed-positions.rs:331:13
    |
 LL |     true || let 0 = 0;
    |             ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:338:14
+  --> $DIR/disallowed-positions.rs:334:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:341:22
+  --> $DIR/disallowed-positions.rs:337:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:346:9
+  --> $DIR/disallowed-positions.rs:342:9
    |
 LL |     x = let 0 = 0;
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:350:12
+  --> $DIR/disallowed-positions.rs:346:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:353:8
+  --> $DIR/disallowed-positions.rs:349:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:356:6
+  --> $DIR/disallowed-positions.rs:352:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:360:6
+  --> $DIR/disallowed-positions.rs:356:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:365:6
+  --> $DIR/disallowed-positions.rs:361:6
    |
 LL |     (let true = let true = true);
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:365:17
+  --> $DIR/disallowed-positions.rs:361:17
    |
 LL |     (let true = let true = true);
    |                 ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:372:25
+  --> $DIR/disallowed-positions.rs:368:25
    |
 LL |         let x = true && let y = 1;
    |                         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:378:19
+  --> $DIR/disallowed-positions.rs:374:19
    |
 LL |         [1, 2, 3][let _ = ()]
    |                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:383:6
+  --> $DIR/disallowed-positions.rs:379:6
    |
 LL |     &let 0 = 0
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:395:17
+  --> $DIR/disallowed-positions.rs:391:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:401:17
+  --> $DIR/disallowed-positions.rs:397:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:407:17
+  --> $DIR/disallowed-positions.rs:403:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:419:17
+  --> $DIR/disallowed-positions.rs:415:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions.rs:419:9
+  --> $DIR/disallowed-positions.rs:415:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -418,389 +418,371 @@ LL |         { true && let 1 = 1 }
    |         +                   +
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:429:9
+  --> $DIR/disallowed-positions.rs:425:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:434:9
+  --> $DIR/disallowed-positions.rs:430:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:438:9
+  --> $DIR/disallowed-positions.rs:434:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:438:32
+  --> $DIR/disallowed-positions.rs:434:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:447:9
+  --> $DIR/disallowed-positions.rs:443:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:447:31
+  --> $DIR/disallowed-positions.rs:443:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:453:9
+  --> $DIR/disallowed-positions.rs:449:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:453:31
+  --> $DIR/disallowed-positions.rs:449:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:459:9
+  --> $DIR/disallowed-positions.rs:455:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:476:22
+  --> $DIR/disallowed-positions.rs:472:22
    |
 LL |     let x = (true && let y = 1);
    |                      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:481:20
+  --> $DIR/disallowed-positions.rs:477:20
    |
 LL |         ([1, 2, 3][let _ = ()])
    |                    ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:485:20
-   |
-LL |     #[cfg(FALSE)] (let 0 = 1);
-   |                    ^^^
-
-error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:99:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:101:16
+  --> $DIR/disallowed-positions.rs:103:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
 
-error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:105:23
-   |
-LL |     use_expr!(true && let 0 = 1);
-   |                       ^^^
-
-error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:109:17
-   |
-LL |     noop_expr!((let 0 = 1));
-   |                 ^^^
-
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:27:9
+  --> $DIR/disallowed-positions.rs:29:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:27:9
+  --> $DIR/disallowed-positions.rs:29:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:31:11
+  --> $DIR/disallowed-positions.rs:33:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:31:11
+  --> $DIR/disallowed-positions.rs:33:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:35:9
+  --> $DIR/disallowed-positions.rs:37:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:35:9
+  --> $DIR/disallowed-positions.rs:37:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:39:17
+  --> $DIR/disallowed-positions.rs:41:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:39:17
+  --> $DIR/disallowed-positions.rs:41:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:43:9
+  --> $DIR/disallowed-positions.rs:45:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:43:9
+  --> $DIR/disallowed-positions.rs:45:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:43:24
+  --> $DIR/disallowed-positions.rs:45:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:43:24
+  --> $DIR/disallowed-positions.rs:45:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:51:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:51:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:49:48
+  --> $DIR/disallowed-positions.rs:51:48
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:51:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:49:61
+  --> $DIR/disallowed-positions.rs:51:61
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                             ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:51:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:59:12
+  --> $DIR/disallowed-positions.rs:61:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:59:12
+  --> $DIR/disallowed-positions.rs:61:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:63:14
+  --> $DIR/disallowed-positions.rs:65:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:63:14
+  --> $DIR/disallowed-positions.rs:65:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:67:12
+  --> $DIR/disallowed-positions.rs:69:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:67:12
+  --> $DIR/disallowed-positions.rs:69:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:71:20
+  --> $DIR/disallowed-positions.rs:73:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:71:20
+  --> $DIR/disallowed-positions.rs:73:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:75:12
+  --> $DIR/disallowed-positions.rs:77:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:75:12
+  --> $DIR/disallowed-positions.rs:77:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:75:27
+  --> $DIR/disallowed-positions.rs:77:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:75:27
+  --> $DIR/disallowed-positions.rs:77:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:81:38
+  --> $DIR/disallowed-positions.rs:83:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:81:38
+  --> $DIR/disallowed-positions.rs:83:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:81:51
+  --> $DIR/disallowed-positions.rs:83:51
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:81:38
+  --> $DIR/disallowed-positions.rs:83:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:81:64
+  --> $DIR/disallowed-positions.rs:83:64
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:81:38
+  --> $DIR/disallowed-positions.rs:83:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:99:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:99:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:99:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:99:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:101:16
+  --> $DIR/disallowed-positions.rs:103:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:101:16
+  --> $DIR/disallowed-positions.rs:103:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:101:16
+  --> $DIR/disallowed-positions.rs:103:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:101:16
+  --> $DIR/disallowed-positions.rs:103:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:114:9
+  --> $DIR/disallowed-positions.rs:110:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
@@ -808,7 +790,7 @@ LL |     if &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:119:9
+  --> $DIR/disallowed-positions.rs:115:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
@@ -816,7 +798,7 @@ LL |     if !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:122:9
+  --> $DIR/disallowed-positions.rs:118:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
@@ -824,7 +806,7 @@ LL |     if *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:126:9
+  --> $DIR/disallowed-positions.rs:122:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
@@ -832,72 +814,72 @@ LL |     if -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:136:9
+  --> $DIR/disallowed-positions.rs:132:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:136:9
+  --> $DIR/disallowed-positions.rs:132:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:142:16
+  --> $DIR/disallowed-positions.rs:138:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:142:13
+  --> $DIR/disallowed-positions.rs:138:13
    |
 LL |     if true || let 0 = 0 {}
    |             ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:145:17
+  --> $DIR/disallowed-positions.rs:141:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:145:14
+  --> $DIR/disallowed-positions.rs:141:14
    |
 LL |     if (true || let 0 = 0) {}
    |              ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:148:25
+  --> $DIR/disallowed-positions.rs:144:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:148:22
+  --> $DIR/disallowed-positions.rs:144:22
    |
 LL |     if true && (true || let 0 = 0) {}
    |                      ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:151:25
+  --> $DIR/disallowed-positions.rs:147:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:151:17
+  --> $DIR/disallowed-positions.rs:147:17
    |
 LL |     if true || (true && let 0 = 0) {}
    |                 ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:156:12
+  --> $DIR/disallowed-positions.rs:152:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^^^^^^^
@@ -905,46 +887,46 @@ LL |     if x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:161:15
+  --> $DIR/disallowed-positions.rs:157:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:161:15
+  --> $DIR/disallowed-positions.rs:157:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:165:11
+  --> $DIR/disallowed-positions.rs:161:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:165:11
+  --> $DIR/disallowed-positions.rs:161:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:169:9
+  --> $DIR/disallowed-positions.rs:165:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:169:9
+  --> $DIR/disallowed-positions.rs:165:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:175:8
+  --> $DIR/disallowed-positions.rs:171:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -952,7 +934,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:179:8
+  --> $DIR/disallowed-positions.rs:175:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -960,7 +942,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:186:8
+  --> $DIR/disallowed-positions.rs:182:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -968,7 +950,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:194:8
+  --> $DIR/disallowed-positions.rs:190:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -976,7 +958,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:200:19
+  --> $DIR/disallowed-positions.rs:196:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^^^^^^^^^^^^^
@@ -984,7 +966,7 @@ LL |     if let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:206:12
+  --> $DIR/disallowed-positions.rs:202:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
@@ -992,7 +974,7 @@ LL |     while &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:211:12
+  --> $DIR/disallowed-positions.rs:207:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
@@ -1000,7 +982,7 @@ LL |     while !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:214:12
+  --> $DIR/disallowed-positions.rs:210:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
@@ -1008,7 +990,7 @@ LL |     while *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:218:12
+  --> $DIR/disallowed-positions.rs:214:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
@@ -1016,72 +998,72 @@ LL |     while -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:228:12
+  --> $DIR/disallowed-positions.rs:224:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:228:12
+  --> $DIR/disallowed-positions.rs:224:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:234:19
+  --> $DIR/disallowed-positions.rs:230:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:234:16
+  --> $DIR/disallowed-positions.rs:230:16
    |
 LL |     while true || let 0 = 0 {}
    |                ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:237:20
+  --> $DIR/disallowed-positions.rs:233:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:237:17
+  --> $DIR/disallowed-positions.rs:233:17
    |
 LL |     while (true || let 0 = 0) {}
    |                 ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:240:28
+  --> $DIR/disallowed-positions.rs:236:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:240:25
+  --> $DIR/disallowed-positions.rs:236:25
    |
 LL |     while true && (true || let 0 = 0) {}
    |                         ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:243:28
+  --> $DIR/disallowed-positions.rs:239:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:243:20
+  --> $DIR/disallowed-positions.rs:239:20
    |
 LL |     while true || (true && let 0 = 0) {}
    |                    ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:248:15
+  --> $DIR/disallowed-positions.rs:244:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^^^^^^^
@@ -1089,46 +1071,46 @@ LL |     while x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:253:18
+  --> $DIR/disallowed-positions.rs:249:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:253:18
+  --> $DIR/disallowed-positions.rs:249:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:257:14
+  --> $DIR/disallowed-positions.rs:253:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:257:14
+  --> $DIR/disallowed-positions.rs:253:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:261:12
+  --> $DIR/disallowed-positions.rs:257:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:261:12
+  --> $DIR/disallowed-positions.rs:257:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:267:11
+  --> $DIR/disallowed-positions.rs:263:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1136,7 +1118,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:271:11
+  --> $DIR/disallowed-positions.rs:267:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1144,7 +1126,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:278:11
+  --> $DIR/disallowed-positions.rs:274:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1152,7 +1134,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:286:11
+  --> $DIR/disallowed-positions.rs:282:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1160,7 +1142,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:292:22
+  --> $DIR/disallowed-positions.rs:288:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^^^^^^^^^^^^^
@@ -1168,7 +1150,7 @@ LL |     while let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:308:6
+  --> $DIR/disallowed-positions.rs:304:6
    |
 LL |     &let 0 = 0;
    |      ^^^^^^^^^
@@ -1176,7 +1158,7 @@ LL |     &let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:312:6
+  --> $DIR/disallowed-positions.rs:308:6
    |
 LL |     !let 0 = 0;
    |      ^^^^^^^^^
@@ -1184,7 +1166,7 @@ LL |     !let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:315:6
+  --> $DIR/disallowed-positions.rs:311:6
    |
 LL |     *let 0 = 0;
    |      ^^^^^^^^^
@@ -1192,7 +1174,7 @@ LL |     *let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:319:6
+  --> $DIR/disallowed-positions.rs:315:6
    |
 LL |     -let 0 = 0;
    |      ^^^^^^^^^
@@ -1200,59 +1182,59 @@ LL |     -let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:329:6
+  --> $DIR/disallowed-positions.rs:325:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:329:6
+  --> $DIR/disallowed-positions.rs:325:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:335:13
+  --> $DIR/disallowed-positions.rs:331:13
    |
 LL |     true || let 0 = 0;
    |             ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:335:10
+  --> $DIR/disallowed-positions.rs:331:10
    |
 LL |     true || let 0 = 0;
    |          ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:338:14
+  --> $DIR/disallowed-positions.rs:334:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:338:11
+  --> $DIR/disallowed-positions.rs:334:11
    |
 LL |     (true || let 0 = 0);
    |           ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:341:22
+  --> $DIR/disallowed-positions.rs:337:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:341:19
+  --> $DIR/disallowed-positions.rs:337:19
    |
 LL |     true && (true || let 0 = 0);
    |                   ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:346:9
+  --> $DIR/disallowed-positions.rs:342:9
    |
 LL |     x = let 0 = 0;
    |         ^^^^^^^^^
@@ -1260,46 +1242,46 @@ LL |     x = let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:350:12
+  --> $DIR/disallowed-positions.rs:346:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:350:12
+  --> $DIR/disallowed-positions.rs:346:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:353:8
+  --> $DIR/disallowed-positions.rs:349:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:353:8
+  --> $DIR/disallowed-positions.rs:349:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:356:6
+  --> $DIR/disallowed-positions.rs:352:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:356:6
+  --> $DIR/disallowed-positions.rs:352:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:360:6
+  --> $DIR/disallowed-positions.rs:356:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1307,20 +1289,20 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:365:6
+  --> $DIR/disallowed-positions.rs:361:6
    |
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:365:6
+  --> $DIR/disallowed-positions.rs:361:6
    |
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:383:6
+  --> $DIR/disallowed-positions.rs:379:6
    |
 LL |     &let 0 = 0
    |      ^^^^^^^^^
@@ -1328,7 +1310,7 @@ LL |     &let 0 = 0
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:395:17
+  --> $DIR/disallowed-positions.rs:391:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -1336,7 +1318,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:401:17
+  --> $DIR/disallowed-positions.rs:397:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -1344,7 +1326,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:407:17
+  --> $DIR/disallowed-positions.rs:403:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -1352,7 +1334,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:419:17
+  --> $DIR/disallowed-positions.rs:415:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -1360,124 +1342,124 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:429:9
+  --> $DIR/disallowed-positions.rs:425:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:429:9
+  --> $DIR/disallowed-positions.rs:425:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:434:9
+  --> $DIR/disallowed-positions.rs:430:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:434:9
+  --> $DIR/disallowed-positions.rs:430:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:438:9
+  --> $DIR/disallowed-positions.rs:434:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:438:9
+  --> $DIR/disallowed-positions.rs:434:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:438:32
+  --> $DIR/disallowed-positions.rs:434:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:438:32
+  --> $DIR/disallowed-positions.rs:434:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:447:9
+  --> $DIR/disallowed-positions.rs:443:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:447:9
+  --> $DIR/disallowed-positions.rs:443:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:447:31
+  --> $DIR/disallowed-positions.rs:443:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:447:31
+  --> $DIR/disallowed-positions.rs:443:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:453:9
+  --> $DIR/disallowed-positions.rs:449:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:453:9
+  --> $DIR/disallowed-positions.rs:449:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:453:31
+  --> $DIR/disallowed-positions.rs:449:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:453:31
+  --> $DIR/disallowed-positions.rs:449:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:459:9
+  --> $DIR/disallowed-positions.rs:455:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:459:9
+  --> $DIR/disallowed-positions.rs:455:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:114:8
+  --> $DIR/disallowed-positions.rs:110:8
    |
 LL |     if &let 0 = 0 {}
    |        ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -1489,19 +1471,19 @@ LL +     if let 0 = 0 {}
    |
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:122:8
+  --> $DIR/disallowed-positions.rs:118:8
    |
 LL |     if *let 0 = 0 {}
    |        ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:126:8
+  --> $DIR/disallowed-positions.rs:122:8
    |
 LL |     if -let 0 = 0 {}
    |        ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:136:8
+  --> $DIR/disallowed-positions.rs:132:8
    |
 LL |     if (let 0 = 0)? {}
    |        ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -1509,7 +1491,7 @@ LL |     if (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:136:19
+  --> $DIR/disallowed-positions.rs:132:19
    |
 LL | / fn nested_within_if_expr() {
 LL | |     if &let 0 = 0 {}
@@ -1526,7 +1508,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:156:8
+  --> $DIR/disallowed-positions.rs:152:8
    |
 LL |     if x = let 0 = 0 {}
    |        ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -1537,7 +1519,7 @@ LL |     if x == let 0 = 0 {}
    |          ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:161:8
+  --> $DIR/disallowed-positions.rs:157:8
    |
 LL |     if true..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1546,7 +1528,7 @@ LL |     if true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:165:8
+  --> $DIR/disallowed-positions.rs:161:8
    |
 LL |     if ..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -1555,7 +1537,7 @@ LL |     if ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:169:8
+  --> $DIR/disallowed-positions.rs:165:8
    |
 LL |     if (let 0 = 0).. {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -1564,7 +1546,7 @@ LL |     if (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:175:12
+  --> $DIR/disallowed-positions.rs:171:12
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1575,7 +1557,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:175:8
+  --> $DIR/disallowed-positions.rs:171:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1584,7 +1566,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:179:12
+  --> $DIR/disallowed-positions.rs:175:12
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1595,7 +1577,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:179:8
+  --> $DIR/disallowed-positions.rs:175:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1604,7 +1586,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:186:12
+  --> $DIR/disallowed-positions.rs:182:12
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -1615,20 +1597,20 @@ LL |     if let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:186:41
+  --> $DIR/disallowed-positions.rs:182:41
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |                                         ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:186:41: 186:43]`
+           found closure `[closure@$DIR/disallowed-positions.rs:182:41: 182:43]`
 help: use parentheses to call this closure
    |
 LL |     if let Range { start: F, end } = F..(|| true)() {}
    |                                         +       +++
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:186:8
+  --> $DIR/disallowed-positions.rs:182:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1637,7 +1619,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:194:12
+  --> $DIR/disallowed-positions.rs:190:12
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -1648,7 +1630,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:194:44
+  --> $DIR/disallowed-positions.rs:190:44
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |                                            ^^^^^^^ expected `bool`, found `&&bool`
@@ -1660,7 +1642,7 @@ LL +     if let Range { start: true, end } = t..false {}
    |
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:194:8
+  --> $DIR/disallowed-positions.rs:190:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1669,7 +1651,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:132:20
+  --> $DIR/disallowed-positions.rs:128:20
    |
 LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1677,7 +1659,7 @@ LL |         if let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:206:11
+  --> $DIR/disallowed-positions.rs:202:11
    |
 LL |     while &let 0 = 0 {}
    |           ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -1689,19 +1671,19 @@ LL +     while let 0 = 0 {}
    |
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:214:11
+  --> $DIR/disallowed-positions.rs:210:11
    |
 LL |     while *let 0 = 0 {}
    |           ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:218:11
+  --> $DIR/disallowed-positions.rs:214:11
    |
 LL |     while -let 0 = 0 {}
    |           ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:228:11
+  --> $DIR/disallowed-positions.rs:224:11
    |
 LL |     while (let 0 = 0)? {}
    |           ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -1709,7 +1691,7 @@ LL |     while (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:228:22
+  --> $DIR/disallowed-positions.rs:224:22
    |
 LL | / fn nested_within_while_expr() {
 LL | |     while &let 0 = 0 {}
@@ -1726,7 +1708,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:248:11
+  --> $DIR/disallowed-positions.rs:244:11
    |
 LL |     while x = let 0 = 0 {}
    |           ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -1737,7 +1719,7 @@ LL |     while x == let 0 = 0 {}
    |             ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:253:11
+  --> $DIR/disallowed-positions.rs:249:11
    |
 LL |     while true..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1746,7 +1728,7 @@ LL |     while true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:257:11
+  --> $DIR/disallowed-positions.rs:253:11
    |
 LL |     while ..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -1755,7 +1737,7 @@ LL |     while ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:261:11
+  --> $DIR/disallowed-positions.rs:257:11
    |
 LL |     while (let 0 = 0).. {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -1764,7 +1746,7 @@ LL |     while (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:267:15
+  --> $DIR/disallowed-positions.rs:263:15
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1775,7 +1757,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:267:11
+  --> $DIR/disallowed-positions.rs:263:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1784,7 +1766,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:271:15
+  --> $DIR/disallowed-positions.rs:267:15
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1795,7 +1777,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:271:11
+  --> $DIR/disallowed-positions.rs:267:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1804,7 +1786,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:278:15
+  --> $DIR/disallowed-positions.rs:274:15
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -1815,20 +1797,20 @@ LL |     while let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:278:44
+  --> $DIR/disallowed-positions.rs:274:44
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |                                            ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:278:44: 278:46]`
+           found closure `[closure@$DIR/disallowed-positions.rs:274:44: 274:46]`
 help: use parentheses to call this closure
    |
 LL |     while let Range { start: F, end } = F..(|| true)() {}
    |                                            +       +++
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:278:11
+  --> $DIR/disallowed-positions.rs:274:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1837,7 +1819,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:286:15
+  --> $DIR/disallowed-positions.rs:282:15
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -1848,7 +1830,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:286:47
+  --> $DIR/disallowed-positions.rs:282:47
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |                                               ^^^^^^^ expected `bool`, found `&&bool`
@@ -1860,7 +1842,7 @@ LL +     while let Range { start: true, end } = t..false {}
    |
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:286:11
+  --> $DIR/disallowed-positions.rs:282:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1869,7 +1851,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:224:23
+  --> $DIR/disallowed-positions.rs:220:23
    |
 LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1877,19 +1859,19 @@ LL |         while let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:315:5
+  --> $DIR/disallowed-positions.rs:311:5
    |
 LL |     *let 0 = 0;
    |     ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:319:5
+  --> $DIR/disallowed-positions.rs:315:5
    |
 LL |     -let 0 = 0;
    |     ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:329:5
+  --> $DIR/disallowed-positions.rs:325:5
    |
 LL |     (let 0 = 0)?;
    |     ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -1897,7 +1879,7 @@ LL |     (let 0 = 0)?;
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:329:16
+  --> $DIR/disallowed-positions.rs:325:16
    |
 LL | / fn outside_if_and_while_expr() {
 LL | |     &let 0 = 0;
@@ -1914,7 +1896,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:360:10
+  --> $DIR/disallowed-positions.rs:356:10
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1925,7 +1907,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:383:5
+  --> $DIR/disallowed-positions.rs:379:5
    |
 LL | fn outside_if_and_while_expr() {
    |                                - help: try adding a return type: `-> &bool`
@@ -1934,14 +1916,14 @@ LL |     &let 0 = 0
    |     ^^^^^^^^^^ expected `()`, found `&bool`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:325:17
+  --> $DIR/disallowed-positions.rs:321:17
    |
 LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
 
-error: aborting due to 218 previous errors
+error: aborting due to 215 previous errors
 
 Some errors have detailed explanations: E0277, E0308, E0600, E0614.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
new file mode 100644 (file)
index 0000000..2b407ef
--- /dev/null
@@ -0,0 +1,62 @@
+// gate-test-let_chains
+
+// Here we test feature gating for ´let_chains`.
+// See `disallowed-positions.rs` for the grammar
+// defining the language for gated allowed positions.
+
+#![allow(irrefutable_let_patterns)]
+
+use std::ops::Range;
+
+fn _if() {
+    if let 0 = 1 {} // Stable!
+
+    if true && let 0 = 1 {}
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+
+    if let 0 = 1 && true {}
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+
+    if let Range { start: _, end: _ } = (true..true) && false {}
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+
+    if let 1 = 1 && let true = { true } && false {
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    }
+}
+
+fn _while() {
+    while let 0 = 1 {} // Stable!
+
+    while true && let 0 = 1 {}
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+
+    while let 0 = 1 && true {}
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+
+    while let Range { start: _, end: _ } = (true..true) && false {}
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+}
+
+fn _macros() {
+    macro_rules! noop_expr { ($e:expr) => {}; }
+
+    noop_expr!((let 0 = 1));
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR expected expression, found `let` statement
+
+    macro_rules! use_expr {
+        ($e:expr) => {
+            if $e {}
+            while $e {}
+        }
+    }
+    #[cfg(FALSE)] (let 0 = 1);
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR expected expression, found `let` statement
+    use_expr!(let 0 = 1);
+    //~^ ERROR no rules expected the token `let`
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
new file mode 100644 (file)
index 0000000..feea1c2
--- /dev/null
@@ -0,0 +1,114 @@
+error: expected expression, found `let` statement
+  --> $DIR/feature-gate.rs:55:20
+   |
+LL |     #[cfg(FALSE)] (let 0 = 1);
+   |                    ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/feature-gate.rs:45:17
+   |
+LL |     noop_expr!((let 0 = 1));
+   |                 ^^^
+
+error: no rules expected the token `let`
+  --> $DIR/feature-gate.rs:58:15
+   |
+LL |     macro_rules! use_expr {
+   |     --------------------- when calling this macro
+...
+LL |     use_expr!(let 0 = 1);
+   |               ^^^ no rules expected this token in macro call
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:14:16
+   |
+LL |     if true && let 0 = 1 {}
+   |                ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:17:8
+   |
+LL |     if let 0 = 1 && true {}
+   |        ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:20:8
+   |
+LL |     if let Range { start: _, end: _ } = (true..true) && false {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:23:8
+   |
+LL |     if let 1 = 1 && let true = { true } && false {
+   |        ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:23:21
+   |
+LL |     if let 1 = 1 && let true = { true } && false {
+   |                     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:32:19
+   |
+LL |     while true && let 0 = 1 {}
+   |                   ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:35:11
+   |
+LL |     while let 0 = 1 && true {}
+   |           ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:38:11
+   |
+LL |     while let Range { start: _, end: _ } = (true..true) && false {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:55:20
+   |
+LL |     #[cfg(FALSE)] (let 0 = 1);
+   |                    ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/feature-gate.rs:45:17
+   |
+LL |     noop_expr!((let 0 = 1));
+   |                 ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
index 7bc6d43a7276a90bb16e565a1550946105dcccb9..a942d1f4cafbfaccc17095f143907126aa0e0bb0 100644 (file)
@@ -1,3 +1,5 @@
+#![feature(let_chains)]
+
 fn main() {
     let _opt = Some(1i32);
 
index d1552a0b2d5ad2d3214a6073d95e77b489d5fbad..d1ce83c723329d2bf7e64d75bc3fe9a48d370666 100644 (file)
@@ -1,35 +1,35 @@
 error: expected expression, found `let` statement
-  --> $DIR/invalid-let-in-a-valid-let-context.rs:6:19
+  --> $DIR/invalid-let-in-a-valid-let-context.rs:8:19
    |
 LL |         let _ = &&let Some(x) = Some(42);
    |                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/invalid-let-in-a-valid-let-context.rs:11:47
+  --> $DIR/invalid-let-in-a-valid-let-context.rs:13:47
    |
 LL |         if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] = 1 {
    |                                               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/invalid-let-in-a-valid-let-context.rs:11:57
+  --> $DIR/invalid-let-in-a-valid-let-context.rs:13:57
    |
 LL |         if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] = 1 {
    |                                                         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/invalid-let-in-a-valid-let-context.rs:21:23
+  --> $DIR/invalid-let-in-a-valid-let-context.rs:23:23
    |
 LL |             [1, 2, 3][let _ = ()];
    |                       ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/invalid-let-in-a-valid-let-context.rs:30:47
+  --> $DIR/invalid-let-in-a-valid-let-context.rs:32:47
    |
 LL |         if let Some(elem) = _opt && [1, 2, 3][let _ = ()] = 1 {
    |                                               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/invalid-let-in-a-valid-let-context.rs:38:21
+  --> $DIR/invalid-let-in-a-valid-let-context.rs:40:21
    |
 LL |             let x = let y = 1;
    |                     ^^^
index 1ef4bc56e52521b3f569fd81271f1a26dadd0de1..3d1626e8ffb9adb95afc00a8db2aa8e40279be6e 100644 (file)
@@ -1,7 +1,7 @@
 // revisions: allowed disallowed
 //[allowed] check-pass
 
-#![feature(if_let_guard)]
+#![feature(if_let_guard, let_chains)]
 #![cfg_attr(allowed, allow(irrefutable_let_patterns))]
 #![cfg_attr(disallowed, deny(irrefutable_let_patterns))]
 
index 34302ba96d3a2437fbc59824b9818c0847872b1d..6b7d88356508549ce72a53ad57afd2daa952420a 100644 (file)
@@ -1,5 +1,7 @@
 // check-pass
 
+#![feature(let_chains)]
+
 fn main() {
     let x = Some(vec!["test"]);
 
index 6938062fa35f04a0d51ae00b0ee2b64b68451e27..7c7e31f4db4007e5a8f7d443239f86af4c77f942 100644 (file)
@@ -1,5 +1,7 @@
 // check-pass
 
+#![feature(let_chains)]
+
 fn main() {
     let opt = Some("foo bar");
 
index f6de37867d85566b84fb0266c0fe5e5f7101faa9..f90b9ab0d40f03c9823583dc785d1e78f56749c8 100644 (file)
@@ -2,6 +2,7 @@ fn main() {
     match true {
         _ if let true = true && true => {}
         //~^ ERROR `if let` guards are
+        //~| ERROR `let` expressions in this
         _ => {}
     }
 }
index 0d620df96f6105ec0084baa5ced17c10554f1618..b25f299a2190f939eb8bddcef3fa4e15d9eedd24 100644 (file)
@@ -8,6 +8,15 @@ LL |         _ if let true = true && true => {}
    = help: add `#![feature(if_let_guard)]` to the crate attributes to enable
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
-error: aborting due to previous error
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/issue-93150.rs:3:14
+   |
+LL |         _ if let true = true && true => {}
+   |              ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index beaca33d5636401c0e043576f2529e1ca7556ded..e061174f667d97a68384d77c36e295d0d52979de 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-#![feature(if_let_guard)]
+#![feature(if_let_guard, let_chains)]
 
 fn check_if_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
     if let Some(first) = opt
index 83f79679c6e67f7b16d38f9bfce6f5ae5a6637e3..adda51f6be0ecb97eddee6bae8a86136153594ce 100644 (file)
@@ -14,6 +14,7 @@
 #![feature(core_intrinsics)]
 #![feature(start)]
 #![feature(bench_black_box)]
+#![allow(invalid_value)]
 
 use std::hint::black_box;
 use std::mem::MaybeUninit;
diff --git a/src/test/ui/span/issue-36530.rs b/src/test/ui/span/issue-36530.rs
deleted file mode 100644 (file)
index 70e04bf..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// gate-test-custom_inner_attributes
-
-#![feature(register_attr)]
-
-#![register_attr(foo)]
-
-#[foo]
-mod foo {
-    #![foo] //~ ERROR custom inner attributes are unstable
-}
-
-fn main() {}
diff --git a/src/test/ui/span/issue-36530.stderr b/src/test/ui/span/issue-36530.stderr
deleted file mode 100644 (file)
index a998d72..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: custom inner attributes are unstable
-  --> $DIR/issue-36530.rs:9:8
-   |
-LL |     #![foo]
-   |        ^^^
-   |
-   = note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
-   = help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
index 4d19230df6badfacbed2d791e4fb94bb56fdf3c8..8dbadf58d5c888262bd183ea911f656e6142925f 100644 (file)
@@ -1,4 +1,4 @@
-// Test to ensure that trait bounds are propertly
+// Test to ensure that trait bounds are properly
 // checked on specializable associated types
 
 #![allow(incomplete_features)]
diff --git a/src/test/ui/suggestions/call-boxed.rs b/src/test/ui/suggestions/call-boxed.rs
new file mode 100644 (file)
index 0000000..d19e459
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+    let mut x = 1i32;
+    let y = Box::new(|| 1);
+    x = y;
+    //~^ ERROR mismatched types
+    //~| HELP use parentheses to call this closure
+}
diff --git a/src/test/ui/suggestions/call-boxed.stderr b/src/test/ui/suggestions/call-boxed.stderr
new file mode 100644 (file)
index 0000000..9b619ac
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/call-boxed.rs:4:9
+   |
+LL |     let mut x = 1i32;
+   |                 ---- expected due to this value
+LL |     let y = Box::new(|| 1);
+   |                      -- the found closure
+LL |     x = y;
+   |         ^ expected `i32`, found struct `Box`
+   |
+   = note: expected type `i32`
+            found struct `Box<[closure@$DIR/call-boxed.rs:3:22: 3:24]>`
+help: use parentheses to call this closure
+   |
+LL |     x = y();
+   |          ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/call-on-missing.rs b/src/test/ui/suggestions/call-on-missing.rs
new file mode 100644 (file)
index 0000000..25ced84
--- /dev/null
@@ -0,0 +1,39 @@
+struct Foo { i: i32 }
+
+impl Foo {
+    fn bar(&self) {}
+}
+
+fn foo() -> Foo {
+    Foo { i: 1 }
+}
+
+fn main() {
+    foo.bar();
+    //~^ ERROR no method named `bar`
+    //~| HELP use parentheses to call this function
+
+    foo.i;
+    //~^ ERROR no field `i`
+    //~| HELP use parentheses to call this function
+
+    let callable = Box::new(|| Foo { i: 1 }) as Box<dyn Fn() -> Foo>;
+
+    callable.bar();
+    //~^ ERROR no method named `bar`
+    //~| HELP use parentheses to call this trait object
+
+    callable.i;
+    //~^ ERROR no field `i`
+    //~| HELP use parentheses to call this trait object
+}
+
+fn type_param<T: Fn() -> Foo>(t: T) {
+    t.bar();
+    //~^ ERROR no method named `bar`
+    //~| HELP use parentheses to call this type parameter
+
+    t.i;
+    //~^ ERROR no field `i`
+    //~| HELP use parentheses to call this type parameter
+}
diff --git a/src/test/ui/suggestions/call-on-missing.stderr b/src/test/ui/suggestions/call-on-missing.stderr
new file mode 100644 (file)
index 0000000..ca9abc7
--- /dev/null
@@ -0,0 +1,75 @@
+error[E0599]: no method named `bar` found for fn item `fn() -> Foo {foo}` in the current scope
+  --> $DIR/call-on-missing.rs:12:9
+   |
+LL |     foo.bar();
+   |         ^^^ method not found in `fn() -> Foo {foo}`
+   |
+help: use parentheses to call this function
+   |
+LL |     foo().bar();
+   |        ++
+
+error[E0609]: no field `i` on type `fn() -> Foo {foo}`
+  --> $DIR/call-on-missing.rs:16:9
+   |
+LL |     foo.i;
+   |         ^
+   |
+help: use parentheses to call this function
+   |
+LL |     foo().i;
+   |        ++
+
+error[E0599]: no method named `bar` found for struct `Box<dyn Fn() -> Foo>` in the current scope
+  --> $DIR/call-on-missing.rs:22:14
+   |
+LL |     callable.bar();
+   |              ^^^ method not found in `Box<dyn Fn() -> Foo>`
+   |
+help: use parentheses to call this trait object
+   |
+LL |     callable().bar();
+   |             ++
+
+error[E0609]: no field `i` on type `Box<dyn Fn() -> Foo>`
+  --> $DIR/call-on-missing.rs:26:14
+   |
+LL |     callable.i;
+   |              ^ unknown field
+   |
+help: use parentheses to call this trait object
+   |
+LL |     callable().i;
+   |             ++
+
+error[E0599]: no method named `bar` found for type parameter `T` in the current scope
+  --> $DIR/call-on-missing.rs:32:7
+   |
+LL | fn type_param<T: Fn() -> Foo>(t: T) {
+   |               - method `bar` not found for this type parameter
+LL |     t.bar();
+   |       ^^^ method not found in `T`
+   |
+help: use parentheses to call this type parameter
+   |
+LL |     t().bar();
+   |      ++
+
+error[E0609]: no field `i` on type `T`
+  --> $DIR/call-on-missing.rs:36:7
+   |
+LL | fn type_param<T: Fn() -> Foo>(t: T) {
+   |               - type parameter 'T' declared here
+...
+LL |     t.i;
+   |       ^
+   |
+help: use parentheses to call this type parameter
+   |
+LL |     t().i;
+   |      ++
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0599, E0609.
+For more information about an error, try `rustc --explain E0599`.
index e75ce0da82e51ef25f52b0469b336c39fdb65168..3c7b895e337e72c8ee20a9e38dbd4f964dcc2d52 100644 (file)
@@ -33,8 +33,8 @@ LL |     let _: usize = foo;
            found fn item `fn(usize, usize) -> usize {foo}`
 help: use parentheses to call this function
    |
-LL |     let _: usize = foo(_, _);
-   |                       ++++++
+LL |     let _: usize = foo(/* usize */, /* usize */);
+   |                       ++++++++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:30:16
@@ -51,8 +51,8 @@ LL |     let _: S = S;
              found fn item `fn(usize, usize) -> S {S}`
 help: use parentheses to instantiate this tuple struct
    |
-LL |     let _: S = S(_, _);
-   |                 ++++++
+LL |     let _: S = S(/* usize */, /* usize */);
+   |                 ++++++++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:31:20
@@ -103,10 +103,10 @@ LL |     let _: usize = T::baz;
    |
    = note: expected type `usize`
            found fn item `fn(usize, usize) -> usize {<_ as T>::baz}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
-LL |     let _: usize = T::baz(_, _);
-   |                          ++++++
+LL |     let _: usize = T::baz(/* usize */, /* usize */);
+   |                          ++++++++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:34:20
@@ -121,10 +121,10 @@ LL |     let _: usize = T::bat;
    |
    = note: expected type `usize`
            found fn item `fn(usize) -> usize {<_ as T>::bat}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
-LL |     let _: usize = T::bat(_);
-   |                          +++
+LL |     let _: usize = T::bat(/* usize */);
+   |                          +++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:35:16
@@ -141,8 +141,8 @@ LL |     let _: E = E::A;
            found fn item `fn(usize) -> E {E::A}`
 help: use parentheses to instantiate this tuple variant
    |
-LL |     let _: E = E::A(_);
-   |                    +++
+LL |     let _: E = E::A(/* usize */);
+   |                    +++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:37:20
@@ -157,10 +157,10 @@ LL |     let _: usize = X::baz;
    |
    = note: expected type `usize`
            found fn item `fn(usize, usize) -> usize {<X as T>::baz}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
-LL |     let _: usize = X::baz(_, _);
-   |                          ++++++
+LL |     let _: usize = X::baz(/* usize */, /* usize */);
+   |                          ++++++++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:38:20
@@ -175,10 +175,10 @@ LL |     let _: usize = X::bat;
    |
    = note: expected type `usize`
            found fn item `fn(usize) -> usize {<X as T>::bat}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
-LL |     let _: usize = X::bat(_);
-   |                          +++
+LL |     let _: usize = X::bat(/* usize */);
+   |                          +++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:39:20
@@ -193,10 +193,10 @@ LL |     let _: usize = X::bax;
    |
    = note: expected type `usize`
            found fn item `fn(usize) -> usize {<X as T>::bax}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
-LL |     let _: usize = X::bax(_);
-   |                          +++
+LL |     let _: usize = X::bax(/* usize */);
+   |                          +++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:40:20
@@ -211,10 +211,10 @@ LL |     let _: usize = X::bach;
    |
    = note: expected type `usize`
            found fn item `fn(usize) -> usize {<X as T>::bach}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
-LL |     let _: usize = X::bach(_);
-   |                           +++
+LL |     let _: usize = X::bach(/* usize */);
+   |                           +++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:41:20
@@ -229,10 +229,10 @@ LL |     let _: usize = X::ban;
    |
    = note: expected type `usize`
            found fn item `for<'r> fn(&'r X) -> usize {<X as T>::ban}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
-LL |     let _: usize = X::ban(_);
-   |                          +++
+LL |     let _: usize = X::ban(/* &X */);
+   |                          ++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:42:20
@@ -247,10 +247,10 @@ LL |     let _: usize = X::bal;
    |
    = note: expected type `usize`
            found fn item `for<'r> fn(&'r X) -> usize {<X as T>::bal}`
-help: use parentheses to call this function
+help: use parentheses to call this associated function
    |
-LL |     let _: usize = X::bal(_);
-   |                          +++
+LL |     let _: usize = X::bal(/* &X */);
+   |                          ++++++++++
 
 error[E0615]: attempted to take value of method `ban` on type `X`
   --> $DIR/fn-or-tuple-struct-without-args.rs:43:22
diff --git a/src/test/ui/suggestions/issue-89064.rs b/src/test/ui/suggestions/issue-89064.rs
new file mode 100644 (file)
index 0000000..fa5fc89
--- /dev/null
@@ -0,0 +1,35 @@
+use std::convert::TryInto;
+
+trait A<T> {
+    fn foo() {}
+}
+
+trait B<T, U> {
+    fn bar() {}
+}
+
+struct S;
+
+impl<T> A<T> for S {}
+impl<T, U> B<T, U> for S {}
+
+fn main() {
+    let _ = A::foo::<S>();
+    //~^ ERROR
+    //~| HELP remove these generics
+    //~| HELP consider moving this generic argument
+
+    let _ = B::bar::<S, S>();
+    //~^ ERROR
+    //~| HELP remove these generics
+    //~| HELP consider moving these generic arguments
+
+    let _ = A::<S>::foo::<S>();
+    //~^ ERROR
+    //~| HELP remove these generics
+
+    let _ = 42.into::<Option<_>>();
+    //~^ ERROR
+    //~| HELP remove these generics
+    //~| HELP consider moving this generic argument
+}
diff --git a/src/test/ui/suggestions/issue-89064.stderr b/src/test/ui/suggestions/issue-89064.stderr
new file mode 100644 (file)
index 0000000..8b2a388
--- /dev/null
@@ -0,0 +1,82 @@
+error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/issue-89064.rs:17:16
+   |
+LL |     let _ = A::foo::<S>();
+   |                ^^^ expected 0 generic arguments
+   |
+note: associated function defined here, with 0 generic parameters
+  --> $DIR/issue-89064.rs:4:8
+   |
+LL |     fn foo() {}
+   |        ^^^
+help: consider moving this generic argument to the `A` trait, which takes up to 1 argument
+   |
+LL -     let _ = A::foo::<S>();
+LL +     let _ = A::<S>::foo();
+   |
+help: remove these generics
+   |
+LL -     let _ = A::foo::<S>();
+LL +     let _ = A::foo();
+   |
+
+error[E0107]: this associated function takes 0 generic arguments but 2 generic arguments were supplied
+  --> $DIR/issue-89064.rs:22:16
+   |
+LL |     let _ = B::bar::<S, S>();
+   |                ^^^ expected 0 generic arguments
+   |
+note: associated function defined here, with 0 generic parameters
+  --> $DIR/issue-89064.rs:8:8
+   |
+LL |     fn bar() {}
+   |        ^^^
+help: consider moving these generic arguments to the `B` trait, which takes up to 2 arguments
+   |
+LL -     let _ = B::bar::<S, S>();
+LL +     let _ = B::<S, S>::bar();
+   |
+help: remove these generics
+   |
+LL -     let _ = B::bar::<S, S>();
+LL +     let _ = B::bar();
+   |
+
+error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/issue-89064.rs:27:21
+   |
+LL |     let _ = A::<S>::foo::<S>();
+   |                     ^^^----- help: remove these generics
+   |                     |
+   |                     expected 0 generic arguments
+   |
+note: associated function defined here, with 0 generic parameters
+  --> $DIR/issue-89064.rs:4:8
+   |
+LL |     fn foo() {}
+   |        ^^^
+
+error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/issue-89064.rs:31:16
+   |
+LL |     let _ = 42.into::<Option<_>>();
+   |                ^^^^ expected 0 generic arguments
+   |
+note: associated function defined here, with 0 generic parameters
+  --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
+   |
+LL |     fn into(self) -> T;
+   |        ^^^^
+help: consider moving this generic argument to the `Into` trait, which takes up to 1 argument
+   |
+LL |     let _ = Into::<Option<_>>::into(42);
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: remove these generics
+   |
+LL -     let _ = 42.into::<Option<_>>();
+LL +     let _ = 42.into();
+   |
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/suggestions/return-closures.rs b/src/test/ui/suggestions/return-closures.rs
new file mode 100644 (file)
index 0000000..86c7c15
--- /dev/null
@@ -0,0 +1,13 @@
+fn foo() {
+    //~^ HELP try adding a return type
+    |x: &i32| 1i32
+    //~^ ERROR mismatched types
+}
+
+fn bar(i: impl Sized) {
+    //~^ HELP a return type might be missing here
+    || i
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/return-closures.stderr b/src/test/ui/suggestions/return-closures.stderr
new file mode 100644 (file)
index 0000000..e273793
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0308]: mismatched types
+  --> $DIR/return-closures.rs:3:5
+   |
+LL | fn foo() {
+   |          - help: try adding a return type: `-> impl for<'r> Fn(&'r i32) -> i32`
+LL |
+LL |     |x: &i32| 1i32
+   |     ^^^^^^^^^^^^^^ expected `()`, found closure
+   |
+   = note: expected unit type `()`
+                found closure `[closure@$DIR/return-closures.rs:3:5: 3:14]`
+
+error[E0308]: mismatched types
+  --> $DIR/return-closures.rs:9:5
+   |
+LL | fn bar(i: impl Sized) {
+   |                       - help: a return type might be missing here: `-> _`
+LL |
+LL |     || i
+   |     ^^^^ expected `()`, found closure
+   |
+   = note: expected unit type `()`
+                found closure `[closure@$DIR/return-closures.rs:9:5: 9:7]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 7cf536f7966e0c342df53f2671cf10ffd0103523..14fef1b524892d78877981ad584138923f6c1ae6 100644 (file)
@@ -1,5 +1,5 @@
 // Ensure that the compiler include the blanklet implementation suggestion
-// when inside a `impl` statment are used two local traits.
+// when inside a `impl` statement are used two local traits.
 //
 // edition:2021
 use std::fmt;
diff --git a/src/test/ui/suggestions/too-many-field-suggestions.rs b/src/test/ui/suggestions/too-many-field-suggestions.rs
new file mode 100644 (file)
index 0000000..905f950
--- /dev/null
@@ -0,0 +1,29 @@
+struct Thing {
+    a0: Foo,
+    a1: Foo,
+    a2: Foo,
+    a3: Foo,
+    a4: Foo,
+    a5: Foo,
+    a6: Foo,
+    a7: Foo,
+    a8: Foo,
+    a9: Foo,
+}
+
+struct Foo {
+    field: Field,
+}
+
+struct Field;
+
+impl Foo {
+    fn bar(&self) {}
+}
+
+fn bar(t: Thing) {
+    t.bar(); //~ ERROR no method named `bar` found for struct `Thing`
+    t.field; //~ ERROR no field `field` on type `Thing`
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/too-many-field-suggestions.stderr b/src/test/ui/suggestions/too-many-field-suggestions.stderr
new file mode 100644 (file)
index 0000000..63ad6fd
--- /dev/null
@@ -0,0 +1,44 @@
+error[E0599]: no method named `bar` found for struct `Thing` in the current scope
+  --> $DIR/too-many-field-suggestions.rs:25:7
+   |
+LL | struct Thing {
+   | ------------ method `bar` not found for this struct
+...
+LL |     t.bar();
+   |       ^^^ method not found in `Thing`
+   |
+help: some of the expressions' fields have a method of the same name
+   |
+LL |     t.a0.bar();
+   |       +++
+LL |     t.a1.bar();
+   |       +++
+LL |     t.a2.bar();
+   |       +++
+LL |     t.a3.bar();
+   |       +++
+     and 6 other candidates
+
+error[E0609]: no field `field` on type `Thing`
+  --> $DIR/too-many-field-suggestions.rs:26:7
+   |
+LL |     t.field;
+   |       ^^^^^ unknown field
+   |
+   = note: available fields are: `a0`, `a1`, `a2`, `a3`, `a4` ... and 5 others
+help: some of the expressions' fields have a field of the same name
+   |
+LL |     t.a0.field;
+   |       +++
+LL |     t.a1.field;
+   |       +++
+LL |     t.a2.field;
+   |       +++
+LL |     t.a3.field;
+   |       +++
+     and 6 other candidates
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0599, E0609.
+For more information about an error, try `rustc --explain E0599`.
index 1314f9cb0932d6b98ef0842b0f950dc9bc324350..17ddaa312f7c440b1965df00f96e986e4eba9b6d 100644 (file)
@@ -1,5 +1,5 @@
 // This tests issue #79683: note in the error message that the trait is
-// explicitely unimplemented instead of suggesting to implement it.
+// explicitly unimplemented instead of suggesting to implement it.
 
 #![feature(negative_impls)]
 
diff --git a/src/test/ui/type/issue-100584.rs b/src/test/ui/type/issue-100584.rs
new file mode 100644 (file)
index 0000000..1028465
--- /dev/null
@@ -0,0 +1,15 @@
+#![deny(unused)]
+fn foo(xyza: &str) {
+//~^ ERROR unused variable: `xyza`
+    let _ = "{xyza}";
+}
+
+fn foo3(xyza: &str) {
+//~^ ERROR unused variable: `xyza`
+    let _ = "aaa{xyza}bbb";
+}
+
+fn main() {
+  foo("x");
+  foo3("xx");
+}
diff --git a/src/test/ui/type/issue-100584.stderr b/src/test/ui/type/issue-100584.stderr
new file mode 100644 (file)
index 0000000..e1db14d
--- /dev/null
@@ -0,0 +1,44 @@
+error: unused variable: `xyza`
+  --> $DIR/issue-100584.rs:2:8
+   |
+LL | fn foo(xyza: &str) {
+   |        ^^^^ unused variable
+LL |
+LL |     let _ = "{xyza}";
+   |             -------- you might have meant to use string interpolation in this string literal
+   |
+note: the lint level is defined here
+  --> $DIR/issue-100584.rs:1:9
+   |
+LL | #![deny(unused)]
+   |         ^^^^^^
+   = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
+help: string interpolation only works in `format!` invocations
+   |
+LL |     let _ = format!("{xyza}");
+   |             ++++++++        +
+help: if this is intentional, prefix it with an underscore
+   |
+LL | fn foo(_xyza: &str) {
+   |        ~~~~~
+
+error: unused variable: `xyza`
+  --> $DIR/issue-100584.rs:7:9
+   |
+LL | fn foo3(xyza: &str) {
+   |         ^^^^ unused variable
+LL |
+LL |     let _ = "aaa{xyza}bbb";
+   |             -------------- you might have meant to use string interpolation in this string literal
+   |
+help: string interpolation only works in `format!` invocations
+   |
+LL |     let _ = format!("aaa{xyza}bbb");
+   |             ++++++++              +
+help: if this is intentional, prefix it with an underscore
+   |
+LL | fn foo3(_xyza: &str) {
+   |         ~~~~~
+
+error: aborting due to 2 previous errors
+
index 65b79650d4d72495e6b7312fba7e03edb3d3000f..e49731725d51271c2f0bf24700985acc207fca69 100644 (file)
@@ -52,7 +52,7 @@ fn foo<'a>(y: &'a i32) {
 // Do this instead:
 type T4<U> = <U as Bound>::Assoc;
 
-// Make sure the help about associatd types is not shown incorrectly
+// Make sure the help about associated types is not shown incorrectly
 type T5<U: Bound> = <U as Bound>::Assoc;  //~ WARN not enforced in type aliases
 type T6<U: Bound> = ::std::vec::Vec<U>;  //~ WARN not enforced in type aliases
 
index 56a9b5317f76e49f2e78c280b5fceb723226a0a0..cf77c057d46d4b5babce2b4b9e23d96f786982f6 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: a value of type `i32` cannot be built from an iterator over elements of type `i32`
-  --> $DIR/type-check-defaults.rs:6:19
+  --> $DIR/type-check-defaults.rs:6:23
    |
 LL | struct WellFormed<Z = Foo<i32, i32>>(Z);
-   |                   ^^^^^^^^^^^^^^^^^ value of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
+   |                       ^^^^^^^^^^^^^ value of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
    |
    = help: the trait `FromIterator<i32>` is not implemented for `i32`
 note: required by a bound in `Foo`
@@ -12,10 +12,10 @@ LL | struct Foo<T, U: FromIterator<T>>(T, U);
    |                  ^^^^^^^^^^^^^^^ required by this bound in `Foo`
 
 error[E0277]: a value of type `i32` cannot be built from an iterator over elements of type `i32`
-  --> $DIR/type-check-defaults.rs:8:27
+  --> $DIR/type-check-defaults.rs:8:38
    |
 LL | struct WellFormedNoBounds<Z:?Sized = Foo<i32, i32>>(Z);
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^ value of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
+   |                                      ^^^^^^^^^^^^^ value of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
    |
    = help: the trait `FromIterator<i32>` is not implemented for `i32`
 note: required by a bound in `Foo`
index 1508b84c1b6e74fe36bd80e8847103bdc4e3325a..84ac48b1e77b4ae610b45c204a22901536c97ddc 100644 (file)
@@ -4,8 +4,8 @@ error: reached the type-length limit while instantiating `std::mem::drop::<Optio
 LL | pub fn drop<T>(_x: T) {}
    | ^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
    = help: consider adding a `#![type_length_limit="8"]` attribute to your crate
+   = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
 
 error: reached the type-length limit while instantiating `<[closure@std::rt::lang_start<()...e<()>>::call_once - shim(vtable)`
   --> $SRC_DIR/core/src/ops/function.rs:LL:COL
@@ -13,8 +13,8 @@ error: reached the type-length limit while instantiating `<[closure@std::rt::lan
 LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
    = help: consider adding a `#![type_length_limit="8"]` attribute to your crate
+   = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt'
 
 error: aborting due to 2 previous errors
 
index c5d2ec0840996ac6afc42868ae0082c82226f913..a837a7d2d62d178833e6607ad3e12b2ec53fecf5 100644 (file)
@@ -2,17 +2,13 @@ error[E0599]: no method named `x` found for fn item `fn() -> Ret {Obj::func}` in
   --> $DIR/issue-29124.rs:15:15
    |
 LL |     Obj::func.x();
-   |     --------- ^ method not found in `fn() -> Ret {Obj::func}`
-   |     |
-   |     this is a function, perhaps you wish to call it
+   |               ^ method not found in `fn() -> Ret {Obj::func}`
 
 error[E0599]: no method named `x` found for fn item `fn() -> Ret {func}` in the current scope
   --> $DIR/issue-29124.rs:17:10
    |
 LL |     func.x();
-   |     ---- ^ method not found in `fn() -> Ret {func}`
-   |     |
-   |     this is a function, perhaps you wish to call it
+   |          ^ method not found in `fn() -> Ret {func}`
 
 error: aborting due to 2 previous errors
 
index 1875d8280cb627b21e8b25be5406249f85b3cbcb..be68ad32ae55bb35e1b097361f86492acee30df5 100644 (file)
@@ -4,7 +4,7 @@ struct Bar<T> {
 
 struct Foo();
 impl Foo {
-    fn foo() { }
+    fn foo(&self) { }
 }
 
 fn main() {
index 6ed70b301e4a45543e547148177fd1222fa9bfad..a18c54a29b52c0e875b580fa15e0b069b5acc6bb 100644 (file)
@@ -2,11 +2,9 @@ error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo}` in the
   --> $DIR/empty-tuple-method.rs:12:15
    |
 LL |     thing.bar.foo();
-   |     --------- ^^^ method not found in `fn() -> Foo {Foo}`
-   |     |
-   |     this is the constructor of a struct
+   |               ^^^ method not found in `fn() -> Foo {Foo}`
    |
-help: call the constructor
+help: use parentheses to instantiate this tuple struct
    |
 LL |     (thing.bar)().foo();
    |     +         +++
index 3b926b90f10bbe23c293dea4a226c8d640576f78..d87f99c3c5a193dc3ba7f3382744d43bdf8dced4 100644 (file)
@@ -6,7 +6,7 @@ enum Foo{
     Tup()
 }
 impl Foo {
-    fn foo() { }
+    fn foo(&self) { }
 }
 
 fn main() {
index a3a818696ab5ba18afc336f88130dd2f4ade7ed3..90641410d8e967430f568da85b4507012eb2cd48 100644 (file)
@@ -2,11 +2,9 @@ error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo::Tup}` i
   --> $DIR/enum-variant.rs:14:15
    |
 LL |     thing.bar.foo();
-   |     --------- ^^^ method not found in `fn() -> Foo {Foo::Tup}`
-   |     |
-   |     this is the constructor of an enum variant
+   |               ^^^ method not found in `fn() -> Foo {Foo::Tup}`
    |
-help: call the constructor
+help: use parentheses to instantiate this tuple variant
    |
 LL |     (thing.bar)().foo();
    |     +         +++
index 4d22ada0247e98f71e76c9d0813926bc12ada199..c1ca26ee9af1dc84ca41784e4834b60c2b2f737f 100644 (file)
@@ -2,14 +2,12 @@ error[E0609]: no field `0` on type `fn(char, u16) -> Foo {Foo}`
   --> $DIR/tuple-field.rs:12:15
    |
 LL |     thing.bar.0;
-   |     --------- ^
-   |     |
-   |     this is the constructor of a struct
+   |               ^
    |
-help: call the constructor
+help: use parentheses to instantiate this tuple struct
    |
-LL |     (thing.bar)(_, _).0;
-   |     +         +++++++
+LL |     (thing.bar)(/* char */, /* u16 */).0;
+   |     +         ++++++++++++++++++++++++
 
 error: aborting due to previous error
 
index 1e392e17984b09167daaf428c24cf68837c02739..e27c41858d322e181021cf02313543d6a25264e2 100644 (file)
@@ -2,14 +2,7 @@ error[E0599]: no method named `foo` found for fn item `fn(u8, i32) -> Foo {Foo}`
   --> $DIR/tuple-method.rs:12:15
    |
 LL |     thing.bar.foo();
-   |     --------- ^^^ method not found in `fn(u8, i32) -> Foo {Foo}`
-   |     |
-   |     this is the constructor of a struct
-   |
-help: call the constructor
-   |
-LL |     (thing.bar)(_, _).foo();
-   |     +         +++++++
+   |               ^^^ method not found in `fn(u8, i32) -> Foo {Foo}`
 
 error: aborting due to previous error
 
index 32f53849848c75abd5e599818799c2fa87215c99..0d4d87ef47e2b99db2886049828f3ee0ac59997b 100644 (file)
@@ -2,27 +2,13 @@ error[E0599]: no method named `nonexistent_method` found for fn item `fn(_) -> O
   --> $DIR/issue-96738.rs:2:10
    |
 LL |     Some.nonexistent_method();
-   |     ---- ^^^^^^^^^^^^^^^^^^ method not found in `fn(_) -> Option<_> {Option::<_>::Some}`
-   |     |
-   |     this is the constructor of an enum variant
-   |
-help: call the constructor
-   |
-LL |     (Some)(_).nonexistent_method();
-   |     +    ++++
+   |          ^^^^^^^^^^^^^^^^^^ method not found in `fn(_) -> Option<_> {Option::<_>::Some}`
 
 error[E0609]: no field `nonexistent_field` on type `fn(_) -> Option<_> {Option::<_>::Some}`
   --> $DIR/issue-96738.rs:3:10
    |
 LL |     Some.nonexistent_field;
-   |     ---- ^^^^^^^^^^^^^^^^^
-   |     |
-   |     this is the constructor of an enum variant
-   |
-help: call the constructor
-   |
-LL |     (Some)(_).nonexistent_field;
-   |     +    ++++
+   |          ^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
index 939b3c5223c484c1209ae9bac1c22415f4965493..ec86213f8629df02bc4efa51d6d4bbdb0469eacc 100644 (file)
@@ -3,6 +3,7 @@
 fn main() {
     <i32 as Add<u32>>::add(1, 2);
     //~^ ERROR cannot add `u32` to `i32`
+    //~| ERROR cannot add `u32` to `i32`
     <i32 as Add<i32>>::add(1u32, 2);
     //~^ ERROR mismatched types
     <i32 as Add<i32>>::add(1, 2u32);
index f08c81bc1e937f7bada03d02c80886a7d277c649..eaab6ff3d9a0419227d6ad01307049dbebcc021a 100644 (file)
@@ -19,7 +19,7 @@ LL |     <i32 as Add<u32>>::add(1, 2);
            and 48 others
 
 error[E0308]: mismatched types
-  --> $DIR/ufcs-qpath-self-mismatch.rs:6:28
+  --> $DIR/ufcs-qpath-self-mismatch.rs:7:28
    |
 LL |     <i32 as Add<i32>>::add(1u32, 2);
    |     ---------------------- ^^^^ expected `i32`, found `u32`
@@ -37,7 +37,7 @@ LL |     <i32 as Add<i32>>::add(1i32, 2);
    |                             ~~~
 
 error[E0308]: mismatched types
-  --> $DIR/ufcs-qpath-self-mismatch.rs:8:31
+  --> $DIR/ufcs-qpath-self-mismatch.rs:9:31
    |
 LL |     <i32 as Add<i32>>::add(1, 2u32);
    |     ----------------------    ^^^^ expected `i32`, found `u32`
@@ -54,7 +54,25 @@ help: change the type of the numeric literal from `u32` to `i32`
 LL |     <i32 as Add<i32>>::add(1, 2i32);
    |                                ~~~
 
-error: aborting due to 3 previous errors
+error[E0277]: cannot add `u32` to `i32`
+  --> $DIR/ufcs-qpath-self-mismatch.rs:4:5
+   |
+LL |     <i32 as Add<u32>>::add(1, 2);
+   |     ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u32`
+   |
+   = help: the trait `Add<u32>` is not implemented for `i32`
+   = help: the following other types implement trait `Add<Rhs>`:
+             <&'a f32 as Add<f32>>
+             <&'a f64 as Add<f64>>
+             <&'a i128 as Add<i128>>
+             <&'a i16 as Add<i16>>
+             <&'a i32 as Add<i32>>
+             <&'a i64 as Add<i64>>
+             <&'a i8 as Add<i8>>
+             <&'a isize as Add<isize>>
+           and 48 others
+
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.
index 4f89afa320d706f1cd6b255628ed311db83dab77..e5ca0edd7a91c62826aa111d4be9dada4161bb37 100644 (file)
@@ -2,9 +2,7 @@ error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-cl
   --> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10
    |
 LL |     mut_.call((0, ));
-   |     ---- ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]`
-   |     |
-   |     this is a function, perhaps you wish to call it
+   |          ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unpretty/avoid-crash.rs b/src/test/ui/unpretty/avoid-crash.rs
new file mode 100644 (file)
index 0000000..fd84b70
--- /dev/null
@@ -0,0 +1,4 @@
+// normalize-stderr-test "error `.*`" -> "$$ERROR_MESSAGE"
+// compile-flags: -o/tmp/ -Zunpretty=ast-tree
+
+fn main() {}
diff --git a/src/test/ui/unpretty/avoid-crash.stderr b/src/test/ui/unpretty/avoid-crash.stderr
new file mode 100644 (file)
index 0000000..11cd386
--- /dev/null
@@ -0,0 +1,4 @@
+error: pretty-print failed to write `/tmp/` due to $ERROR_MESSAGE
+
+error: aborting due to previous error
+
index f5491552a45d2ed89134cab0d3b53c6adbde58f7..71bbdf5dec7696600f3a02ee2544624d0c097244 100644 (file)
@@ -5,11 +5,8 @@ LL |     &X(*Y)
    |        ^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all function arguments must have a statically known size
    = help: unsized fn params are gated as an unstable feature
-help: function arguments must have a statically known size, borrowed types always have a known size
-   |
-LL |     &X(&*Y)
-   |        +
 
 error: aborting due to previous error
 
index 7f59067483b9643499b0e1e86bf6886d03926cfc..40781fbf082b648047a6431cdf4d37dae84b4dcd 100644 (file)
@@ -1,4 +1,4 @@
-// Test various uses of structs with distint variances to make sure
+// Test various uses of structs with distinct variances to make sure
 // they permit lifetimes to be approximated as expected.
 
 struct SomeStruct<T>(fn(T));
index 2113eb2addb9bc492b3b2020796213c7470f1f89..d4b2d08342a9bd0f9c0d0770aec5ac31179300c6 100644 (file)
@@ -1,4 +1,4 @@
-// Test various uses of structs with distint variances to make sure
+// Test various uses of structs with distinct variances to make sure
 // they permit lifetimes to be approximated as expected.
 
 #![allow(dead_code)]
index d40dbceb5f8c41990f5a65052797ba0f1fdedba3..72f50f3459d1a47d8002a84043e6117f60b0d5ff 100644 (file)
@@ -1,4 +1,4 @@
-// Test various uses of structs with distint variances to make sure
+// Test various uses of structs with distinct variances to make sure
 // they permit lifetimes to be approximated as expected.
 
 struct SomeStruct<T>(*mut T);
index a59ba3400a4d13fb0ec06f9fa58d89cad86f7d55..9bd3cc7711b84777124ca566bf7117162934c422 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `Self: Eq` is not satisfied
-  --> $DIR/wf-trait-fn-ret.rs:10:22
+  --> $DIR/wf-trait-fn-ret.rs:10:23
    |
 LL |     fn bar(&self) -> &Bar<Self>;
-   |                      ^^^^^^^^^^ the trait `Eq` is not implemented for `Self`
+   |                       ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
    |
 note: required by a bound in `Bar`
   --> $DIR/wf-trait-fn-ret.rs:7:14
index 6da726708a4406f31f996d813790818dce837161..4ed54cecce3ce9ab6ff058781f4c8a500ee6b8b5 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 6da726708a4406f31f996d813790818dce837161
+Subproject commit 4ed54cecce3ce9ab6ff058781f4c8a500ee6b8b5
index 0e27cc927acea4c010f810cd350f047eebece429..fac2c99714d9bf808d6a13f6bae1b6a82af59356 100644 (file)
@@ -24,6 +24,7 @@ env:
   RUST_BACKTRACE: 1
   CARGO_TARGET_DIR: '${{ github.workspace }}/target'
   NO_FMT_TEST: 1
+  CARGO_INCREMENTAL: 0
 
 jobs:
   base:
index 97453303cd6aae58c0959ede46d21704e254464e..30607af490124589f44ce0cf831ca57ab8edad98 100644 (file)
@@ -10,6 +10,7 @@ env:
   RUST_BACKTRACE: 1
   CARGO_TARGET_DIR: '${{ github.workspace }}/target'
   NO_FMT_TEST: 1
+  CARGO_INCREMENTAL: 0
 
 defaults:
   run:
index 380cd451987bfc982d00448668e1699fb999ffc9..c488c142e46fc2847fe41d7c3c3582508a705eac 100644 (file)
@@ -6,11 +6,157 @@ document.
 
 ## Unreleased / In Rust Nightly
 
-[7c21f91b...master](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...master)
+[d7b5cbf0...master](https://github.com/rust-lang/rust-clippy/compare/d7b5cbf0...master)
+
+## Rust 1.63
+
+Current stable, released 2022-08-11
+
+[7c21f91b...d7b5cbf0](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...d7b5cbf0)
+
+### New Lints
+
+* [`borrow_deref_ref`]
+  [#7930](https://github.com/rust-lang/rust-clippy/pull/7930)
+* [`doc_link_with_quotes`]
+  [#8385](https://github.com/rust-lang/rust-clippy/pull/8385)
+* [`no_effect_replace`]
+  [#8754](https://github.com/rust-lang/rust-clippy/pull/8754)
+* [`rc_clone_in_vec_init`]
+  [#8769](https://github.com/rust-lang/rust-clippy/pull/8769)
+* [`derive_partial_eq_without_eq`]
+  [#8796](https://github.com/rust-lang/rust-clippy/pull/8796)
+* [`mismatching_type_param_order`]
+  [#8831](https://github.com/rust-lang/rust-clippy/pull/8831)
+* [`duplicate_mod`] [#8832](https://github.com/rust-lang/rust-clippy/pull/8832)
+* [`unused_rounding`]
+  [#8866](https://github.com/rust-lang/rust-clippy/pull/8866)
+* [`get_first`] [#8882](https://github.com/rust-lang/rust-clippy/pull/8882)
+* [`swap_ptr_to_ref`]
+  [#8916](https://github.com/rust-lang/rust-clippy/pull/8916)
+* [`almost_complete_letter_range`]
+  [#8918](https://github.com/rust-lang/rust-clippy/pull/8918)
+* [`needless_parens_on_range_literals`]
+  [#8933](https://github.com/rust-lang/rust-clippy/pull/8933)
+* [`as_underscore`] [#8934](https://github.com/rust-lang/rust-clippy/pull/8934)
+
+### Moves and Deprecations
+
+* Rename `eval_order_dependence` to [`mixed_read_write_in_expression`], move to
+  `nursery` [#8621](https://github.com/rust-lang/rust-clippy/pull/8621)
+
+### Enhancements
+
+* [`undocumented_unsafe_blocks`]: Now also lints on unsafe trait implementations
+  [#8761](https://github.com/rust-lang/rust-clippy/pull/8761)
+* [`empty_line_after_outer_attr`]: Now also lints on argumentless macros
+  [#8790](https://github.com/rust-lang/rust-clippy/pull/8790)
+* [`expect_used`]: Now can be disabled in tests with the `allow-expect-in-tests`
+  option [#8802](https://github.com/rust-lang/rust-clippy/pull/8802)
+* [`unwrap_used`]: Now can be disabled in tests with the `allow-unwrap-in-tests`
+  option [#8802](https://github.com/rust-lang/rust-clippy/pull/8802)
+* [`disallowed_methods`]: Now also lints indirect usages
+  [#8852](https://github.com/rust-lang/rust-clippy/pull/8852)
+* [`get_last_with_len`]: Now also lints `VecDeque` and any deref to slice
+  [#8862](https://github.com/rust-lang/rust-clippy/pull/8862)
+* [`manual_range_contains`]: Now also lints on chains of `&&` and `||`
+  [#8884](https://github.com/rust-lang/rust-clippy/pull/8884)
+* [`rc_clone_in_vec_init`]: Now also lints on `Weak`
+  [#8885](https://github.com/rust-lang/rust-clippy/pull/8885)
+* [`dbg_macro`]: Introduce `allow-dbg-in-tests` config option
+  [#8897](https://github.com/rust-lang/rust-clippy/pull/8897)
+* [`use_self`]: Now also lints on `TupleStruct` and `Struct` patterns
+  [#8899](https://github.com/rust-lang/rust-clippy/pull/8899)
+* [`manual_find_map`] and [`manual_filter_map`]: Now also lints on more complex
+  method chains inside `map`
+  [#8930](https://github.com/rust-lang/rust-clippy/pull/8930)
+* [`needless_return`]: Now also lints on macro expressions in return statements
+  [#8932](https://github.com/rust-lang/rust-clippy/pull/8932)
+* [`doc_markdown`]: Users can now indicate, that the `doc-valid-idents` config
+  should extend the default and not replace it
+  [#8944](https://github.com/rust-lang/rust-clippy/pull/8944)
+* [`disallowed_names`]: Users can now indicate, that the `disallowed-names`
+  config should extend the default and not replace it
+  [#8944](https://github.com/rust-lang/rust-clippy/pull/8944)
+* [`never_loop`]: Now checks for `continue` in struct expression
+  [#9002](https://github.com/rust-lang/rust-clippy/pull/9002)
+
+### False Positive Fixes
+
+* [`useless_transmute`]: No longer lints on types with erased regions
+  [#8564](https://github.com/rust-lang/rust-clippy/pull/8564)
+* [`vec_init_then_push`]: No longer lints when further extended
+  [#8699](https://github.com/rust-lang/rust-clippy/pull/8699)
+* [`cmp_owned`]: No longer lints on `From::from` for `Copy` types
+  [#8807](https://github.com/rust-lang/rust-clippy/pull/8807)
+* [`redundant_allocation`]: No longer lints on fat pointers that would become
+  thin pointers [#8813](https://github.com/rust-lang/rust-clippy/pull/8813)
+* [`derive_partial_eq_without_eq`]:
+    * Handle differing predicates applied by `#[derive(PartialEq)]` and
+      `#[derive(Eq)]`
+      [#8869](https://github.com/rust-lang/rust-clippy/pull/8869)
+    * No longer lints on non-public types and better handles generics
+      [#8950](https://github.com/rust-lang/rust-clippy/pull/8950)
+* [`empty_line_after_outer_attr`]: No longer lints empty lines in inner
+  string values [#8892](https://github.com/rust-lang/rust-clippy/pull/8892)
+* [`branches_sharing_code`]: No longer lints when using different binding names
+  [#8901](https://github.com/rust-lang/rust-clippy/pull/8901)
+* [`significant_drop_in_scrutinee`]: No longer lints on Try `?` and `await`
+  desugared expressions [#8902](https://github.com/rust-lang/rust-clippy/pull/8902)
+* [`checked_conversions`]: No longer lints in `const` contexts
+  [#8907](https://github.com/rust-lang/rust-clippy/pull/8907)
+* [`iter_overeager_cloned`]: No longer lints on `.cloned().flatten()` when
+  `T::Item` doesn't implement `IntoIterator`
+  [#8960](https://github.com/rust-lang/rust-clippy/pull/8960)
+
+### Suggestion Fixes/Improvements
+
+* [`vec_init_then_push`]: Suggest to remove `mut` binding when possible
+  [#8699](https://github.com/rust-lang/rust-clippy/pull/8699)
+* [`manual_range_contains`]: Fix suggestion for integers with different signs
+  [#8763](https://github.com/rust-lang/rust-clippy/pull/8763)
+* [`identity_op`]: Add parenthesis to suggestions where required
+  [#8786](https://github.com/rust-lang/rust-clippy/pull/8786)
+* [`cast_lossless`]: No longer gives wrong suggestion on `usize`/`isize`->`f64`
+  [#8778](https://github.com/rust-lang/rust-clippy/pull/8778)
+* [`rc_clone_in_vec_init`]: Add suggestion
+  [#8814](https://github.com/rust-lang/rust-clippy/pull/8814)
+* The "unknown field" error messages for config files now wraps the field names
+  [#8823](https://github.com/rust-lang/rust-clippy/pull/8823)
+* [`cast_abs_to_unsigned`]: Do not remove cast if it's required
+  [#8876](https://github.com/rust-lang/rust-clippy/pull/8876)
+* [`significant_drop_in_scrutinee`]: Improve lint message for types that are not
+  references and not trivially clone-able
+  [#8902](https://github.com/rust-lang/rust-clippy/pull/8902)
+* [`for_loops_over_fallibles`]: Now suggests the correct variant of `iter()`,
+  `iter_mut()` or `into_iter()`
+  [#8941](https://github.com/rust-lang/rust-clippy/pull/8941)
+
+### ICE Fixes
+
+* Fix ICE in [`let_unit_value`] when calling a `static`/`const` callable type
+  [#8835](https://github.com/rust-lang/rust-clippy/pull/8835)
+* Fix ICEs on callable `static`/`const`s
+  [#8896](https://github.com/rust-lang/rust-clippy/pull/8896)
+* [`needless_late_init`]
+  [#8912](https://github.com/rust-lang/rust-clippy/pull/8912)
+* Fix ICE in shadow lints
+  [#8913](https://github.com/rust-lang/rust-clippy/pull/8913)
+
+### Documentation Improvements
+
+* Clippy has a [Book](https://doc.rust-lang.org/nightly/clippy/) now!
+  [#7359](https://github.com/rust-lang/rust-clippy/pull/7359)
+* Add a *copy lint name*-button to Clippy's lint list
+  [#8839](https://github.com/rust-lang/rust-clippy/pull/8839)
+* Display past names of renamed lints on Clippy's lint list
+  [#8843](https://github.com/rust-lang/rust-clippy/pull/8843)
+* Add the ability to show the lint output in the lint list
+  [#8947](https://github.com/rust-lang/rust-clippy/pull/8947)
 
 ## Rust 1.62
 
-Current stable, released 2022-06-30
+Released 2022-06-30
 
 [d0cf3481...7c21f91b](https://github.com/rust-lang/rust-clippy/compare/d0cf3481...7c21f91b)
 
@@ -3481,6 +3627,7 @@ Released 2018-09-13
 [`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut
 [`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
 [`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes
+[`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts
 [`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
 [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
@@ -3496,6 +3643,7 @@ Released 2018-09-13
 [`collapsible_else_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if
 [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
 [`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match
+[`collapsible_str_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace
 [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
 [`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
@@ -3656,6 +3804,8 @@ Released 2018-09-13
 [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator
 [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
 [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
+[`iter_on_empty_collections`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_empty_collections
+[`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items
 [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
 [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
 [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
@@ -3697,6 +3847,7 @@ Released 2018-09-13
 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
 [`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once
 [`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
+[`manual_string_new`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_string_new
 [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
 [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
@@ -3747,6 +3898,7 @@ Released 2018-09-13
 [`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions
 [`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic
 [`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one
+[`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments
 [`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
 [`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
 [`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate
@@ -3827,6 +3979,7 @@ Released 2018-09-13
 [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
 [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
 [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
+[`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
 [`print_in_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_in_format_impl
@@ -3872,6 +4025,7 @@ Released 2018-09-13
 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
 [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
 [`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used
+[`result_large_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err
 [`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
 [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
 [`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
@@ -3930,6 +4084,7 @@ Released 2018-09-13
 [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
 [`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings
 [`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
+[`suspicious_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_to_owned
 [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
 [`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref
 [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
@@ -4002,6 +4157,7 @@ Released 2018-09-13
 [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
 [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 [`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
+[`unused_peekable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_peekable
 [`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding
 [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
 [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
index f5c51b9474fcd878cf631441cc03a194d239301b..92b2771f3fe73aeccc27b51c1edd243108f0e35d 100644 (file)
@@ -37,7 +37,7 @@ fn update_reference_file(test_output_entry: &DirEntry, ignore_timestamp: bool) {
         return;
     }
 
-    let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file");
+    let test_output_file = fs::read(test_output_path).expect("Unable to read test output file");
     let reference_file = fs::read(&reference_file_path).unwrap_or_default();
 
     if test_output_file != reference_file {
index 3b27f061eb0b4f3fc57964044297bc26e8c3a413..357cf6fc43aadada9baabbce3ac08cd70c5d0f93 100644 (file)
@@ -46,7 +46,7 @@ fn try_run(context: &FmtContext) -> Result<bool, CliError> {
         // dependency
         if fs::read_to_string(project_root.join("Cargo.toml"))
             .expect("Failed to read clippy Cargo.toml")
-            .contains(&"[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
+            .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
         {
             return Err(CliError::IntellijSetupActive);
         }
@@ -193,10 +193,10 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
     let args = &["--version"];
 
     if context.verbose {
-        println!("{}", format_command(&program, &dir, args));
+        println!("{}", format_command(program, &dir, args));
     }
 
-    let output = Command::new(&program).current_dir(&dir).args(args.iter()).output()?;
+    let output = Command::new(program).current_dir(&dir).args(args.iter()).output()?;
 
     if output.status.success() {
         Ok(())
@@ -207,7 +207,7 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
         Err(CliError::RustfmtNotInstalled)
     } else {
         Err(CliError::CommandFailed(
-            format_command(&program, &dir, args),
+            format_command(program, &dir, args),
             std::str::from_utf8(&output.stderr).unwrap_or("").to_string(),
         ))
     }
index 8a6bd1cbdf564b5bff3095f012adff97ce736884..82574a8e64b0ae028eb64769914837fd8c148553 100644 (file)
@@ -1,3 +1,4 @@
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(once_cell)]
 #![feature(rustc_private)]
index 10a8f31f4573f790d63a4c786037abff9ce40004..be05e67d724dfc120acfec0d1385dda0cd3df741 100644 (file)
@@ -155,7 +155,7 @@ fn to_camel_case(name: &str) -> String {
     name.split('_')
         .map(|s| {
             if s.is_empty() {
-                String::from("")
+                String::new()
             } else {
                 [&s[0..1].to_uppercase(), &s[1..]].concat()
             }
index 05e79a241884f43bb9175afd3b01b483e6596959..c503142e5e4552b1cdc28877dca9ab3734ba2083 100644 (file)
@@ -418,7 +418,7 @@ fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) {
             .expect("failed to find `impl_lint_pass` terminator");
 
         impl_lint_pass_end += impl_lint_pass_start;
-        if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(&lint_name_upper) {
+        if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) {
             let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len());
             for c in content[lint_name_end..impl_lint_pass_end].chars() {
                 // Remove trailing whitespace
@@ -451,7 +451,7 @@ fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) {
                 }
 
                 let mut content =
-                    fs::read_to_string(&path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
+                    fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
 
                 eprintln!(
                     "warn: you will have to manually remove any code related to `{}` from `{}`",
diff --git a/src/tools/clippy/clippy_lints/src/as_underscore.rs b/src/tools/clippy/clippy_lints/src/as_underscore.rs
deleted file mode 100644 (file)
index 0bdef9d..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, TyKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// ### 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 du to the type being inferred.
-    ///
-    /// The lint is allowed by default as using `_` is less wordy than always specifying the type.
-    ///
-    /// ### Example
-    /// ```rust
-    /// fn foo(n: usize) {}
-    /// let n: u16 = 256;
-    /// foo(n as _);
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// fn foo(n: usize) {}
-    /// let n: u16 = 256;
-    /// foo(n as usize);
-    /// ```
-    #[clippy::version = "1.63.0"]
-    pub AS_UNDERSCORE,
-    restriction,
-    "detects `as _` conversion"
-}
-declare_lint_pass!(AsUnderscore => [AS_UNDERSCORE]);
-
-impl<'tcx> LateLintPass<'tcx> for AsUnderscore {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        if let ExprKind::Cast(_, ty) = expr.kind && let TyKind::Infer = ty.kind {
-
-            let ty_resolved = cx.typeck_results().expr_ty(expr);
-            if let ty::Error(_) = ty_resolved.kind() {
-                span_lint_and_help(
-                    cx,
-                AS_UNDERSCORE,
-                expr.span,
-                "using `as _` conversion",
-                None,
-                "consider giving the type explicitly",
-                );
-            } else {
-            span_lint_and_then(
-                cx,
-                AS_UNDERSCORE,
-                expr.span,
-                "using `as _` conversion",
-                |diag| {
-                    diag.span_suggestion(
-                        ty.span,
-                        "consider giving the type explicitly",
-                        ty_resolved,
-                        Applicability::MachineApplicable,
-                    );
-            }
-            );
-        }
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs
deleted file mode 100644 (file)
index 0993adb..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_no_std_crate;
-use clippy_utils::source::snippet_opt;
-use clippy_utils::{meets_msrv, msrvs};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, TyKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_semver::RustcVersion;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// 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:
-    /// ```rust
-    /// 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);
-    /// ```
-    #[clippy::version = "1.60.0"]
-    pub BORROW_AS_PTR,
-    pedantic,
-    "borrowing just to cast to a raw pointer"
-}
-
-impl_lint_pass!(BorrowAsPtr => [BORROW_AS_PTR]);
-
-pub struct BorrowAsPtr {
-    msrv: Option<RustcVersion>,
-}
-
-impl BorrowAsPtr {
-    #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
-        Self { msrv }
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) {
-            return;
-        }
-
-        if expr.span.from_expansion() {
-            return;
-        }
-
-        if_chain! {
-            if let ExprKind::Cast(left_expr, ty) = &expr.kind;
-            if let TyKind::Ptr(_) = ty.kind;
-            if let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = &left_expr.kind;
-
-            then {
-                let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
-                let macro_name = match mutability {
-                    Mutability::Not => "addr_of",
-                    Mutability::Mut => "addr_of_mut",
-                };
-
-                span_lint_and_sugg(
-                    cx,
-                    BORROW_AS_PTR,
-                    expr.span,
-                    "borrow as raw pointer",
-                    "try",
-                    format!(
-                        "{}::ptr::{}!({})",
-                        core_or_std,
-                        macro_name,
-                        snippet_opt(cx, e.span).unwrap()
-                    ),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-    }
-
-    extract_msrv_attr!(LateContext);
-}
index 937765b66147912aa6c9172a2b61b4369f91cbec..c4520d003928e3832053fe749045c643407ed2c1 100644 (file)
     ///
     /// ### Example
     /// ```rust
-    /// fn foo(_x: &str) {}
-    ///
     /// let s = &String::new();
     ///
     /// let a: &String = &* s;
-    /// foo(&*s);
     /// ```
     ///
     /// Use instead:
     /// ```rust
-    /// # fn foo(_x: &str) {}
     /// # let s = &String::new();
     /// let a: &String = s;
-    /// foo(&**s);
     /// ```
-    #[clippy::version = "1.59.0"]
+    #[clippy::version = "1.63.0"]
     pub BORROW_DEREF_REF,
     complexity,
     "deref on an immutable reference returns the same type as itself"
diff --git a/src/tools/clippy/clippy_lints/src/bytecount.rs b/src/tools/clippy/clippy_lints/src/bytecount.rs
deleted file mode 100644 (file)
index 326ce34..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::match_type;
-use clippy_utils::visitors::is_local_used;
-use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, UintTy};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// # let vec = vec![1_u8];
-    /// let count = vec.iter().filter(|x| **x == 0u8).count();
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// # let vec = vec![1_u8];
-    /// let count = bytecount::count(&vec, 0u8);
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub NAIVE_BYTECOUNT,
-    pedantic,
-    "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values"
-}
-
-declare_lint_pass!(ByteCount => [NAIVE_BYTECOUNT]);
-
-impl<'tcx> LateLintPass<'tcx> for ByteCount {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if_chain! {
-            if let ExprKind::MethodCall(count, [count_recv], _) = expr.kind;
-            if count.ident.name == sym::count;
-            if let ExprKind::MethodCall(filter, [filter_recv, filter_arg], _) = count_recv.kind;
-            if filter.ident.name == sym!(filter);
-            if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind;
-            let body = cx.tcx.hir().body(body);
-            if let [param] = body.params;
-            if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
-            if let ExprKind::Binary(ref op, l, r) = body.value.kind;
-            if op.node == BinOpKind::Eq;
-            if match_type(cx,
-                       cx.typeck_results().expr_ty(filter_recv).peel_refs(),
-                       &paths::SLICE_ITER);
-            let operand_is_arg = |expr| {
-                let expr = peel_ref_operators(cx, peel_blocks(expr));
-                path_to_local_id(expr, arg_id)
-            };
-            let needle = if operand_is_arg(l) {
-                r
-            } else if operand_is_arg(r) {
-                l
-            } else {
-                return;
-            };
-            if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
-            if !is_local_used(cx, needle, arg_id);
-            then {
-                let haystack = if let ExprKind::MethodCall(path, args, _) =
-                        filter_recv.kind {
-                    let p = path.ident.name;
-                    if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
-                        &args[0]
-                    } else {
-                        filter_recv
-                    }
-                } else {
-                    filter_recv
-                };
-                let mut applicability = Applicability::MaybeIncorrect;
-                span_lint_and_sugg(
-                    cx,
-                    NAIVE_BYTECOUNT,
-                    expr.span,
-                    "you appear to be counting bytes the naive way",
-                    "consider using the bytecount crate",
-                    format!("bytecount::count({}, {})",
-                            snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
-                            snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
-                    applicability,
-                );
-            }
-        };
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/bytes_count_to_len.rs b/src/tools/clippy/clippy_lints/src/bytes_count_to_len.rs
deleted file mode 100644 (file)
index d70dbf5..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{match_def_path, paths};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// "hello".bytes().count();
-    /// String::from("hello").bytes().count();
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// "hello".len();
-    /// String::from("hello").len();
-    /// ```
-    #[clippy::version = "1.62.0"]
-    pub BYTES_COUNT_TO_LEN,
-    complexity,
-    "Using `bytes().count()` when `len()` performs the same functionality"
-}
-
-declare_lint_pass!(BytesCountToLen => [BYTES_COUNT_TO_LEN]);
-
-impl<'tcx> LateLintPass<'tcx> for BytesCountToLen {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if_chain! {
-            if let hir::ExprKind::MethodCall(_, expr_args, _) = &expr.kind;
-            if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
-            if match_def_path(cx, expr_def_id, &paths::ITER_COUNT);
-
-            if let [bytes_expr] = &**expr_args;
-            if let hir::ExprKind::MethodCall(_, bytes_args, _) = &bytes_expr.kind;
-            if let Some(bytes_def_id) = cx.typeck_results().type_dependent_def_id(bytes_expr.hir_id);
-            if match_def_path(cx, bytes_def_id, &paths::STR_BYTES);
-
-            if let [str_expr] = &**bytes_args;
-            let ty = cx.typeck_results().expr_ty(str_expr).peel_refs();
-
-            if is_type_diagnostic_item(cx, ty, sym::String) || ty.kind() == &ty::Str;
-            then {
-                let mut applicability = Applicability::MachineApplicable;
-                span_lint_and_sugg(
-                    cx,
-                    BYTES_COUNT_TO_LEN,
-                    expr.span,
-                    "using long and hard to read `.bytes().count()`",
-                    "consider calling `.len()` instead",
-                    format!("{}.len()", snippet_with_applicability(cx, str_expr.span, "..", &mut applicability)),
-                    applicability
-                );
-            }
-        };
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
deleted file mode 100644 (file)
index 7eff71d..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
-use rustc_hir::{Expr, ExprKind, PathSegment};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{source_map::Spanned, symbol::sym, Span};
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// fn is_rust_file(filename: &str) -> bool {
-    ///     filename.ends_with(".rs")
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// fn is_rust_file(filename: &str) -> bool {
-    ///     let filename = std::path::Path::new(filename);
-    ///     filename.extension()
-    ///         .map(|ext| ext.eq_ignore_ascii_case("rs"))
-    ///         .unwrap_or(false)
-    /// }
-    /// ```
-    #[clippy::version = "1.51.0"]
-    pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
-    pedantic,
-    "Checks for calls to ends_with with case-sensitive file extensions"
-}
-
-declare_lint_pass!(CaseSensitiveFileExtensionComparisons => [CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS]);
-
-fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Span> {
-    if_chain! {
-        if let ExprKind::MethodCall(PathSegment { ident, .. }, [obj, extension, ..], span) = expr.kind;
-        if ident.as_str() == "ends_with";
-        if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = extension.kind;
-        if (2..=6).contains(&ext_literal.as_str().len());
-        if ext_literal.as_str().starts_with('.');
-        if ext_literal.as_str().chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit())
-            || ext_literal.as_str().chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit());
-        then {
-            let mut ty = ctx.typeck_results().expr_ty(obj);
-            ty = match ty.kind() {
-                ty::Ref(_, ty, ..) => *ty,
-                _ => ty
-            };
-
-            match ty.kind() {
-                ty::Str => {
-                    return Some(span);
-                },
-                ty::Adt(def, _) => {
-                    if ctx.tcx.is_diagnostic_item(sym::String, def.did()) {
-                        return Some(span);
-                    }
-                },
-                _ => { return None; }
-            }
-        }
-    }
-    None
-}
-
-impl<'tcx> LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons {
-    fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if let Some(span) = check_case_sensitive_file_extension_comparison(ctx, expr) {
-            span_lint_and_help(
-                ctx,
-                CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
-                span,
-                "case-sensitive file extension comparison",
-                None,
-                "consider using a case-insensitive comparison instead",
-            );
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs b/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
new file mode 100644 (file)
index 0000000..56e894c
--- /dev/null
@@ -0,0 +1,25 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, Ty, TyKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+
+use super::AS_UNDERSCORE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ty: &'tcx Ty<'_>) {
+    if matches!(ty.kind, TyKind::Infer) {
+        span_lint_and_then(cx, AS_UNDERSCORE, expr.span, "using `as _` conversion", |diag| {
+            let ty_resolved = cx.typeck_results().expr_ty(expr);
+            if let ty::Error(_) = ty_resolved.kind() {
+                diag.help("consider giving the type explicitly");
+            } else {
+                diag.span_suggestion(
+                    ty.span,
+                    "consider giving the type explicitly",
+                    ty_resolved,
+                    Applicability::MachineApplicable,
+                );
+            }
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
new file mode 100644 (file)
index 0000000..6e1f8cd
--- /dev/null
@@ -0,0 +1,37 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_no_std_crate;
+use clippy_utils::source::snippet_with_context;
+use rustc_errors::Applicability;
+use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind};
+use rustc_lint::LateContext;
+
+use super::BORROW_AS_PTR;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    cast_expr: &'tcx Expr<'_>,
+    cast_to: &'tcx Ty<'_>,
+) {
+    if matches!(cast_to.kind, TyKind::Ptr(_))
+        && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind
+    {
+        let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
+        let macro_name = match mutability {
+            Mutability::Not => "addr_of",
+            Mutability::Mut => "addr_of_mut",
+        };
+        let mut app = Applicability::MachineApplicable;
+        let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0;
+
+        span_lint_and_sugg(
+            cx,
+            BORROW_AS_PTR,
+            expr.span,
+            "borrow as raw pointer",
+            "try",
+            format!("{}::ptr::{}!({})", core_or_std, macro_name, snip),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
new file mode 100644 (file)
index 0000000..284ef16
--- /dev/null
@@ -0,0 +1,63 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{match_def_path, meets_msrv, msrvs, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{def_id::DefId, Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+use rustc_semver::RustcVersion;
+
+use super::CAST_SLICE_FROM_RAW_PARTS;
+
+enum RawPartsKind {
+    Immutable,
+    Mutable,
+}
+
+fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option<RawPartsKind> {
+    if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS) {
+        Some(RawPartsKind::Immutable)
+    } else if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS_MUT) {
+        Some(RawPartsKind::Mutable)
+    } else {
+        None
+    }
+}
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    cast_expr: &Expr<'_>,
+    cast_to: Ty<'_>,
+    msrv: Option<RustcVersion>,
+) {
+    if_chain! {
+        if meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS);
+        if let ty::RawPtr(ptrty) = cast_to.kind();
+        if let ty::Slice(_) = ptrty.ty.kind();
+        if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind;
+        if let ExprKind::Path(ref qpath) = fun.kind;
+        if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
+        if let Some(rpk) = raw_parts_kind(cx, fun_def_id);
+        then {
+            let func = match rpk {
+                RawPartsKind::Immutable => "from_raw_parts",
+                RawPartsKind::Mutable => "from_raw_parts_mut"
+            };
+            let span = expr.span;
+            let mut applicability = Applicability::MachineApplicable;
+            let ptr = snippet_with_applicability(cx, ptr_arg.span, "ptr", &mut applicability);
+            let len = snippet_with_applicability(cx, len_arg.span, "len", &mut applicability);
+            span_lint_and_sugg(
+                cx,
+                CAST_SLICE_FROM_RAW_PARTS,
+                span,
+                &format!("casting the result of `{func}` to {cast_to}"),
+                "replace with",
+                format!("core::ptr::slice_{func}({ptr}, {len})"),
+                applicability
+            );
+        }
+    }
+}
index af3798a0cc8c068520c2efad604a4947fb1c3079..cc5d346b954e3d393e71fa6090c4bcc0839bafa7 100644 (file)
@@ -1,3 +1,5 @@
+mod as_underscore;
+mod borrow_as_ptr;
 mod cast_abs_to_unsigned;
 mod cast_enum_constructor;
 mod cast_lossless;
@@ -8,6 +10,7 @@
 mod cast_ref_to_mut;
 mod cast_sign_loss;
 mod cast_slice_different_sizes;
+mod cast_slice_from_raw_parts;
 mod char_lit_as_u8;
 mod fn_to_numeric_cast;
 mod fn_to_numeric_cast_any;
@@ -16,7 +19,7 @@
 mod unnecessary_cast;
 mod utils;
 
-use clippy_utils::is_hir_ty_cfg_dependant;
+use clippy_utils::{is_hir_ty_cfg_dependant, meets_msrv, msrvs};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
     "casting the result of `abs()` to an unsigned integer can panic"
 }
 
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// fn foo(n: usize) {}
+    /// let n: u16 = 256;
+    /// foo(n as _);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn foo(n: usize) {}
+    /// let n: u16 = 256;
+    /// foo(n as usize);
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub AS_UNDERSCORE,
+    restriction,
+    "detects `as _` conversion"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// 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:
+    /// ```rust
+    /// 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);
+    /// ```
+    #[clippy::version = "1.60.0"]
+    pub BORROW_AS_PTR,
+    pedantic,
+    "borrowing just to cast to a raw pointer"
+}
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust,ignore
+    /// 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:
+    /// ```rust,ignore
+    /// 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
+    #[clippy::version = "1.64.0"]
+    pub CAST_SLICE_FROM_RAW_PARTS,
+    suspicious,
+    "casting a slice created from a pointer and length to a slice pointer"
+}
+
 pub struct Casts {
     msrv: Option<RustcVersion>,
 }
@@ -534,7 +624,10 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
     PTR_AS_PTR,
     CAST_ENUM_TRUNCATION,
     CAST_ENUM_CONSTRUCTOR,
-    CAST_ABS_TO_UNSIGNED
+    CAST_ABS_TO_UNSIGNED,
+    AS_UNDERSCORE,
+    BORROW_AS_PTR,
+    CAST_SLICE_FROM_RAW_PARTS
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -547,8 +640,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             return;
         }
 
-        if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
-            if is_hir_ty_cfg_dependant(cx, cast_to) {
+        if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind {
+            if is_hir_ty_cfg_dependant(cx, cast_to_hir) {
                 return;
             }
             let (cast_from, cast_to) = (
@@ -559,7 +652,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
                 return;
             }
-
+            cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, self.msrv);
             fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
             fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
             fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
@@ -575,6 +668,12 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
                 cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
             }
+
+            as_underscore::check(cx, expr, cast_to_hir);
+
+            if meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) {
+                borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
+            }
         }
 
         cast_ref_to_mut::check(cx, expr);
index fff7da8e33f2fff24aca3a5760557b58f893ac4a..19d2e6e1d1298e448619d608056a591ba13d88eb 100644 (file)
@@ -90,13 +90,20 @@ pub(super) fn check<'tcx>(
 
 fn lint_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &str, cast_from: Ty<'_>, cast_to: Ty<'_>) {
     let literal_kind_name = if cast_from.is_integral() { "integer" } else { "float" };
+    let replaced_literal;
+    let matchless = if literal_str.contains(['(', ')']) {
+        replaced_literal = literal_str.replace(['(', ')'], "");
+        &replaced_literal
+    } else {
+        literal_str
+    };
     span_lint_and_sugg(
         cx,
         UNNECESSARY_CAST,
         expr.span,
         &format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to),
         "try",
-        format!("{}_{}", literal_str.trim_end_matches('.'), cast_to),
+        format!("{}_{}", matchless.trim_end_matches('.'), cast_to),
         Applicability::MachineApplicable,
     );
 }
index 59f10247a11d4c98ea4821a3746ee2479c37aff9..1506ea604f0dd21ab827db4062d57bd9a2939532 100644 (file)
@@ -1,24 +1,34 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res};
-use clippy_utils::{get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage};
+use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res};
+use clippy_utils::{
+    fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, meets_msrv, msrvs, path_to_local,
+    walk_to_expr_usage,
+};
 use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{
-    self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId,
-    ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem,
-    TraitItemKind, TyKind, UnOp,
+    self as hir, def_id::DefId, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy,
+    GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind,
+    Path, QPath, TraitItem, TraitItemKind, TyKind, UnOp,
 };
+use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
-use rustc_middle::ty::{self, Binder, BoundVariableKind, List, Ty, TyCtxt, TypeVisitable, TypeckResults};
+use rustc_middle::ty::{
+    self, subst::Subst, Binder, BoundVariableKind, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind,
+    ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults,
+};
+use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
-use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
+use std::collections::VecDeque;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -151,6 +161,7 @@ pub struct Dereferencing {
     /// been finished. Note we can't lint at the end of every body as they can be nested within each
     /// other.
     current_body: Option<BodyId>,
+
     /// The list of locals currently being checked by the lint.
     /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
     /// This is needed for or patterns where one of the branches can be linted, but another can not
@@ -158,6 +169,19 @@ pub struct Dereferencing {
     ///
     /// e.g. `m!(x) | Foo::Bar(ref x)`
     ref_locals: FxIndexMap<HirId, Option<RefPat>>,
+
+    // `IntoIterator` for arrays requires Rust 1.53.
+    msrv: Option<RustcVersion>,
+}
+
+impl Dereferencing {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self {
+            msrv,
+            ..Dereferencing::default()
+        }
+    }
 }
 
 struct StateData {
@@ -170,6 +194,7 @@ struct StateData {
 struct DerefedBorrow {
     count: usize,
     msg: &'static str,
+    snip_expr: Option<HirId>,
 }
 
 enum State {
@@ -250,7 +275,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         match (self.state.take(), kind) {
             (None, kind) => {
                 let expr_ty = typeck.expr_ty(expr);
-                let (position, adjustments) = walk_parents(cx, expr);
+                let (position, adjustments) = walk_parents(cx, expr, self.msrv);
 
                 match kind {
                     RefOp::Deref => {
@@ -331,20 +356,23 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         let deref_msg =
                             "this expression creates a reference which is immediately dereferenced by the compiler";
                         let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
+                        let impl_msg = "the borrowed expression implements the required traits";
 
-                        let (required_refs, msg) = if position.can_auto_borrow() {
-                            (1, if deref_count == 1 { borrow_msg } else { deref_msg })
+                        let (required_refs, msg, snip_expr) = if position.can_auto_borrow() {
+                            (1, if deref_count == 1 { borrow_msg } else { deref_msg }, None)
+                        } else if let Position::ImplArg(hir_id) = position {
+                            (0, impl_msg, Some(hir_id))
                         } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) =
                             next_adjust.map(|a| &a.kind)
                         {
                             if matches!(mutability, AutoBorrowMutability::Mut { .. }) && !position.is_reborrow_stable()
                             {
-                                (3, deref_msg)
+                                (3, deref_msg, None)
                             } else {
-                                (2, deref_msg)
+                                (2, deref_msg, None)
                             }
                         } else {
-                            (2, deref_msg)
+                            (2, deref_msg, None)
                         };
 
                         if deref_count >= required_refs {
@@ -354,6 +382,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                                     // can't be removed without breaking the code. See earlier comment.
                                     count: deref_count - required_refs,
                                     msg,
+                                    snip_expr,
                                 }),
                                 StateData { span: expr.span, hir_id: expr.hir_id, position },
                             ));
@@ -510,7 +539,7 @@ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
                             spans: vec![pat.span],
                             app,
                             replacements: vec![(pat.span, snip.into())],
-                            hir_id: pat.hir_id
+                            hir_id: pat.hir_id,
                         }),
                     );
                 }
@@ -542,6 +571,8 @@ fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
             self.current_body = None;
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 fn try_parse_ref_op<'tcx>(
@@ -594,6 +625,7 @@ enum Position {
     /// The method is defined on a reference type. e.g. `impl Foo for &T`
     MethodReceiverRefImpl,
     Callee,
+    ImplArg(HirId),
     FieldAccess(Symbol),
     Postfix,
     Deref,
@@ -630,7 +662,7 @@ fn precedence(self) -> i8 {
             | Self::Callee
             | Self::FieldAccess(_)
             | Self::Postfix => PREC_POSTFIX,
-            Self::Deref => PREC_PREFIX,
+            Self::ImplArg(_) | Self::Deref => PREC_PREFIX,
             Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
         }
     }
@@ -639,8 +671,12 @@ fn precedence(self) -> i8 {
 /// Walks up the parent expressions attempting to determine both how stable the auto-deref result
 /// is, and which adjustments will be applied to it. Note this will not consider auto-borrow
 /// locations as those follow different rules.
-#[allow(clippy::too_many_lines)]
-fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &'tcx [Adjustment<'tcx>]) {
+#[expect(clippy::too_many_lines)]
+fn walk_parents<'tcx>(
+    cx: &LateContext<'tcx>,
+    e: &'tcx Expr<'_>,
+    msrv: Option<RustcVersion>,
+) -> (Position, &'tcx [Adjustment<'tcx>]) {
     let mut adjustments = [].as_slice();
     let mut precedence = 0i8;
     let ctxt = e.span.ctxt();
@@ -745,13 +781,20 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                     .iter()
                     .position(|arg| arg.hir_id == child_id)
                     .zip(expr_sig(cx, func))
-                    .and_then(|(i, sig)| sig.input_with_hir(i))
-                    .map(|(hir_ty, ty)| match hir_ty {
-                        // Type inference for closures can depend on how they're called. Only go by the explicit
-                        // types here.
-                        Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()),
-                        None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
-                            .position_for_arg(),
+                    .and_then(|(i, sig)| {
+                        sig.input_with_hir(i).map(|(hir_ty, ty)| match hir_ty {
+                            // Type inference for closures can depend on how they're called. Only go by the explicit
+                            // types here.
+                            Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()),
+                            None => {
+                                if let ty::Param(param_ty) = ty.skip_binder().kind() {
+                                    needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv)
+                                } else {
+                                    ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
+                                        .position_for_arg()
+                                }
+                            },
+                        })
                     }),
                 ExprKind::MethodCall(_, args, _) => {
                     let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
@@ -773,7 +816,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                                     .and_then(|subs| subs.get(1..))
                                 {
                                     Some(subs) => cx.tcx.mk_substs(subs.iter().copied()),
-                                    None => cx.tcx.mk_substs([].iter()),
+                                    None => cx.tcx.mk_substs(std::iter::empty::<ty::subst::GenericArg<'_>>()),
                                 } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
                                     // Trait methods taking `&self`
                                     sub_ty
@@ -792,12 +835,17 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                                 Position::MethodReceiver
                             }
                         } else {
-                            ty_auto_deref_stability(
-                                cx,
-                                cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
-                                precedence,
-                            )
-                            .position_for_arg()
+                            let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
+                            if let ty::Param(param_ty) = ty.kind() {
+                                needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv)
+                            } else {
+                                ty_auto_deref_stability(
+                                    cx,
+                                    cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
+                                    precedence,
+                                )
+                                .position_for_arg()
+                            }
                         }
                     })
                 },
@@ -948,6 +996,205 @@ fn visit_generic_arg(&mut self, arg: &GenericArg<'_>) {
     v.0
 }
 
+// Checks whether:
+// * child is an expression of the form `&e` in an argument position requiring an `impl Trait`
+// * `e`'s type implements `Trait` and is copyable
+// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`.
+//   The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to
+// be moved, but it cannot be.
+fn needless_borrow_impl_arg_position<'tcx>(
+    cx: &LateContext<'tcx>,
+    parent: &Expr<'tcx>,
+    arg_index: usize,
+    param_ty: ParamTy,
+    mut expr: &Expr<'tcx>,
+    precedence: i8,
+    msrv: Option<RustcVersion>,
+) -> Position {
+    let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
+    let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
+
+    let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) };
+    let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+    let substs_with_expr_ty = cx
+        .typeck_results()
+        .node_substs(if let ExprKind::Call(callee, _) = parent.kind {
+            callee.hir_id
+        } else {
+            parent.hir_id
+        });
+
+    let predicates = cx.tcx.param_env(callee_def_id).caller_bounds();
+    let projection_predicates = predicates
+        .iter()
+        .filter_map(|predicate| {
+            if let PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
+                Some(projection_predicate)
+            } else {
+                None
+            }
+        })
+        .collect::<Vec<_>>();
+
+    let mut trait_with_ref_mut_self_method = false;
+
+    // If no traits were found, or only the `Destruct`, `Sized`, or `Any` traits were found, return.
+    if predicates
+        .iter()
+        .filter_map(|predicate| {
+            if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder()
+                && trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx)
+            {
+                Some(trait_predicate.trait_ref.def_id)
+            } else {
+                None
+            }
+        })
+        .inspect(|trait_def_id| {
+            trait_with_ref_mut_self_method |= has_ref_mut_self_method(cx, *trait_def_id);
+        })
+        .all(|trait_def_id| {
+            Some(trait_def_id) == destruct_trait_def_id
+                || Some(trait_def_id) == sized_trait_def_id
+                || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id)
+        })
+    {
+        return Position::Other(precedence);
+    }
+
+    // `substs_with_referent_ty` can be constructed outside of `check_referent` because the same
+    // elements are modified each time `check_referent` is called.
+    let mut substs_with_referent_ty = substs_with_expr_ty.to_vec();
+
+    let mut check_referent = |referent| {
+        let referent_ty = cx.typeck_results().expr_ty(referent);
+
+        if !is_copy(cx, referent_ty) {
+            return false;
+        }
+
+        // https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
+        if trait_with_ref_mut_self_method && !matches!(referent_ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
+            return false;
+        }
+
+        if !replace_types(
+            cx,
+            param_ty,
+            referent_ty,
+            fn_sig,
+            arg_index,
+            &projection_predicates,
+            &mut substs_with_referent_ty,
+        ) {
+            return false;
+        }
+
+        predicates.iter().all(|predicate| {
+            if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder()
+                && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id)
+                && let ty::Param(param_ty) = trait_predicate.self_ty().kind()
+                && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack()
+                && ty.is_array()
+                && !meets_msrv(msrv, msrvs::ARRAY_INTO_ITERATOR)
+            {
+                return false;
+            }
+
+            let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty);
+            let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
+            cx.tcx
+                .infer_ctxt()
+                .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
+        })
+    };
+
+    let mut needless_borrow = false;
+    while let ExprKind::AddrOf(_, _, referent) = expr.kind {
+        if !check_referent(referent) {
+            break;
+        }
+        expr = referent;
+        needless_borrow = true;
+    }
+
+    if needless_borrow {
+        Position::ImplArg(expr.hir_id)
+    } else {
+        Position::Other(precedence)
+    }
+}
+
+fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
+    cx.tcx
+        .associated_items(trait_def_id)
+        .in_definition_order()
+        .any(|assoc_item| {
+            if assoc_item.fn_has_self_parameter {
+                let self_ty = cx.tcx.fn_sig(assoc_item.def_id).skip_binder().inputs()[0];
+                matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut))
+            } else {
+                false
+            }
+        })
+}
+
+// Iteratively replaces `param_ty` with `new_ty` in `substs`, and similarly for each resulting
+// projected type that is a type parameter. Returns `false` if replacing the types would have an
+// effect on the function signature beyond substituting `new_ty` for `param_ty`.
+// See: https://github.com/rust-lang/rust-clippy/pull/9136#discussion_r927212757
+fn replace_types<'tcx>(
+    cx: &LateContext<'tcx>,
+    param_ty: ParamTy,
+    new_ty: Ty<'tcx>,
+    fn_sig: FnSig<'tcx>,
+    arg_index: usize,
+    projection_predicates: &[ProjectionPredicate<'tcx>],
+    substs: &mut [ty::GenericArg<'tcx>],
+) -> bool {
+    let mut replaced = BitSet::new_empty(substs.len());
+
+    let mut deque = VecDeque::with_capacity(substs.len());
+    deque.push_back((param_ty, new_ty));
+
+    while let Some((param_ty, new_ty)) = deque.pop_front() {
+        // If `replaced.is_empty()`, then `param_ty` and `new_ty` are those initially passed in.
+        if !fn_sig
+            .inputs_and_output
+            .iter()
+            .enumerate()
+            .all(|(i, ty)| (replaced.is_empty() && i == arg_index) || !ty.contains(param_ty.to_ty(cx.tcx)))
+        {
+            return false;
+        }
+
+        substs[param_ty.index as usize] = ty::GenericArg::from(new_ty);
+
+        // The `replaced.insert(...)` check provides some protection against infinite loops.
+        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 ty::Param(term_param_ty) = term_ty.kind()
+                {
+                    let item_def_id = projection_predicate.projection_ty.item_def_id;
+                    let assoc_item = cx.tcx.associated_item(item_def_id);
+                    let projection = cx.tcx
+                        .mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, &[]));
+
+                    if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
+                        && substs[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty)
+                    {
+                        deque.push_back((*term_param_ty, projected_ty));
+                    }
+                }
+            }
+        }
+    }
+
+    true
+}
+
 struct TyPosition<'tcx> {
     position: Position,
     ty: Option<Ty<'tcx>>,
@@ -1086,7 +1333,8 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
         },
         State::DerefedBorrow(state) => {
             let mut app = Applicability::MachineApplicable;
-            let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
+            let snip_expr = state.snip_expr.map_or(expr, |hir_id| cx.tcx.hir().expect_expr(hir_id));
+            let (snip, snip_is_macro) = snippet_with_context(cx, snip_expr.span, data.span.ctxt(), "..", &mut app);
             span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| {
                 let calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee);
                 let sugg = if !snip_is_macro
index a982990e4186c9cc6c2aef5bb9477d9a7b96651a..9ca443b7dff6cbe67a24c5008dee96d2d09be293 100644 (file)
@@ -516,7 +516,10 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
         tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain(
             params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
                 tcx.mk_predicate(Binder::dummy(PredicateKind::Trait(TraitPredicate {
-                    trait_ref: TraitRef::new(eq_trait_id, tcx.mk_substs([tcx.mk_param_from_def(param)].into_iter())),
+                    trait_ref: TraitRef::new(
+                        eq_trait_id,
+                        tcx.mk_substs(std::iter::once(tcx.mk_param_from_def(param))),
+                    ),
                     constness: BoundConstness::NotConst,
                     polarity: ImplPolarity::Positive,
                 })))
index cb07f57e87006ff95368b8619b4bb559f983bc8a..0ff1d2755daf6284c5babcdc77a6989e05497f61 100644 (file)
@@ -21,7 +21,7 @@
     /// /// See also: [`foo`]
     /// fn bar() {}
     /// ```
-    #[clippy::version = "1.60.0"]
+    #[clippy::version = "1.63.0"]
     pub DOC_LINK_WITH_QUOTES,
     pedantic,
     "possible typo for an intra-doc link"
index e1eb3b6324c7820091e7b10dfa23f8c80d6e157a..7ff7068f0b05e56aec583ec5dd066ab280109193 100644 (file)
@@ -39,7 +39,7 @@
     /// // a.rs
     /// use crate::b;
     /// ```
-    #[clippy::version = "1.62.0"]
+    #[clippy::version = "1.63.0"]
     pub DUPLICATE_MOD,
     suspicious,
     "file loaded as module multiple times"
index 1ac7bfba06ba217a38c4d23560be1ac841116126..327865e4c858ab36e8166c5773aa505804a44cce 100644 (file)
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_hir;
-use clippy_utils::ty::contains_ty;
 use rustc_hir::intravisit;
 use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
 use rustc_infer::infer::TyCtxtInferExt;
@@ -30,18 +29,12 @@ pub struct BoxedLocal {
     ///
     /// ### Example
     /// ```rust
-    /// # fn foo(bar: usize) {}
-    /// let x = Box::new(1);
-    /// foo(*x);
-    /// println!("{}", *x);
+    /// fn foo(x: Box<u32>) {}
     /// ```
     ///
     /// Use instead:
     /// ```rust
-    /// # fn foo(bar: usize) {}
-    /// let x = 1;
-    /// foo(x);
-    /// println!("{}", x);
+    /// fn foo(x: u32) {}
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub BOXED_LOCAL,
@@ -172,7 +165,7 @@ fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
                 // skip if there is a `self` parameter binding to a type
                 // that contains `Self` (i.e.: `self: Box<Self>`), see #4804
                 if let Some(trait_self_ty) = self.trait_self_ty {
-                    if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(cmt.place.ty(), trait_self_ty) {
+                    if map.name(cmt.hir_id) == kw::SelfLower && cmt.place.ty().contains(trait_self_ty) {
                         return;
                     }
                 }
index df9b41d2c98bef1fe10d2f1eca1fe10e41477aab..bb50e8fcabbb712c15c4dd0cdae52368fbb8ae23 100644 (file)
@@ -172,7 +172,7 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
             expr.span,
             "logarithm for bases 2, 10 and e can be computed more accurately",
             "consider using",
-            format!("{}.{}()", Sugg::hir(cx, &args[0], ".."), method),
+            format!("{}.{}()", Sugg::hir(cx, &args[0], "..").maybe_par(), method),
             Applicability::MachineApplicable,
         );
     }
@@ -263,13 +263,13 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
             (
                 SUBOPTIMAL_FLOPS,
                 "square-root of a number can be computed more efficiently and accurately",
-                format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")),
+                format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
             )
         } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
             (
                 IMPRECISE_FLOPS,
                 "cube-root of a number can be computed more accurately",
-                format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")),
+                format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
             )
         } else if let Some(exponent) = get_integer_from_float_constant(&value) {
             (
@@ -277,7 +277,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                 "exponentiation with integer powers can be computed more efficiently",
                 format!(
                     "{}.powi({})",
-                    Sugg::hir(cx, &args[0], ".."),
+                    Sugg::hir(cx, &args[0], "..").maybe_par(),
                     numeric_literal::format(&exponent.to_string(), None, false)
                 ),
             )
@@ -327,7 +327,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                         "consider using",
                         format!(
                             "{}.mul_add({}, {})",
-                            Sugg::hir(cx, &args[0], ".."),
+                            Sugg::hir(cx, &args[0], "..").maybe_par(),
                             Sugg::hir(cx, &args[0], ".."),
                             Sugg::hir(cx, other_addend, ".."),
                         ),
@@ -418,7 +418,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
                 "consider using",
                 format!(
                     "{}.exp_m1()",
-                    Sugg::hir(cx, self_arg, "..")
+                    Sugg::hir(cx, self_arg, "..").maybe_par()
                 ),
                 Applicability::MachineApplicable,
             );
@@ -550,11 +550,11 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
         then {
             let positive_abs_sugg = (
                 "manual implementation of `abs` method",
-                format!("{}.abs()", Sugg::hir(cx, body, "..")),
+                format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_par()),
             );
             let negative_abs_sugg = (
                 "manual implementation of negation of `abs` method",
-                format!("-{}.abs()", Sugg::hir(cx, body, "..")),
+                format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_par()),
             );
             let sugg = if is_testing_positive(cx, cond, body) {
                 if if_expr_positive {
@@ -621,7 +621,7 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
                 expr.span,
                 "log base can be expressed more clearly",
                 "consider using",
-                format!("{}.log({})", Sugg::hir(cx, largs_self, ".."), Sugg::hir(cx, rargs_self, ".."),),
+                format!("{}.log({})", Sugg::hir(cx, largs_self, "..").maybe_par(), Sugg::hir(cx, rargs_self, ".."),),
                 Applicability::MachineApplicable,
             );
         }
@@ -651,7 +651,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) &&
                (F32(180_f32) == lvalue || F64(180_f64) == lvalue)
             {
-                let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
+                let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
                 if_chain! {
                     if let ExprKind::Lit(ref literal) = mul_lhs.kind;
                     if let ast::LitKind::Float(ref value, float_type) = literal.node;
@@ -677,7 +677,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
                 (F32(180_f32) == rvalue || F64(180_f64) == rvalue) &&
                 (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
             {
-                let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
+                let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
                 if_chain! {
                     if let ExprKind::Lit(ref literal) = mul_lhs.kind;
                     if let ast::LitKind::Float(ref value, float_type) = literal.node;
index 925a8cb8deed94ff792f3f4a7ce144ec5b2486c5..0c5851cdbed2a4241e0a3f2d35901f311dd732ec 100644 (file)
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
-use clippy_utils::source::{snippet_opt, snippet_with_applicability};
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -56,29 +56,27 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         };
 
         let mut applicability = Applicability::MachineApplicable;
-        if format_args.value_args.is_empty() {
-            match *format_args.format_string_parts {
+        if format_args.args.is_empty() {
+            match *format_args.format_string.parts {
                 [] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
                 [_] => {
-                    if let Some(s_src) = snippet_opt(cx, format_args.format_string_span) {
-                        // Simulate macro expansion, converting {{ and }} to { and }.
-                        let s_expand = s_src.replace("{{", "{").replace("}}", "}");
-                        let sugg = format!("{}.to_string()", s_expand);
-                        span_useless_format(cx, call_site, sugg, applicability);
-                    }
+                    // Simulate macro expansion, converting {{ and }} to { and }.
+                    let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}");
+                    let sugg = format!("{}.to_string()", s_expand);
+                    span_useless_format(cx, call_site, sugg, applicability);
                 },
                 [..] => {},
             }
-        } else if let [value] = *format_args.value_args {
+        } else if let [arg] = &*format_args.args {
+            let value = arg.param.value;
             if_chain! {
-                if format_args.format_string_parts == [kw::Empty];
+                if format_args.format_string.parts == [kw::Empty];
                 if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
                     ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()),
                     ty::Str => true,
                     _ => false,
                 };
-                if let Some(args) = format_args.args();
-                if args.iter().all(|arg| arg.format_trait == sym::Display && !arg.has_string_formatting());
+                if !arg.format.has_string_formatting();
                 then {
                     let is_new_string = match value.kind {
                         ExprKind::Binary(..) => true,
index 1e6feaac26c3ab77e604572bd461efcc27803ca3..9fb9fd99748b4b63eabb571073dcba3306d938fb 100644 (file)
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::is_diag_trait_item;
-use clippy_utils::macros::{is_format_macro, FormatArgsArg, FormatArgsExpn};
+use clippy_utils::macros::{is_format_macro, FormatArgsExpn};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::implements_trait;
 use if_chain::if_chain;
+use itertools::Itertools;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_middle::ty::Ty;
@@ -74,20 +75,16 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             if let Some(macro_def_id) = outermost_expn_data.macro_def_id;
             if is_format_macro(cx, macro_def_id);
             if let ExpnKind::Macro(_, name) = outermost_expn_data.kind;
-            if let Some(args) = format_args.args();
             then {
-                for (i, arg) in args.iter().enumerate() {
-                    if arg.format_trait != sym::Display {
+                for arg in &format_args.args {
+                    if arg.format.has_string_formatting() {
                         continue;
                     }
-                    if arg.has_string_formatting() {
+                    if is_aliased(&format_args, arg.param.value.hir_id) {
                         continue;
                     }
-                    if is_aliased(&args, i) {
-                        continue;
-                    }
-                    check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.value);
-                    check_to_string_in_format_args(cx, name, arg.value);
+                    check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value);
+                    check_to_string_in_format_args(cx, name, arg.param.value);
                 }
             }
         }
@@ -134,45 +131,56 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex
         if is_diag_trait_item(cx, method_def_id, sym::ToString);
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
         if let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display);
+        let (n_needed_derefs, target) =
+            count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter());
+        if implements_trait(cx, target, display_trait_id, &[]);
+        if let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait();
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
-            let (n_needed_derefs, target) = count_needed_derefs(
-                receiver_ty,
-                cx.typeck_results().expr_adjustments(receiver).iter(),
-            );
-            if implements_trait(cx, target, display_trait_id, &[]) {
-                if n_needed_derefs == 0 {
-                    span_lint_and_sugg(
-                        cx,
-                        TO_STRING_IN_FORMAT_ARGS,
-                        value.span.with_lo(receiver.span.hi()),
-                        &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
-                        "remove this",
-                        String::new(),
-                        Applicability::MachineApplicable,
-                    );
-                } else {
-                    span_lint_and_sugg(
-                        cx,
-                        TO_STRING_IN_FORMAT_ARGS,
-                        value.span,
-                        &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
-                        "use this",
-                        format!("{:*>width$}{}", "", receiver_snippet, width = n_needed_derefs),
-                        Applicability::MachineApplicable,
-                    );
-                }
+            let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]);
+            if n_needed_derefs == 0 && !needs_ref {
+                span_lint_and_sugg(
+                    cx,
+                    TO_STRING_IN_FORMAT_ARGS,
+                    value.span.with_lo(receiver.span.hi()),
+                    &format!(
+                        "`to_string` applied to a type that implements `Display` in `{}!` args",
+                        name
+                    ),
+                    "remove this",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                span_lint_and_sugg(
+                    cx,
+                    TO_STRING_IN_FORMAT_ARGS,
+                    value.span,
+                    &format!(
+                        "`to_string` applied to a type that implements `Display` in `{}!` args",
+                        name
+                    ),
+                    "use this",
+                    format!(
+                        "{}{:*>width$}{}",
+                        if needs_ref { "&" } else { "" },
+                        "",
+                        receiver_snippet,
+                        width = n_needed_derefs
+                    ),
+                    Applicability::MachineApplicable,
+                );
             }
         }
     }
 }
 
-// Returns true if `args[i]` "refers to" or "is referred to by" another argument.
-fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool {
-    let value = args[i].value;
-    args.iter()
-        .enumerate()
-        .any(|(j, arg)| i != j && std::ptr::eq(value, arg.value))
+// Returns true if `hir_id` is referred to by multiple format params
+fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool {
+    args.params()
+        .filter(|param| param.value.hir_id == hir_id)
+        .at_most_one()
+        .is_err()
 }
 
 fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
index 04b5be6c80ec6acf2727dfeaec769f0f71f43de0..d8bc0bf08f2b314b8513902d14f6da434e229d74 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArgsArg, FormatArgsExpn};
+use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArg, FormatArgsExpn};
 use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -168,10 +168,9 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>,
         if let macro_def_id = outer_macro.def_id;
         if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, outer_macro.expn);
         if is_format_macro(cx, macro_def_id);
-        if let Some(args) = format_args.args();
         then {
-            for arg in args {
-                if arg.format_trait != impl_trait.name {
+            for arg in format_args.args {
+                if arg.format.r#trait != impl_trait.name {
                     continue;
                 }
                 check_format_arg_self(cx, expr, &arg, impl_trait);
@@ -180,11 +179,11 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>,
     }
 }
 
-fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArgsArg<'_>, impl_trait: FormatTrait) {
+fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArg<'_>, impl_trait: FormatTrait) {
     // Handle multiple dereferencing of references e.g. &&self
     // Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl)
     // Since the argument to fmt is itself a reference: &self
-    let reference = peel_ref_operators(cx, arg.value);
+    let reference = peel_ref_operators(cx, arg.param.value);
     let map = cx.tcx.hir();
     // Is the reference self?
     if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) {
index 73261fb8a44c7c9ed0891bdb971b3f40a8edcaa9..90911e0bf2595ca667b9b3f14b0a755c0e4290f6 100644 (file)
@@ -1,6 +1,6 @@
 mod must_use;
 mod not_unsafe_ptr_arg_deref;
-mod result_unit_err;
+mod result;
 mod too_many_arguments;
 mod too_many_lines;
 
     "public function returning `Result` with an `Err` type of `()`"
 }
 
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// 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(())
+    /// }
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub RESULT_LARGE_ERR,
+    perf,
+    "function returning `Result` with large `Err` type"
+}
+
 #[derive(Copy, Clone)]
 pub struct Functions {
     too_many_arguments_threshold: u64,
     too_many_lines_threshold: u64,
+    large_error_threshold: u64,
 }
 
 impl Functions {
-    pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64) -> Self {
+    pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64) -> Self {
         Self {
             too_many_arguments_threshold,
             too_many_lines_threshold,
+            large_error_threshold,
         }
     }
 }
@@ -240,6 +285,7 @@ pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64) ->
     DOUBLE_MUST_USE,
     MUST_USE_CANDIDATE,
     RESULT_UNIT_ERR,
+    RESULT_LARGE_ERR,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Functions {
@@ -259,18 +305,18 @@ fn check_fn(
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
         must_use::check_item(cx, item);
-        result_unit_err::check_item(cx, item);
+        result::check_item(cx, item, self.large_error_threshold);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
         must_use::check_impl_item(cx, item);
-        result_unit_err::check_impl_item(cx, item);
+        result::check_impl_item(cx, item, self.large_error_threshold);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
         too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold);
         not_unsafe_ptr_arg_deref::check_trait_item(cx, item);
         must_use::check_trait_item(cx, item);
-        result_unit_err::check_trait_item(cx, item);
+        result::check_trait_item(cx, item, self.large_error_threshold);
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
new file mode 100644 (file)
index 0000000..af520a4
--- /dev/null
@@ -0,0 +1,100 @@
+use rustc_errors::Diagnostic;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LintContext};
+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;
+use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item};
+
+use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR};
+
+/// The type of the `Err`-variant in a `std::result::Result` returned by the
+/// given `FnDecl`
+fn result_err_ty<'tcx>(
+    cx: &LateContext<'tcx>,
+    decl: &hir::FnDecl<'tcx>,
+    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)
+        && is_type_diagnostic_item(cx, ty, sym::Result)
+        && let ty::Adt(_, substs) = ty.kind()
+    {
+        let err_ty = substs.type_at(1);
+        Some((hir_ty, err_ty))
+    } else {
+        None
+    }
+}
+
+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)
+    {
+        if cx.access_levels.is_exported(item.def_id) {
+            let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+            check_result_unit_err(cx, err_ty, fn_header_span);
+        }
+        check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold);
+    }
+}
+
+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)
+        && trait_ref_of_method(cx, item.def_id).is_none()
+    {
+        if cx.access_levels.is_exported(item.def_id) {
+            let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+            check_result_unit_err(cx, err_ty, fn_header_span);
+        }
+        check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold);
+    }
+}
+
+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 cx.access_levels.is_exported(item.def_id) {
+                check_result_unit_err(cx, err_ty, fn_header_span);
+            }
+            check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold);
+        }
+    }
+}
+
+fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: Span) {
+    if err_ty.is_unit() {
+        span_lint_and_help(
+            cx,
+            RESULT_UNIT_ERR,
+            fn_header_span,
+            "this returns a `Result<_, ()>`",
+            None,
+            "use a custom `Error` type instead",
+        );
+    }
+}
+
+fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) {
+    let ty_size = approx_ty_size(cx, err_ty);
+    if ty_size >= large_err_threshold {
+        span_lint_and_then(
+            cx,
+            RESULT_LARGE_ERR,
+            hir_ty_span,
+            "the `Err`-variant returned from this function is very large",
+            |diag: &mut Diagnostic| {
+                diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes"));
+                diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
+            },
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs b/src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs
deleted file mode 100644 (file)
index 2e63a1f..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty;
-use rustc_span::{sym, Span};
-use rustc_typeck::hir_ty_to_ty;
-
-use if_chain::if_chain;
-
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::trait_ref_of_method;
-use clippy_utils::ty::is_type_diagnostic_item;
-
-use super::RESULT_UNIT_ERR;
-
-pub(super) fn check_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
-    if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.def_id);
-        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if is_public {
-            check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
-        }
-    }
-}
-
-pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &hir::ImplItem<'_>) {
-    if let hir::ImplItemKind::Fn(ref sig, _) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.def_id);
-        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if is_public && trait_ref_of_method(cx, item.def_id).is_none() {
-            check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
-        }
-    }
-}
-
-pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>) {
-    if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.def_id);
-        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if is_public {
-            check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
-        }
-    }
-}
-
-fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span: Span, fn_header_span: Span) {
-    if_chain! {
-        if !in_external_macro(cx.sess(), item_span);
-        if let hir::FnRetTy::Return(ty) = decl.output;
-        let ty = hir_ty_to_ty(cx.tcx, ty);
-        if is_type_diagnostic_item(cx, ty, sym::Result);
-        if let ty::Adt(_, substs) = ty.kind();
-        let err_ty = substs.type_at(1);
-        if err_ty.is_unit();
-        then {
-            span_lint_and_help(
-                cx,
-                RESULT_UNIT_ERR,
-                fn_header_span,
-                "this returns a `Result<_, ()>`",
-                None,
-                "use a custom `Error` type instead",
-            );
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/get_first.rs b/src/tools/clippy/clippy_lints/src/get_first.rs
deleted file mode 100644 (file)
index 529f7ba..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_slice_of_primitives, match_def_path, paths};
-use if_chain::if_chain;
-use rustc_ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Spanned;
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// let x = vec![2, 3, 5];
-    /// let first_element = x.get(0);
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust
-    /// let x = vec![2, 3, 5];
-    /// let first_element = x.first();
-    /// ```
-    #[clippy::version = "1.63.0"]
-    pub GET_FIRST,
-    style,
-    "Using `x.get(0)` when `x.first()` is simpler"
-}
-declare_lint_pass!(GetFirst => [GET_FIRST]);
-
-impl<'tcx> LateLintPass<'tcx> for GetFirst {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if_chain! {
-            if let hir::ExprKind::MethodCall(_, [struct_calling_on, method_arg], _) = &expr.kind;
-            if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
-            if match_def_path(cx, expr_def_id, &paths::SLICE_GET);
-
-            if let Some(_) = is_slice_of_primitives(cx, struct_calling_on);
-            if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = method_arg.kind;
-
-            then {
-                let mut applicability = Applicability::MachineApplicable;
-                let slice_name = snippet_with_applicability(
-                    cx,
-                    struct_calling_on.span, "..",
-                    &mut applicability,
-                );
-                span_lint_and_sugg(
-                    cx,
-                    GET_FIRST,
-                    expr.span,
-                    &format!("accessing first element with `{0}.get(0)`", slice_name),
-                    "try",
-                    format!("{}.first()", slice_name),
-                    applicability,
-                );
-            }
-        }
-    }
-}
index e9501700784931c25ac97277fafa0b825ceac596..4d703d691acc2f81e57296256027072221c27214 100644 (file)
@@ -1,8 +1,9 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::SpanlessEq;
 use if_chain::if_chain;
+use rustc_errors::Diagnostic;
 use rustc_hir::intravisit::{self as visit, Visitor};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 
 impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        let mut arm_visit = ArmVisitor {
-            mutex_lock_called: false,
-            found_mutex: None,
-            cx,
-        };
-        let mut op_visit = OppVisitor {
-            mutex_lock_called: false,
-            found_mutex: None,
-            cx,
-        };
+        let mut arm_visit = ArmVisitor { found_mutex: None, cx };
+        let mut op_visit = OppVisitor { found_mutex: None, cx };
         if let Some(higher::IfLet {
             let_expr,
             if_then,
@@ -63,18 +56,28 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         }) = higher::IfLet::hir(cx, expr)
         {
             op_visit.visit_expr(let_expr);
-            if op_visit.mutex_lock_called {
+            if let Some(op_mutex) = op_visit.found_mutex {
                 arm_visit.visit_expr(if_then);
                 arm_visit.visit_expr(if_else);
 
-                if arm_visit.mutex_lock_called && arm_visit.same_mutex(cx, op_visit.found_mutex.unwrap()) {
-                    span_lint_and_help(
+                if let Some(arm_mutex) = arm_visit.found_mutex_if_same_as(op_mutex) {
+                    let diag = |diag: &mut Diagnostic| {
+                        diag.span_label(
+                            op_mutex.span,
+                            "this Mutex will remain locked for the entire `if let`-block...",
+                        );
+                        diag.span_label(
+                            arm_mutex.span,
+                            "... and is tried to lock again here, which will always deadlock.",
+                        );
+                        diag.help("move the lock call outside of the `if let ...` expression");
+                    };
+                    span_lint_and_then(
                         cx,
                         IF_LET_MUTEX,
                         expr.span,
                         "calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock",
-                        None,
-                        "move the lock call outside of the `if let ...` expression",
+                        diag,
                     );
                 }
             }
@@ -84,7 +87,6 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
 
 /// Checks if `Mutex::lock` is called in the `if let` expr.
 pub struct OppVisitor<'a, 'tcx> {
-    mutex_lock_called: bool,
     found_mutex: Option<&'tcx Expr<'tcx>>,
     cx: &'a LateContext<'tcx>,
 }
@@ -93,7 +95,6 @@ impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
             self.found_mutex = Some(mutex);
-            self.mutex_lock_called = true;
             return;
         }
         visit::walk_expr(self, expr);
@@ -102,7 +103,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 
 /// Checks if `Mutex::lock` is called in any of the branches.
 pub struct ArmVisitor<'a, 'tcx> {
-    mutex_lock_called: bool,
     found_mutex: Option<&'tcx Expr<'tcx>>,
     cx: &'a LateContext<'tcx>,
 }
@@ -111,7 +111,6 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
             self.found_mutex = Some(mutex);
-            self.mutex_lock_called = true;
             return;
         }
         visit::walk_expr(self, expr);
@@ -119,9 +118,12 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
 }
 
 impl<'tcx, 'l> ArmVisitor<'tcx, 'l> {
-    fn same_mutex(&self, cx: &LateContext<'_>, op_mutex: &Expr<'_>) -> bool {
-        self.found_mutex
-            .map_or(false, |arm_mutex| SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex))
+    fn found_mutex_if_same_as(&self, op_mutex: &Expr<'_>) -> Option<&Expr<'_>> {
+        self.found_mutex.and_then(|arm_mutex| {
+            SpanlessEq::new(self.cx)
+                .eq_expr(op_mutex, arm_mutex)
+                .then_some(arm_mutex)
+        })
     }
 }
 
@@ -129,7 +131,7 @@ fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Opt
     if_chain! {
         if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
         if path.ident.as_str() == "lock";
-        let ty = cx.typeck_results().expr_ty(self_arg);
+        let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
         if is_type_diagnostic_item(cx, ty, sym::Mutex);
         then {
             Some(self_arg)
index b8d227855d97616c1f4171dcd4e0b621068e328f..11c43247868ca46b817e01f60b13efe562a531b3 100644 (file)
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::source::snippet_with_macro_callsite;
 use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs, peel_blocks};
-use if_chain::if_chain;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for if-else that could be written to `bool::then`.
+    /// 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` helps it have less lines of code.
+    /// 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
     /// ```rust
@@ -39,7 +41,7 @@
     #[clippy::version = "1.53.0"]
     pub IF_THEN_SOME_ELSE_NONE,
     restriction,
-    "Finds if-else that could be written using `bool::then`"
+    "Finds if-else that could be written using either `bool::then` or `bool::then_some`"
 }
 
 pub struct IfThenSomeElseNone {
@@ -56,7 +58,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
 
 impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if !meets_msrv(self.msrv, msrvs::BOOL_THEN) {
             return;
         }
@@ -70,43 +72,47 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
             return;
         }
 
-        if_chain! {
-            if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr);
-            if let ExprKind::Block(then_block, _) = then.kind;
-            if let Some(then_expr) = then_block.expr;
-            if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind;
-            if let ExprKind::Path(ref then_call_qpath) = then_call.kind;
-            if is_lang_ctor(cx, then_call_qpath, OptionSome);
-            if let ExprKind::Path(ref qpath) = peel_blocks(els).kind;
-            if is_lang_ctor(cx, qpath, OptionNone);
-            if !stmts_contains_early_return(then_block.stmts);
-            then {
-                let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]");
-                let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) {
-                    format!("({})", cond_snip)
-                } else {
-                    cond_snip.into_owned()
-                };
-                let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, "");
-                let closure_body = if then_block.stmts.is_empty() {
-                    arg_snip.into_owned()
-                } else {
-                    format!("{{ /* snippet */ {} }}", arg_snip)
-                };
-                let help = format!(
-                    "consider using `bool::then` like: `{}.then(|| {})`",
-                    cond_snip,
-                    closure_body,
-                );
-                span_lint_and_help(
-                    cx,
-                    IF_THEN_SOME_ELSE_NONE,
-                    expr.span,
-                    "this could be simplified with `bool::then`",
-                    None,
-                    &help,
-                );
-            }
+        if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr)
+            && let ExprKind::Block(then_block, _) = then.kind
+            && let Some(then_expr) = then_block.expr
+            && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
+            && let ExprKind::Path(ref then_call_qpath) = then_call.kind
+            && is_lang_ctor(cx, then_call_qpath, OptionSome)
+            && let ExprKind::Path(ref qpath) = peel_blocks(els).kind
+            && is_lang_ctor(cx, qpath, OptionNone)
+            && !stmts_contains_early_return(then_block.stmts)
+        {
+            let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]");
+            let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) {
+                format!("({})", cond_snip)
+            } else {
+                cond_snip.into_owned()
+            };
+            let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, "");
+            let mut method_body = if then_block.stmts.is_empty() {
+                arg_snip.into_owned()
+            } else {
+                format!("{{ /* snippet */ {} }}", arg_snip)
+            };
+            let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) {
+                "then_some"
+            } else {
+                method_body.insert_str(0, "|| ");
+                "then"
+            };
+
+            let help = format!(
+                "consider using `bool::{}` like: `{}.{}({})`",
+                method_name, cond_snip, method_name, method_body,
+            );
+            span_lint_and_help(
+                cx,
+                IF_THEN_SOME_ELSE_NONE,
+                expr.span,
+                &format!("this could be simplified with `bool::{}`", method_name),
+                None,
+                &help,
+            );
         }
     }
 
index 01082cc8eeb64933304d54f3c2616d81a723f247..134cbbf7b5c66ad5f218173022533dc55b19c77b 100644 (file)
     LintId::of(booleans::NONMINIMAL_BOOL),
     LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
     LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
-    LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
     LintId::of(casts::CAST_ABS_TO_UNSIGNED),
     LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
     LintId::of(casts::CAST_ENUM_TRUNCATION),
     LintId::of(casts::CAST_REF_TO_MUT),
     LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
+    LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
     LintId::of(casts::CHAR_LIT_AS_U8),
     LintId::of(casts::FN_TO_NUMERIC_CAST),
     LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
@@ -80,9 +80,9 @@
     LintId::of(functions::DOUBLE_MUST_USE),
     LintId::of(functions::MUST_USE_UNIT),
     LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
+    LintId::of(functions::RESULT_LARGE_ERR),
     LintId::of(functions::RESULT_UNIT_ERR),
     LintId::of(functions::TOO_MANY_ARGUMENTS),
-    LintId::of(get_first::GET_FIRST),
     LintId::of(if_let_mutex::IF_LET_MUTEX),
     LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
     LintId::of(infinite_iter::INFINITE_ITER),
     LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID),
     LintId::of(manual_retain::MANUAL_RETAIN),
     LintId::of(manual_strip::MANUAL_STRIP),
-    LintId::of(map_clone::MAP_CLONE),
     LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
     LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
     LintId::of(match_result_ok::MATCH_RESULT_OK),
     LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
     LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
     LintId::of(methods::BIND_INSTEAD_OF_MAP),
+    LintId::of(methods::BYTES_COUNT_TO_LEN),
     LintId::of(methods::BYTES_NTH),
     LintId::of(methods::CHARS_LAST_CMP),
     LintId::of(methods::CHARS_NEXT_CMP),
     LintId::of(methods::CLONE_DOUBLE_REF),
     LintId::of(methods::CLONE_ON_COPY),
+    LintId::of(methods::COLLAPSIBLE_STR_REPLACE),
     LintId::of(methods::ERR_EXPECT),
     LintId::of(methods::EXPECT_FUN_CALL),
     LintId::of(methods::EXTEND_WITH_DRAIN),
     LintId::of(methods::FILTER_MAP_IDENTITY),
     LintId::of(methods::FILTER_NEXT),
     LintId::of(methods::FLAT_MAP_IDENTITY),
+    LintId::of(methods::GET_FIRST),
     LintId::of(methods::GET_LAST_WITH_LEN),
     LintId::of(methods::INSPECT_FOR_EACH),
     LintId::of(methods::INTO_ITER_ON_REF),
     LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
     LintId::of(methods::MANUAL_SPLIT_ONCE),
     LintId::of(methods::MANUAL_STR_REPEAT),
+    LintId::of(methods::MAP_CLONE),
     LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
     LintId::of(methods::MAP_FLATTEN),
     LintId::of(methods::MAP_IDENTITY),
+    LintId::of(methods::MUT_MUTEX_LOCK),
     LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
     LintId::of(methods::NEEDLESS_OPTION_TAKE),
     LintId::of(methods::NEEDLESS_SPLITN),
     LintId::of(methods::NEW_RET_NO_SELF),
+    LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
     LintId::of(methods::NO_EFFECT_REPLACE),
     LintId::of(methods::OBFUSCATED_IF_ELSE),
     LintId::of(methods::OK_EXPECT),
     LintId::of(methods::OPTION_MAP_OR_NONE),
     LintId::of(methods::OR_FUN_CALL),
     LintId::of(methods::OR_THEN_UNWRAP),
+    LintId::of(methods::RANGE_ZIP_WITH_LEN),
+    LintId::of(methods::REPEAT_ONCE),
     LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
     LintId::of(methods::SEARCH_IS_SOME),
     LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
     LintId::of(methods::STRING_EXTEND_CHARS),
     LintId::of(methods::SUSPICIOUS_MAP),
     LintId::of(methods::SUSPICIOUS_SPLITN),
+    LintId::of(methods::SUSPICIOUS_TO_OWNED),
     LintId::of(methods::UNINIT_ASSUMED_INIT),
+    LintId::of(methods::UNIT_HASH),
     LintId::of(methods::UNNECESSARY_FILTER_MAP),
     LintId::of(methods::UNNECESSARY_FIND_MAP),
     LintId::of(methods::UNNECESSARY_FOLD),
     LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
+    LintId::of(methods::UNNECESSARY_SORT_BY),
     LintId::of(methods::UNNECESSARY_TO_OWNED),
     LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
     LintId::of(methods::USELESS_ASREF),
+    LintId::of(methods::VEC_RESIZE_TO_ZERO),
     LintId::of(methods::WRONG_SELF_CONVENTION),
     LintId::of(methods::ZST_OFFSET),
     LintId::of(minmax::MIN_MAX),
     LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
     LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
     LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
+    LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
-    LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
     LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
     LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
     LintId::of(needless_bool::BOOL_COMPARISON),
     LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
     LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
     LintId::of(octal_escapes::OCTAL_ESCAPES),
-    LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
+    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
     LintId::of(operators::ABSURD_EXTREME_COMPARISONS),
     LintId::of(operators::ASSIGN_OP_PATTERN),
     LintId::of(operators::BAD_BIT_MASK),
     LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
     LintId::of(question_mark::QUESTION_MARK),
     LintId::of(ranges::MANUAL_RANGE_CONTAINS),
-    LintId::of(ranges::RANGE_ZIP_WITH_LEN),
     LintId::of(ranges::REVERSED_EMPTY_RANGES),
     LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
     LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC),
     LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
     LintId::of(reference::DEREF_ADDROF),
     LintId::of(regex::INVALID_REGEX),
-    LintId::of(repeat_once::REPEAT_ONCE),
     LintId::of(returns::LET_AND_RETURN),
     LintId::of(returns::NEEDLESS_RETURN),
     LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
     LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
     LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
     LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
+    LintId::of(transmute::TRANSMUTING_NULL),
     LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
     LintId::of(transmute::USELESS_TRANSMUTE),
     LintId::of(transmute::WRONG_TRANSMUTE),
-    LintId::of(transmuting_null::TRANSMUTING_NULL),
     LintId::of(types::BORROWED_BOX),
     LintId::of(types::BOX_COLLECTION),
     LintId::of(types::REDUNDANT_ALLOCATION),
     LintId::of(types::VEC_BOX),
     LintId::of(unicode::INVISIBLE_CHARACTERS),
     LintId::of(uninit_vec::UNINIT_VEC),
-    LintId::of(unit_hash::UNIT_HASH),
     LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
     LintId::of(unit_types::LET_UNIT_VALUE),
     LintId::of(unit_types::UNIT_ARG),
     LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
     LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
     LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS),
-    LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
     LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
     LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
+    LintId::of(unused_peekable::UNUSED_PEEKABLE),
     LintId::of(unused_unit::UNUSED_UNIT),
     LintId::of(unwrap::PANICKING_UNWRAP),
     LintId::of(unwrap::UNNECESSARY_UNWRAP),
     LintId::of(useless_conversion::USELESS_CONVERSION),
     LintId::of(vec::USELESS_VEC),
     LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
-    LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
+    LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS),
     LintId::of(write::PRINTLN_EMPTY_STRING),
     LintId::of(write::PRINT_LITERAL),
     LintId::of(write::PRINT_WITH_NEWLINE),
index 3784d3c68dceef2046f01b4f2a0393004867e35a..aa247352f88fb653ccbc6572c45bb74caedc63c7 100644 (file)
@@ -6,7 +6,6 @@
     LintId::of(attrs::DEPRECATED_CFG_ATTR),
     LintId::of(booleans::NONMINIMAL_BOOL),
     LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
-    LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
     LintId::of(casts::CHAR_LIT_AS_U8),
     LintId::of(casts::UNNECESSARY_CAST),
     LintId::of(dereference::EXPLICIT_AUTO_DEREF),
@@ -33,6 +32,7 @@
     LintId::of(matches::NEEDLESS_MATCH),
     LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
     LintId::of(methods::BIND_INSTEAD_OF_MAP),
+    LintId::of(methods::BYTES_COUNT_TO_LEN),
     LintId::of(methods::CLONE_ON_COPY),
     LintId::of(methods::FILTER_MAP_IDENTITY),
     LintId::of(methods::FILTER_NEXT),
     LintId::of(methods::OPTION_AS_REF_DEREF),
     LintId::of(methods::OPTION_FILTER_MAP),
     LintId::of(methods::OR_THEN_UNWRAP),
+    LintId::of(methods::RANGE_ZIP_WITH_LEN),
+    LintId::of(methods::REPEAT_ONCE),
     LintId::of(methods::SEARCH_IS_SOME),
     LintId::of(methods::SKIP_WHILE_NEXT),
     LintId::of(methods::UNNECESSARY_FILTER_MAP),
     LintId::of(methods::UNNECESSARY_FIND_MAP),
+    LintId::of(methods::UNNECESSARY_SORT_BY),
     LintId::of(methods::USELESS_ASREF),
     LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
     LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
@@ -69,6 +72,7 @@
     LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
     LintId::of(no_effect::NO_EFFECT),
     LintId::of(no_effect::UNNECESSARY_OPERATION),
+    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
     LintId::of(operators::DOUBLE_COMPARISONS),
     LintId::of(operators::DURATION_SUBSEC),
     LintId::of(operators::IDENTITY_OP),
     LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
     LintId::of(precedence::PRECEDENCE),
     LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
-    LintId::of(ranges::RANGE_ZIP_WITH_LEN),
     LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
     LintId::of(redundant_slicing::REDUNDANT_SLICING),
     LintId::of(reference::DEREF_ADDROF),
-    LintId::of(repeat_once::REPEAT_ONCE),
     LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
     LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
     LintId::of(swap::MANUAL_SWAP),
     LintId::of(types::TYPE_COMPLEXITY),
     LintId::of(types::VEC_BOX),
     LintId::of(unit_types::UNIT_ARG),
-    LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
     LintId::of(unwrap::UNNECESSARY_UNWRAP),
     LintId::of(useless_conversion::USELESS_CONVERSION),
     LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
index 006275d1383ff0d313784fb9a5a486d88068bd3e..bb94037ec2e7949ba52a2b25ba0bd89ae6794e89 100644 (file)
     LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
     LintId::of(methods::CLONE_DOUBLE_REF),
     LintId::of(methods::ITERATOR_STEP_BY_ZERO),
+    LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
     LintId::of(methods::SUSPICIOUS_SPLITN),
     LintId::of(methods::UNINIT_ASSUMED_INIT),
+    LintId::of(methods::UNIT_HASH),
+    LintId::of(methods::VEC_RESIZE_TO_ZERO),
     LintId::of(methods::ZST_OFFSET),
     LintId::of(minmax::MIN_MAX),
     LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
-    LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
     LintId::of(operators::ABSURD_EXTREME_COMPARISONS),
     LintId::of(operators::BAD_BIT_MASK),
     LintId::of(operators::CMP_NAN),
     LintId::of(serde_api::SERDE_API_MISUSE),
     LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
     LintId::of(swap::ALMOST_SWAPPED),
+    LintId::of(transmute::TRANSMUTING_NULL),
     LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
     LintId::of(transmute::WRONG_TRANSMUTE),
-    LintId::of(transmuting_null::TRANSMUTING_NULL),
     LintId::of(unicode::INVISIBLE_CHARACTERS),
     LintId::of(uninit_vec::UNINIT_VEC),
-    LintId::of(unit_hash::UNIT_HASH),
     LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
     LintId::of(unit_types::UNIT_CMP),
     LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
     LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
     LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
     LintId::of(unwrap::PANICKING_UNWRAP),
-    LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
 ])
index c540573b80228e8f3786a4117ab3dbda503266f7..fd20e016578a1bad268088cfe5dac73f0182b881 100644 (file)
@@ -38,7 +38,6 @@
     almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE,
     approx_const::APPROX_CONSTANT,
     as_conversions::AS_CONVERSIONS,
-    as_underscore::AS_UNDERSCORE,
     asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
     asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
     assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
     bool_assert_comparison::BOOL_ASSERT_COMPARISON,
     booleans::NONMINIMAL_BOOL,
     booleans::OVERLY_COMPLEX_BOOL_EXPR,
-    borrow_as_ptr::BORROW_AS_PTR,
     borrow_deref_ref::BORROW_DEREF_REF,
-    bytecount::NAIVE_BYTECOUNT,
-    bytes_count_to_len::BYTES_COUNT_TO_LEN,
     cargo::CARGO_COMMON_METADATA,
     cargo::MULTIPLE_CRATE_VERSIONS,
     cargo::NEGATIVE_FEATURE_NAMES,
     cargo::REDUNDANT_FEATURE_NAMES,
     cargo::WILDCARD_DEPENDENCIES,
-    case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+    casts::AS_UNDERSCORE,
+    casts::BORROW_AS_PTR,
     casts::CAST_ABS_TO_UNSIGNED,
     casts::CAST_ENUM_CONSTRUCTOR,
     casts::CAST_ENUM_TRUNCATION,
@@ -80,6 +77,7 @@
     casts::CAST_REF_TO_MUT,
     casts::CAST_SIGN_LOSS,
     casts::CAST_SLICE_DIFFERENT_SIZES,
+    casts::CAST_SLICE_FROM_RAW_PARTS,
     casts::CHAR_LIT_AS_U8,
     casts::FN_TO_NUMERIC_CAST,
     casts::FN_TO_NUMERIC_CAST_ANY,
     functions::MUST_USE_CANDIDATE,
     functions::MUST_USE_UNIT,
     functions::NOT_UNSAFE_PTR_ARG_DEREF,
+    functions::RESULT_LARGE_ERR,
     functions::RESULT_UNIT_ERR,
     functions::TOO_MANY_ARGUMENTS,
     functions::TOO_MANY_LINES,
     future_not_send::FUTURE_NOT_SEND,
-    get_first::GET_FIRST,
     if_let_mutex::IF_LET_MUTEX,
     if_not_else::IF_NOT_ELSE,
     if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
     manual_bits::MANUAL_BITS,
     manual_instant_elapsed::MANUAL_INSTANT_ELAPSED,
     manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
-    manual_ok_or::MANUAL_OK_OR,
     manual_rem_euclid::MANUAL_REM_EUCLID,
     manual_retain::MANUAL_RETAIN,
+    manual_string_new::MANUAL_STRING_NEW,
     manual_strip::MANUAL_STRIP,
-    map_clone::MAP_CLONE,
-    map_err_ignore::MAP_ERR_IGNORE,
     map_unit_fn::OPTION_MAP_UNIT_FN,
     map_unit_fn::RESULT_MAP_UNIT_FN,
     match_result_ok::MATCH_RESULT_OK,
     mem_replace::MEM_REPLACE_WITH_DEFAULT,
     mem_replace::MEM_REPLACE_WITH_UNINIT,
     methods::BIND_INSTEAD_OF_MAP,
+    methods::BYTES_COUNT_TO_LEN,
     methods::BYTES_NTH,
+    methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
     methods::CHARS_LAST_CMP,
     methods::CHARS_NEXT_CMP,
     methods::CLONED_INSTEAD_OF_COPIED,
     methods::CLONE_DOUBLE_REF,
     methods::CLONE_ON_COPY,
     methods::CLONE_ON_REF_PTR,
+    methods::COLLAPSIBLE_STR_REPLACE,
     methods::ERR_EXPECT,
     methods::EXPECT_FUN_CALL,
     methods::EXPECT_USED,
     methods::FLAT_MAP_IDENTITY,
     methods::FLAT_MAP_OPTION,
     methods::FROM_ITER_INSTEAD_OF_COLLECT,
+    methods::GET_FIRST,
     methods::GET_LAST_WITH_LEN,
     methods::GET_UNWRAP,
     methods::IMPLICIT_CLONE,
     methods::ITER_NEXT_SLICE,
     methods::ITER_NTH,
     methods::ITER_NTH_ZERO,
+    methods::ITER_ON_EMPTY_COLLECTIONS,
+    methods::ITER_ON_SINGLE_ITEMS,
     methods::ITER_OVEREAGER_CLONED,
     methods::ITER_SKIP_NEXT,
     methods::ITER_WITH_DRAIN,
     methods::MANUAL_FILTER_MAP,
     methods::MANUAL_FIND_MAP,
+    methods::MANUAL_OK_OR,
     methods::MANUAL_SATURATING_ARITHMETIC,
     methods::MANUAL_SPLIT_ONCE,
     methods::MANUAL_STR_REPEAT,
+    methods::MAP_CLONE,
     methods::MAP_COLLECT_RESULT_UNIT,
+    methods::MAP_ERR_IGNORE,
     methods::MAP_FLATTEN,
     methods::MAP_IDENTITY,
     methods::MAP_UNWRAP_OR,
+    methods::MUT_MUTEX_LOCK,
+    methods::NAIVE_BYTECOUNT,
     methods::NEEDLESS_OPTION_AS_DEREF,
     methods::NEEDLESS_OPTION_TAKE,
     methods::NEEDLESS_SPLITN,
     methods::NEW_RET_NO_SELF,
+    methods::NONSENSICAL_OPEN_OPTIONS,
     methods::NO_EFFECT_REPLACE,
     methods::OBFUSCATED_IF_ELSE,
     methods::OK_EXPECT,
     methods::OPTION_MAP_OR_NONE,
     methods::OR_FUN_CALL,
     methods::OR_THEN_UNWRAP,
+    methods::PATH_BUF_PUSH_OVERWRITE,
+    methods::RANGE_ZIP_WITH_LEN,
+    methods::REPEAT_ONCE,
     methods::RESULT_MAP_OR_INTO_OPTION,
     methods::SEARCH_IS_SOME,
     methods::SHOULD_IMPLEMENT_TRAIT,
     methods::SINGLE_CHAR_ADD_STR,
     methods::SINGLE_CHAR_PATTERN,
     methods::SKIP_WHILE_NEXT,
+    methods::STABLE_SORT_PRIMITIVE,
     methods::STRING_EXTEND_CHARS,
     methods::SUSPICIOUS_MAP,
     methods::SUSPICIOUS_SPLITN,
+    methods::SUSPICIOUS_TO_OWNED,
     methods::UNINIT_ASSUMED_INIT,
+    methods::UNIT_HASH,
     methods::UNNECESSARY_FILTER_MAP,
     methods::UNNECESSARY_FIND_MAP,
     methods::UNNECESSARY_FOLD,
     methods::UNNECESSARY_JOIN,
     methods::UNNECESSARY_LAZY_EVALUATIONS,
+    methods::UNNECESSARY_SORT_BY,
     methods::UNNECESSARY_TO_OWNED,
     methods::UNWRAP_OR_ELSE_DEFAULT,
     methods::UNWRAP_USED,
     methods::USELESS_ASREF,
+    methods::VEC_RESIZE_TO_ZERO,
+    methods::VERBOSE_FILE_READS,
     methods::WRONG_SELF_CONVENTION,
     methods::ZST_OFFSET,
     minmax::MIN_MAX,
     mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION,
     module_style::MOD_MODULE_FILES,
     module_style::SELF_NAMED_MODULE_FILES,
+    multi_assignments::MULTI_ASSIGNMENTS,
     mut_key::MUTABLE_KEY_TYPE,
     mut_mut::MUT_MUT,
-    mut_mutex_lock::MUT_MUTEX_LOCK,
     mut_reference::UNNECESSARY_MUT_PASSED,
     mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
     mutex_atomic::MUTEX_ATOMIC,
     nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
     octal_escapes::OCTAL_ESCAPES,
     only_used_in_recursion::ONLY_USED_IN_RECURSION,
-    open_options::NONSENSICAL_OPEN_OPTIONS,
     operators::ABSURD_EXTREME_COMPARISONS,
     operators::ARITHMETIC,
     operators::ASSIGN_OP_PATTERN,
     partialeq_to_none::PARTIALEQ_TO_NONE,
     pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
     pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
-    path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
     pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
     precedence::PRECEDENCE,
     ptr::CMP_NULL,
     ranges::MANUAL_RANGE_CONTAINS,
     ranges::RANGE_MINUS_ONE,
     ranges::RANGE_PLUS_ONE,
-    ranges::RANGE_ZIP_WITH_LEN,
     ranges::REVERSED_EMPTY_RANGES,
     rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT,
     read_zero_byte_vec::READ_ZERO_BYTE_VEC,
     reference::DEREF_ADDROF,
     regex::INVALID_REGEX,
     regex::TRIVIAL_REGEX,
-    repeat_once::REPEAT_ONCE,
     return_self_not_must_use::RETURN_SELF_NOT_MUST_USE,
     returns::LET_AND_RETURN,
     returns::NEEDLESS_RETURN,
     single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
     size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
     slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
-    stable_sort_primitive::STABLE_SORT_PRIMITIVE,
     std_instead_of_core::ALLOC_INSTEAD_OF_CORE,
     std_instead_of_core::STD_INSTEAD_OF_ALLOC,
     std_instead_of_core::STD_INSTEAD_OF_CORE,
     transmute::TRANSMUTE_PTR_TO_PTR,
     transmute::TRANSMUTE_PTR_TO_REF,
     transmute::TRANSMUTE_UNDEFINED_REPR,
+    transmute::TRANSMUTING_NULL,
     transmute::UNSOUND_COLLECTION_TRANSMUTE,
     transmute::USELESS_TRANSMUTE,
     transmute::WRONG_TRANSMUTE,
-    transmuting_null::TRANSMUTING_NULL,
     types::BORROWED_BOX,
     types::BOX_COLLECTION,
     types::LINKEDLIST,
     unicode::NON_ASCII_LITERAL,
     unicode::UNICODE_NOT_NFC,
     uninit_vec::UNINIT_VEC,
-    unit_hash::UNIT_HASH,
     unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
     unit_types::LET_UNIT_VALUE,
     unit_types::UNIT_ARG,
     unnamed_address::VTABLE_ADDRESS_COMPARISONS,
     unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS,
     unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS,
-    unnecessary_sort_by::UNNECESSARY_SORT_BY,
     unnecessary_wraps::UNNECESSARY_WRAPS,
     unnested_or_patterns::UNNESTED_OR_PATTERNS,
     unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
     unused_async::UNUSED_ASYNC,
     unused_io_amount::UNUSED_IO_AMOUNT,
+    unused_peekable::UNUSED_PEEKABLE,
     unused_rounding::UNUSED_ROUNDING,
     unused_self::UNUSED_SELF,
     unused_unit::UNUSED_UNIT,
     useless_conversion::USELESS_CONVERSION,
     vec::USELESS_VEC,
     vec_init_then_push::VEC_INIT_THEN_PUSH,
-    vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
-    verbose_file_reads::VERBOSE_FILE_READS,
     wildcard_imports::ENUM_GLOB_USE,
     wildcard_imports::WILDCARD_IMPORTS,
+    write::POSITIONAL_NAMED_FORMAT_PARAMETERS,
     write::PRINTLN_EMPTY_STRING,
     write::PRINT_LITERAL,
     write::PRINT_STDERR,
index 91210b23afe30c46c31d796b7b4f1e1bdcae82b5..e319e7ee72c57ac656a77dbe35cd248795788d41 100644 (file)
     LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE),
     LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
     LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
+    LintId::of(methods::ITER_ON_EMPTY_COLLECTIONS),
+    LintId::of(methods::ITER_ON_SINGLE_ITEMS),
     LintId::of(methods::ITER_WITH_DRAIN),
+    LintId::of(methods::PATH_BUF_PUSH_OVERWRITE),
     LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
     LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
     LintId::of(mutex_atomic::MUTEX_ATOMIC),
     LintId::of(mutex_atomic::MUTEX_INTEGER),
     LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
     LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
-    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
     LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
-    LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
     LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
     LintId::of(regex::TRIVIAL_REGEX),
     LintId::of(strings::STRING_LIT_AS_BYTES),
index bd7d1a15ab4ea1dad05f3b905d28f3392107d38f..584ccf55e5114fc8f008eb57a4c14bb1de4b85be 100644 (file)
@@ -4,9 +4,7 @@
 
 store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(attrs::INLINE_ALWAYS),
-    LintId::of(borrow_as_ptr::BORROW_AS_PTR),
-    LintId::of(bytecount::NAIVE_BYTECOUNT),
-    LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
+    LintId::of(casts::BORROW_AS_PTR),
     LintId::of(casts::CAST_LOSSLESS),
     LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
     LintId::of(casts::CAST_POSSIBLE_WRAP),
     LintId::of(macro_use::MACRO_USE_IMPORTS),
     LintId::of(manual_assert::MANUAL_ASSERT),
     LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED),
-    LintId::of(manual_ok_or::MANUAL_OK_OR),
+    LintId::of(manual_string_new::MANUAL_STRING_NEW),
     LintId::of(matches::MATCH_BOOL),
     LintId::of(matches::MATCH_ON_VEC_ITEMS),
     LintId::of(matches::MATCH_SAME_ARMS),
     LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
     LintId::of(matches::MATCH_WILD_ERR_ARM),
     LintId::of(matches::SINGLE_MATCH_ELSE),
+    LintId::of(methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
     LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
     LintId::of(methods::FILTER_MAP_NEXT),
     LintId::of(methods::FLAT_MAP_OPTION),
     LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT),
     LintId::of(methods::IMPLICIT_CLONE),
     LintId::of(methods::INEFFICIENT_TO_STRING),
+    LintId::of(methods::MANUAL_OK_OR),
     LintId::of(methods::MAP_UNWRAP_OR),
+    LintId::of(methods::NAIVE_BYTECOUNT),
+    LintId::of(methods::STABLE_SORT_PRIMITIVE),
     LintId::of(methods::UNNECESSARY_JOIN),
     LintId::of(misc::USED_UNDERSCORE_BINDING),
     LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER),
@@ -85,7 +87,6 @@
     LintId::of(ref_option_ref::REF_OPTION_REF),
     LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
     LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
-    LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
     LintId::of(strings::STRING_ADD_ASSIGN),
     LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
     LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
index e1b90acb93c2e9ae78baa4778790830996eb5065..195ce41e31e9f6b4687633830b35d974eca6ef3c 100644 (file)
@@ -7,12 +7,14 @@
     LintId::of(escape::BOXED_LOCAL),
     LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
     LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
+    LintId::of(functions::RESULT_LARGE_ERR),
     LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
     LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
     LintId::of(loops::MANUAL_MEMCPY),
     LintId::of(loops::MISSING_SPIN_LOOP),
     LintId::of(loops::NEEDLESS_COLLECT),
     LintId::of(manual_retain::MANUAL_RETAIN),
+    LintId::of(methods::COLLAPSIBLE_STR_REPLACE),
     LintId::of(methods::EXPECT_FUN_CALL),
     LintId::of(methods::EXTEND_WITH_DRAIN),
     LintId::of(methods::ITER_NTH),
index a7339ef272174d4ee4955b60edd66778cd032461..dd1e1e1a8e33d82088578a75adcaa49cf7db7128 100644 (file)
@@ -4,11 +4,11 @@
 
 store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
     LintId::of(as_conversions::AS_CONVERSIONS),
-    LintId::of(as_underscore::AS_UNDERSCORE),
     LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
     LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
     LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
     LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON),
+    LintId::of(casts::AS_UNDERSCORE),
     LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
     LintId::of(create_dir::CREATE_DIR),
     LintId::of(dbg_macro::DBG_MACRO),
@@ -30,7 +30,6 @@
     LintId::of(large_include_file::LARGE_INCLUDE_FILE),
     LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
     LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
-    LintId::of(map_err_ignore::MAP_ERR_IGNORE),
     LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
     LintId::of(matches::TRY_ERR),
     LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
@@ -39,7 +38,9 @@
     LintId::of(methods::EXPECT_USED),
     LintId::of(methods::FILETYPE_IS_FILE),
     LintId::of(methods::GET_UNWRAP),
+    LintId::of(methods::MAP_ERR_IGNORE),
     LintId::of(methods::UNWRAP_USED),
+    LintId::of(methods::VERBOSE_FILE_READS),
     LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
     LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
     LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
@@ -81,7 +82,6 @@
     LintId::of(unicode::NON_ASCII_LITERAL),
     LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
     LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
-    LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
     LintId::of(write::PRINT_STDERR),
     LintId::of(write::PRINT_STDOUT),
     LintId::of(write::USE_DEBUG),
index bfa654238f130386f1332b134d6a86eefc0fe544..b5cb078e7a3ccce2fc5a8f0b7ed93b68cca24585 100644 (file)
@@ -29,7 +29,6 @@
     LintId::of(functions::DOUBLE_MUST_USE),
     LintId::of(functions::MUST_USE_UNIT),
     LintId::of(functions::RESULT_UNIT_ERR),
-    LintId::of(get_first::GET_FIRST),
     LintId::of(inherent_to_string::INHERENT_TO_STRING),
     LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
     LintId::of(len_zero::COMPARISON_TO_EMPTY),
@@ -45,7 +44,6 @@
     LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
     LintId::of(manual_bits::MANUAL_BITS),
     LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
-    LintId::of(map_clone::MAP_CLONE),
     LintId::of(match_result_ok::MATCH_RESULT_OK),
     LintId::of(matches::COLLAPSIBLE_MATCH),
     LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
@@ -61,6 +59,7 @@
     LintId::of(methods::CHARS_LAST_CMP),
     LintId::of(methods::CHARS_NEXT_CMP),
     LintId::of(methods::ERR_EXPECT),
+    LintId::of(methods::GET_FIRST),
     LintId::of(methods::INTO_ITER_ON_REF),
     LintId::of(methods::IS_DIGIT_ASCII_RADIX),
     LintId::of(methods::ITER_CLONED_COLLECT),
@@ -68,7 +67,9 @@
     LintId::of(methods::ITER_NTH_ZERO),
     LintId::of(methods::ITER_SKIP_NEXT),
     LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
+    LintId::of(methods::MAP_CLONE),
     LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
+    LintId::of(methods::MUT_MUTEX_LOCK),
     LintId::of(methods::NEW_RET_NO_SELF),
     LintId::of(methods::OBFUSCATED_IF_ELSE),
     LintId::of(methods::OK_EXPECT),
@@ -88,7 +89,6 @@
     LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
     LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
     LintId::of(misc_early::REDUNDANT_PATTERN),
-    LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
     LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
     LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
     LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS),
index 964992bd94fe259f64aa4cd6a99a3e05621cca44..8f131bbf98be3fecab313b2ae904e982620fd88d 100644 (file)
@@ -11,6 +11,7 @@
     LintId::of(casts::CAST_ABS_TO_UNSIGNED),
     LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
     LintId::of(casts::CAST_ENUM_TRUNCATION),
+    LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
     LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
     LintId::of(drop_forget_ref::DROP_NON_DROP),
     LintId::of(drop_forget_ref::FORGET_NON_DROP),
@@ -24,6 +25,8 @@
     LintId::of(loops::MUT_RANGE_BOUND),
     LintId::of(methods::NO_EFFECT_REPLACE),
     LintId::of(methods::SUSPICIOUS_MAP),
+    LintId::of(methods::SUSPICIOUS_TO_OWNED),
+    LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
     LintId::of(octal_escapes::OCTAL_ESCAPES),
     LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
@@ -32,4 +35,6 @@
     LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
     LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF),
+    LintId::of(unused_peekable::UNUSED_PEEKABLE),
+    LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS),
 ])
index e6a405f8170d8f0a8e06df0fb807942f9eaf22d4..dfdaf90f09f48151eda7964dd3d2a02cba705271 100644 (file)
@@ -4,6 +4,7 @@
 #![feature(control_flow_enum)]
 #![feature(drain_filter)]
 #![feature(iter_intersperse)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(lint_reasons)]
 #![feature(never_type)]
@@ -170,7 +171,6 @@ macro_rules! declare_clippy_lint {
 mod almost_complete_letter_range;
 mod approx_const;
 mod as_conversions;
-mod as_underscore;
 mod asm_syntax;
 mod assertions_on_constants;
 mod assertions_on_result_states;
@@ -180,12 +180,8 @@ macro_rules! declare_clippy_lint {
 mod blocks_in_if_conditions;
 mod bool_assert_comparison;
 mod booleans;
-mod borrow_as_ptr;
 mod borrow_deref_ref;
-mod bytecount;
-mod bytes_count_to_len;
 mod cargo;
-mod case_sensitive_file_extension_comparisons;
 mod casts;
 mod checked_conversions;
 mod cognitive_complexity;
@@ -238,7 +234,6 @@ macro_rules! declare_clippy_lint {
 mod from_str_radix_10;
 mod functions;
 mod future_not_send;
-mod get_first;
 mod if_let_mutex;
 mod if_not_else;
 mod if_then_some_else_none;
@@ -275,12 +270,10 @@ macro_rules! declare_clippy_lint {
 mod manual_bits;
 mod manual_instant_elapsed;
 mod manual_non_exhaustive;
-mod manual_ok_or;
 mod manual_rem_euclid;
 mod manual_retain;
+mod manual_string_new;
 mod manual_strip;
-mod map_clone;
-mod map_err_ignore;
 mod map_unit_fn;
 mod match_result_ok;
 mod matches;
@@ -297,9 +290,9 @@ macro_rules! declare_clippy_lint {
 mod missing_inline;
 mod mixed_read_write_in_expression;
 mod module_style;
+mod multi_assignments;
 mod mut_key;
 mod mut_mut;
-mod mut_mutex_lock;
 mod mut_reference;
 mod mutable_debug_assertion;
 mod mutex_atomic;
@@ -324,7 +317,6 @@ macro_rules! declare_clippy_lint {
 mod nonstandard_macro_braces;
 mod octal_escapes;
 mod only_used_in_recursion;
-mod open_options;
 mod operators;
 mod option_env_unwrap;
 mod option_if_let_else;
@@ -334,7 +326,6 @@ macro_rules! declare_clippy_lint {
 mod partialeq_ne_impl;
 mod partialeq_to_none;
 mod pass_by_ref_or_value;
-mod path_buf_push_overwrite;
 mod pattern_type_mismatch;
 mod precedence;
 mod ptr;
@@ -354,7 +345,6 @@ macro_rules! declare_clippy_lint {
 mod ref_option_ref;
 mod reference;
 mod regex;
-mod repeat_once;
 mod return_self_not_must_use;
 mod returns;
 mod same_name_method;
@@ -366,7 +356,6 @@ macro_rules! declare_clippy_lint {
 mod single_component_path_imports;
 mod size_of_in_element_count;
 mod slow_vector_initialization;
-mod stable_sort_primitive;
 mod std_instead_of_core;
 mod strings;
 mod strlen_on_c_strings;
@@ -380,23 +369,21 @@ macro_rules! declare_clippy_lint {
 mod trailing_empty_array;
 mod trait_bounds;
 mod transmute;
-mod transmuting_null;
 mod types;
 mod undocumented_unsafe_blocks;
 mod unicode;
 mod uninit_vec;
-mod unit_hash;
 mod unit_return_expecting_ord;
 mod unit_types;
 mod unnamed_address;
 mod unnecessary_owned_empty_strings;
 mod unnecessary_self_imports;
-mod unnecessary_sort_by;
 mod unnecessary_wraps;
 mod unnested_or_patterns;
 mod unsafe_removed_from_name;
 mod unused_async;
 mod unused_io_amount;
+mod unused_peekable;
 mod unused_rounding;
 mod unused_self;
 mod unused_unit;
@@ -407,8 +394,6 @@ macro_rules! declare_clippy_lint {
 mod useless_conversion;
 mod vec;
 mod vec_init_then_push;
-mod vec_resize_to_zero;
-mod verbose_file_reads;
 mod wildcard_imports;
 mod write;
 mod zero_div_zero;
@@ -596,7 +581,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     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_hash::UnitHash));
     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));
@@ -634,8 +618,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     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(move || Box::new(map_clone::MapClone::new(msrv)));
-
     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;
@@ -645,7 +627,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
             msrv,
         ))
     });
-    store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore));
     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));
@@ -653,7 +634,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     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(open_options::OpenOptions));
     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));
@@ -689,10 +669,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     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 || {
         Box::new(functions::Functions::new(
             too_many_arguments_threshold,
             too_many_lines_threshold,
+            large_error_threshold,
         ))
     });
     let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
@@ -719,7 +701,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     );
     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(bytecount::ByteCount));
     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()));
@@ -737,12 +718,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     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(|| Box::new(unnecessary_sort_by::UnnecessarySortBy));
     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(transmuting_null::TransmutingNull));
-    store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite));
     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)));
@@ -818,18 +796,15 @@ 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(verbose_file_reads::VerboseFileReads));
     store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default()));
     store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress));
-    store.register_late_pass(|| Box::new(dereference::Dereferencing::default()));
+    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(mut_mutex_lock::MutMutexLock));
     store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn));
-    store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero));
     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 || {
@@ -841,10 +816,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     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(stable_sort_primitive::StableSortPrimitive));
-    store.register_late_pass(|| Box::new(repeat_once::RepeatOnce));
     store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult));
-    store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr));
     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();
@@ -856,9 +828,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     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(case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons)
-    });
     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)));
@@ -893,11 +862,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     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(borrow_as_ptr::BorrowAsPtr::new(msrv)));
     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));
+    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)));
     let cargo_ignore_publish = conf.cargo_ignore_publish;
@@ -911,18 +879,15 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     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(bytes_count_to_len::BytesCountToLen));
     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_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default()));
-    store.register_late_pass(|| Box::new(get_first::GetFirst));
     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(as_underscore::AsUnderscore));
     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)));
@@ -933,6 +898,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     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));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
index ddaffc751880db30251f01d8c246af8c9d8568d6..6d987f393fa5ce353c2d38dae517e5cdf18f1a6d 100644 (file)
@@ -1,5 +1,6 @@
 use super::NEEDLESS_COLLECT;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
+use clippy_utils::higher;
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -184,10 +185,19 @@ struct IterFunctionVisitor<'a, 'tcx> {
 impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
     fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
         for (expr, hir_id) in block.stmts.iter().filter_map(get_expr_and_hir_id_from_stmt) {
+            if check_loop_kind(expr).is_some() {
+                continue;
+            }
             self.visit_block_expr(expr, hir_id);
         }
         if let Some(expr) = block.expr {
-            self.visit_block_expr(expr, None);
+            if let Some(loop_kind) = check_loop_kind(expr) {
+                if let LoopKind::Conditional(block_expr) = loop_kind {
+                    self.visit_block_expr(block_expr, None);
+                }
+            } else {
+                self.visit_block_expr(expr, None);
+            }
         }
     }
 
@@ -264,6 +274,28 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
     }
 }
 
+enum LoopKind<'tcx> {
+    Conditional(&'tcx Expr<'tcx>),
+    Loop,
+}
+
+fn check_loop_kind<'tcx>(expr: &Expr<'tcx>) -> Option<LoopKind<'tcx>> {
+    if let Some(higher::WhileLet { let_expr, .. }) = higher::WhileLet::hir(expr) {
+        return Some(LoopKind::Conditional(let_expr));
+    }
+    if let Some(higher::While { condition, .. }) = higher::While::hir(expr) {
+        return Some(LoopKind::Conditional(condition));
+    }
+    if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr) {
+        return Some(LoopKind::Conditional(arg));
+    }
+    if let ExprKind::Loop { .. } = expr.kind {
+        return Some(LoopKind::Loop);
+    }
+
+    None
+}
+
 impl<'tcx> IterFunctionVisitor<'_, 'tcx> {
     fn visit_block_expr(&mut self, expr: &'tcx Expr<'tcx>, hir_id: Option<HirId>) {
         self.current_statement_hir_id = hir_id;
index a0ca7e6ff1e22b78f2cd4c08a8ca29c6cea71e8c..2502c8f880ddce76aa1045cfcdc815aaa315209d 100644 (file)
@@ -192,7 +192,7 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str,
     match output.kind {
         TyKind::Tup(tys) if tys.is_empty() => {
             let sugg = "remove the return type";
-            Some((sugg, "".into()))
+            Some((sugg, String::new()))
         },
         _ => {
             let sugg = "return the output of the future directly";
diff --git a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
deleted file mode 100644 (file)
index cf50043..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_lang_ctor, path_to_local_id};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::LangItem::{ResultErr, ResultOk};
-use rustc_hir::{Closure, Expr, ExprKind, PatKind};
-use rustc_lint::LintContext;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::sym;
-
-declare_clippy_lint! {
-    /// ### What it does
-    ///
-    /// Finds patterns that reimplement `Option::ok_or`.
-    ///
-    /// ### Why is this bad?
-    ///
-    /// Concise code helps focusing on behavior instead of boilerplate.
-    ///
-    /// ### Examples
-    /// ```rust
-    /// let foo: Option<i32> = None;
-    /// foo.map_or(Err("error"), |v| Ok(v));
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust
-    /// let foo: Option<i32> = None;
-    /// foo.ok_or("error");
-    /// ```
-    #[clippy::version = "1.49.0"]
-    pub MANUAL_OK_OR,
-    pedantic,
-    "finds patterns that can be encoded more concisely with `Option::ok_or`"
-}
-
-declare_lint_pass!(ManualOkOr => [MANUAL_OK_OR]);
-
-impl<'tcx> LateLintPass<'tcx> for ManualOkOr {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) {
-        if in_external_macro(cx.sess(), scrutinee.span) {
-            return;
-        }
-
-        if_chain! {
-            if let ExprKind::MethodCall(method_segment, [receiver, or_expr, map_expr], _) = scrutinee.kind;
-            if method_segment.ident.name == sym!(map_or);
-            let ty = cx.typeck_results().expr_ty(receiver);
-            if is_type_diagnostic_item(cx, ty, sym::Option);
-            if is_ok_wrapping(cx, map_expr);
-            if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind;
-            if is_lang_ctor(cx, err_path, ResultErr);
-            if let Some(method_receiver_snippet) = snippet_opt(cx, receiver.span);
-            if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span);
-            if let Some(indent) = indent_of(cx, scrutinee.span);
-            then {
-                let reindented_err_arg_snippet =
-                    reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4));
-                span_lint_and_sugg(
-                    cx,
-                    MANUAL_OK_OR,
-                    scrutinee.span,
-                    "this pattern reimplements `Option::ok_or`",
-                    "replace with",
-                    format!(
-                        "{}.ok_or({})",
-                        method_receiver_snippet,
-                        reindented_err_arg_snippet
-                    ),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-    }
-}
-
-fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool {
-    if let ExprKind::Path(ref qpath) = map_expr.kind {
-        if is_lang_ctor(cx, qpath, ResultOk) {
-            return true;
-        }
-    }
-    if_chain! {
-        if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind;
-        let body = cx.tcx.hir().body(body);
-        if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind;
-        if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind;
-        if is_lang_ctor(cx, ok_path, ResultOk);
-        then { path_to_local_id(ok_arg, param_id) } else { false }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
new file mode 100644 (file)
index 0000000..a90eaa8
--- /dev/null
@@ -0,0 +1,140 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability::MachineApplicable;
+use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, symbol, Span};
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// let a = "".to_string();
+    /// let b: String = "".into();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let a = String::new();
+    /// let b = String::new();
+    /// ```
+    #[clippy::version = "1.65.0"]
+    pub MANUAL_STRING_NEW,
+    pedantic,
+    "empty String is being created manually"
+}
+declare_lint_pass!(ManualStringNew => [MANUAL_STRING_NEW]);
+
+impl LateLintPass<'_> for ManualStringNew {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if expr.span.from_expansion() {
+            return;
+        }
+
+        let ty = cx.typeck_results().expr_ty(expr);
+        match ty.kind() {
+            ty::Adt(adt_def, _) if adt_def.is_struct() => {
+                if !cx.tcx.is_diagnostic_item(sym::String, adt_def.did()) {
+                    return;
+                }
+            },
+            _ => return,
+        }
+
+        match expr.kind {
+            ExprKind::Call(func, args) => {
+                parse_call(cx, expr.span, func, args);
+            },
+            ExprKind::MethodCall(path_segment, args, _) => {
+                parse_method_call(cx, expr.span, path_segment, args);
+            },
+            _ => (),
+        }
+    }
+}
+
+/// Checks if an expression's kind corresponds to an empty &str.
+fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool {
+    if  let ExprKind::Lit(lit) = expr_kind &&
+        let LitKind::Str(value, _) = lit.node &&
+        value == symbol::kw::Empty
+    {
+        return true;
+    }
+
+    false
+}
+
+fn warn_then_suggest(cx: &LateContext<'_>, span: Span) {
+    span_lint_and_sugg(
+        cx,
+        MANUAL_STRING_NEW,
+        span,
+        "empty String is being created manually",
+        "consider using",
+        "String::new()".into(),
+        MachineApplicable,
+    );
+}
+
+/// Tries to parse an expression as a method call, emitting the warning if necessary.
+fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, args: &[Expr<'_>]) {
+    if args.is_empty() {
+        // When parsing TryFrom::try_from(...).expect(...), we will have more than 1 arg.
+        return;
+    }
+
+    let ident = path_segment.ident.as_str();
+    let method_arg_kind = &args[0].kind;
+    if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) {
+        warn_then_suggest(cx, span);
+    } else if let ExprKind::Call(func, args) = method_arg_kind {
+        // If our first argument is a function call itself, it could be an `unwrap`-like function.
+        // E.g. String::try_from("hello").unwrap(), TryFrom::try_from("").expect("hello"), etc.
+        parse_call(cx, span, func, args);
+    }
+}
+
+/// Tries to parse an expression as a function call, emitting the warning if necessary.
+fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_>]) {
+    if args.len() != 1 {
+        return;
+    }
+
+    let arg_kind = &args[0].kind;
+    if let ExprKind::Path(qpath) = &func.kind {
+        if let QPath::TypeRelative(_, _) = qpath {
+            // String::from(...) or String::try_from(...)
+            if  let QPath::TypeRelative(ty, path_seg) = qpath &&
+                [sym::from, sym::try_from].contains(&path_seg.ident.name) &&
+                let TyKind::Path(qpath) = &ty.kind &&
+                let QPath::Resolved(_, path) = qpath &&
+                let [path_seg] = path.segments &&
+                path_seg.ident.name == sym::String &&
+                is_expr_kind_empty_str(arg_kind)
+            {
+                warn_then_suggest(cx, span);
+            }
+        } else if let QPath::Resolved(_, path) = qpath {
+            // From::from(...) or TryFrom::try_from(...)
+            if  let [path_seg1, path_seg2] = path.segments &&
+                is_expr_kind_empty_str(arg_kind) && (
+                    (path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) ||
+                    (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from)
+                )
+            {
+                warn_then_suggest(cx, span);
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs
deleted file mode 100644 (file)
index 95c312f..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
-use clippy_utils::{is_trait_method, meets_msrv, msrvs, peel_blocks};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::mir::Mutability;
-use rustc_middle::ty;
-use rustc_middle::ty::adjustment::Adjust;
-use rustc_semver::RustcVersion;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::Ident;
-use rustc_span::{sym, Span};
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// let x = vec![42, 43];
-    /// let y = x.iter();
-    /// let z = y.map(|i| *i);
-    /// ```
-    ///
-    /// The correct use would be:
-    ///
-    /// ```rust
-    /// let x = vec![42, 43];
-    /// let y = x.iter();
-    /// let z = y.cloned();
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub MAP_CLONE,
-    style,
-    "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
-}
-
-pub struct MapClone {
-    msrv: Option<RustcVersion>,
-}
-
-impl_lint_pass!(MapClone => [MAP_CLONE]);
-
-impl MapClone {
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
-        Self { msrv }
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for MapClone {
-    fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
-        if e.span.from_expansion() {
-            return;
-        }
-
-        if_chain! {
-            if let hir::ExprKind::MethodCall(method, args, _) = e.kind;
-            if args.len() == 2;
-            if method.ident.name == sym::map;
-            let ty = cx.typeck_results().expr_ty(&args[0]);
-            if is_type_diagnostic_item(cx, ty, sym::Option) || is_trait_method(cx, e, sym::Iterator);
-            if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = args[1].kind;
-            then {
-                let closure_body = cx.tcx.hir().body(body);
-                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::Unannotated, .., name, None
-                    ) = inner.kind {
-                        if ident_eq(name, closure_expr) {
-                            self.lint_explicit_closure(cx, e.span, args[0].span, true);
-                        }
-                    },
-                    hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
-                        match closure_expr.kind {
-                            hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
-                                if ident_eq(name, inner) {
-                                    if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
-                                        self.lint_explicit_closure(cx, e.span, args[0].span, true);
-                                    }
-                                }
-                            },
-                            hir::ExprKind::MethodCall(method, [obj], _) => if_chain! {
-                                if ident_eq(name, obj) && method.ident.name == sym::clone;
-                                if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
-                                if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
-                                if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id);
-                                // no autoderefs
-                                if !cx.typeck_results().expr_adjustments(obj).iter()
-                                    .any(|a| matches!(a.kind, Adjust::Deref(Some(..))));
-                                then {
-                                    let obj_ty = cx.typeck_results().expr_ty(obj);
-                                    if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
-                                        if matches!(mutability, Mutability::Not) {
-                                            let copy = is_copy(cx, *ty);
-                                            self.lint_explicit_closure(cx, e.span, args[0].span, copy);
-                                        }
-                                    } else {
-                                        lint_needless_cloning(cx, e.span, args[0].span);
-                                    }
-                                }
-                            },
-                            _ => {},
-                        }
-                    },
-                    _ => {},
-                }
-            }
-        }
-    }
-
-    extract_msrv_attr!(LateContext);
-}
-
-fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool {
-    if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind {
-        path.segments.len() == 1 && path.segments[0].ident == name
-    } else {
-        false
-    }
-}
-
-fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
-    span_lint_and_sugg(
-        cx,
-        MAP_CLONE,
-        root.trim_start(receiver).unwrap(),
-        "you are needlessly cloning iterator elements",
-        "remove the `map` call",
-        String::new(),
-        Applicability::MachineApplicable,
-    );
-}
-
-impl MapClone {
-    fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) {
-        let mut applicability = Applicability::MachineApplicable;
-
-        let (message, sugg_method) = if is_copy && meets_msrv(self.msrv, msrvs::ITERATOR_COPIED) {
-            ("you are using an explicit closure for copying elements", "copied")
-        } else {
-            ("you are using an explicit closure for cloning elements", "cloned")
-        };
-
-        span_lint_and_sugg(
-            cx,
-            MAP_CLONE,
-            replace,
-            message,
-            &format!("consider calling the dedicated `{}` method", sugg_method),
-            format!(
-                "{}.{}()",
-                snippet_with_applicability(cx, root, "..", &mut applicability),
-                sugg_method,
-            ),
-            applicability,
-        );
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
deleted file mode 100644 (file)
index 1e54244..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// ### 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:
-    /// ```rust
-    /// 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))
-    ///             }
-    ///         })
-    /// }
-    /// ```
-    #[clippy::version = "1.48.0"]
-    pub MAP_ERR_IGNORE,
-    restriction,
-    "`map_err` should not ignore the original error"
-}
-
-declare_lint_pass!(MapErrIgnore => [MAP_ERR_IGNORE]);
-
-impl<'tcx> LateLintPass<'tcx> for MapErrIgnore {
-    // do not try to lint if this is from a macro or desugaring
-    fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
-        if e.span.from_expansion() {
-            return;
-        }
-
-        // check if this is a method call (e.g. x.foo())
-        if let ExprKind::MethodCall(method, [_, arg], _) = e.kind {
-            // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1]
-            // Enum::Variant[2]))
-            if method.ident.name == sym!(map_err) {
-                // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span
-                // fields
-                if let ExprKind::Closure(&Closure {
-                    capture_clause,
-                    body,
-                    fn_decl_span,
-                    ..
-                }) = arg.kind
-                {
-                    // check if this is by Reference (meaning there's no move statement)
-                    if capture_clause == CaptureBy::Ref {
-                        // Get the closure body to check the parameters and values
-                        let closure_body = cx.tcx.hir().body(body);
-                        // make sure there's only one parameter (`|_|`)
-                        if closure_body.params.len() == 1 {
-                            // make sure that parameter is the wild token (`_`)
-                            if let PatKind::Wild = closure_body.params[0].pat.kind {
-                                // span the area of the closure capture and warn that the
-                                // original error will be thrown away
-                                span_lint_and_help(
-                                    cx,
-                                    MAP_ERR_IGNORE,
-                                    fn_decl_span,
-                                    "`map_err(|_|...` wildcard pattern discards the original error",
-                                    None,
-                                    "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
-                                );
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
index 0da4833f1dfe0c9dfc5694874ab0cad257c30487..34cc082687ec20426d6f36ae4c1aa11a4530458a 100644 (file)
@@ -1,10 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_wild;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::span_contains_comment;
 use rustc_ast::{Attribute, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat};
-use rustc_lint::LateContext;
+use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty;
 use rustc_span::source_map::Spanned;
 
@@ -76,6 +77,7 @@ fn find_matches_sugg<'a, 'b, I>(
         >,
 {
     if_chain! {
+        if !span_contains_comment(cx.sess().source_map(), expr.span);
         if iter.len() >= 2;
         if cx.typeck_results().expr_ty(expr).is_bool();
         if let Some((_, last_pat_opt, last_expr, _)) = iter.next_back();
index fa19cddd35ec7afff4258f68eb901967e01b411b..6f037339ec75870552a3d2867f447a012364d143 100644 (file)
@@ -8,7 +8,7 @@
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Node, Pat, PatKind, Path, QPath};
+use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath};
 use rustc_lint::LateContext;
 use rustc_span::sym;
 use rustc_typeck::hir_ty_to_ty;
@@ -65,8 +65,26 @@ pub(crate) fn check_if_let<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'_>, if_let:
 fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>]) -> bool {
     for arm in arms {
         let arm_expr = peel_blocks_with_stmt(arm.body);
+
+        if let Some(guard_expr) = &arm.guard {
+            match guard_expr {
+                // gives up if `pat if expr` can have side effects
+                Guard::If(if_cond) => {
+                    if if_cond.can_have_side_effects() {
+                        return false;
+                    }
+                },
+                // gives up `pat if let ...` arm
+                Guard::IfLet(_) => {
+                    return false;
+                },
+            };
+        }
+
         if let PatKind::Wild = arm.pat.kind {
-            return eq_expr_value(cx, match_expr, strip_return(arm_expr));
+            if !eq_expr_value(cx, match_expr, strip_return(arm_expr)) {
+                return false;
+            }
         } else if !pat_same_as_expr(arm.pat, arm_expr) {
             return false;
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
new file mode 100644 (file)
index 0000000..6a7c63d
--- /dev/null
@@ -0,0 +1,70 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::match_type;
+use clippy_utils::visitors::is_local_used;
+use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, UintTy};
+use rustc_span::sym;
+
+use super::NAIVE_BYTECOUNT;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    filter_recv: &'tcx Expr<'_>,
+    filter_arg: &'tcx Expr<'_>,
+) {
+    if_chain! {
+        if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind;
+        let body = cx.tcx.hir().body(body);
+        if let [param] = body.params;
+        if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
+        if let ExprKind::Binary(ref op, l, r) = body.value.kind;
+        if op.node == BinOpKind::Eq;
+        if match_type(cx,
+                    cx.typeck_results().expr_ty(filter_recv).peel_refs(),
+                    &paths::SLICE_ITER);
+        let operand_is_arg = |expr| {
+            let expr = peel_ref_operators(cx, peel_blocks(expr));
+            path_to_local_id(expr, arg_id)
+        };
+        let needle = if operand_is_arg(l) {
+            r
+        } else if operand_is_arg(r) {
+            l
+        } else {
+            return;
+        };
+        if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
+        if !is_local_used(cx, needle, arg_id);
+        then {
+            let haystack = if let ExprKind::MethodCall(path, args, _) =
+                    filter_recv.kind {
+                let p = path.ident.name;
+                if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
+                    &args[0]
+                } else {
+                    filter_recv
+                }
+            } else {
+                filter_recv
+            };
+            let mut applicability = Applicability::MaybeIncorrect;
+            span_lint_and_sugg(
+                cx,
+                NAIVE_BYTECOUNT,
+                expr.span,
+                "you appear to be counting bytes the naive way",
+                "consider using the bytecount crate",
+                format!("bytecount::count({}, {})",
+                        snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
+                        snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
+                applicability,
+            );
+        }
+    };
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
new file mode 100644 (file)
index 0000000..fcfc25b
--- /dev/null
@@ -0,0 +1,37 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::BYTES_COUNT_TO_LEN;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    count_recv: &'tcx hir::Expr<'_>,
+    bytes_recv: &'tcx hir::Expr<'_>,
+) {
+    if_chain! {
+        if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id);
+        if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id);
+        if cx.tcx.type_of(impl_id).is_str();
+        let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs();
+        if ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String);
+        then {
+            let mut applicability = Applicability::MachineApplicable;
+            span_lint_and_sugg(
+                cx,
+                BYTES_COUNT_TO_LEN,
+                expr.span,
+                "using long and hard to read `.bytes().count()`",
+                "consider calling `.len()` instead",
+                format!("{}.len()", snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)),
+                applicability
+            );
+        }
+    };
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
new file mode 100644 (file)
index 0000000..b3c2c7c
--- /dev/null
@@ -0,0 +1,41 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::{source_map::Spanned, symbol::sym, Span};
+
+use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    call_span: Span,
+    recv: &'tcx Expr<'_>,
+    arg: &'tcx Expr<'_>,
+) {
+    if_chain! {
+        if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+        if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+        if cx.tcx.type_of(impl_id).is_str();
+        if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind;
+        if (2..=6).contains(&ext_literal.as_str().len());
+        let ext_str = ext_literal.as_str();
+        if ext_str.starts_with('.');
+        if ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit())
+            || ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit());
+        let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs();
+        if recv_ty.is_str() || is_type_diagnostic_item(cx, recv_ty, sym::String);
+        then {
+            span_lint_and_help(
+                cx,
+                CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+                call_span,
+                "case-sensitive file extension comparison",
+                None,
+                "consider using a case-insensitive comparison instead",
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
new file mode 100644 (file)
index 0000000..561033b
--- /dev/null
@@ -0,0 +1,96 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{eq_expr_value, get_parent_expr};
+use core::ops::ControlFlow;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use std::collections::VecDeque;
+
+use super::method_call;
+use super::COLLAPSIBLE_STR_REPLACE;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    from: &'tcx hir::Expr<'tcx>,
+    to: &'tcx hir::Expr<'tcx>,
+) {
+    let replace_methods = collect_replace_calls(cx, expr, to);
+    if replace_methods.methods.len() > 1 {
+        let from_kind = cx.typeck_results().expr_ty(from).peel_refs().kind();
+        // If the parent node's `to` argument is the same as the `to` argument
+        // of the last replace call in the current chain, don't lint as it was already linted
+        if let Some(parent) = get_parent_expr(cx, expr)
+            && let Some(("replace", [_, current_from, current_to], _)) = method_call(parent)
+            && eq_expr_value(cx, to, current_to)
+            && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
+        {
+            return;
+        }
+
+        check_consecutive_replace_calls(cx, expr, &replace_methods, to);
+    }
+}
+
+struct ReplaceMethods<'tcx> {
+    methods: VecDeque<&'tcx hir::Expr<'tcx>>,
+    from_args: VecDeque<&'tcx hir::Expr<'tcx>>,
+}
+
+fn collect_replace_calls<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    to_arg: &'tcx hir::Expr<'tcx>,
+) -> ReplaceMethods<'tcx> {
+    let mut methods = VecDeque::new();
+    let mut from_args = VecDeque::new();
+
+    let _: Option<()> = for_each_expr(expr, |e| {
+        if let Some(("replace", [_, from, to], _)) = method_call(e) {
+            if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
+                methods.push_front(e);
+                from_args.push_front(from);
+                ControlFlow::Continue(())
+            } else {
+                ControlFlow::BREAK
+            }
+        } else {
+            ControlFlow::Continue(())
+        }
+    });
+
+    ReplaceMethods { methods, from_args }
+}
+
+/// Check a chain of `str::replace` calls for `collapsible_str_replace` lint.
+fn check_consecutive_replace_calls<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    replace_methods: &ReplaceMethods<'tcx>,
+    to_arg: &'tcx hir::Expr<'tcx>,
+) {
+    let from_args = &replace_methods.from_args;
+    let from_arg_reprs: Vec<String> = from_args
+        .iter()
+        .map(|from_arg| snippet(cx, from_arg.span, "..").to_string())
+        .collect();
+    let app = Applicability::MachineApplicable;
+    let earliest_replace_call = replace_methods.methods.front().unwrap();
+    if let Some((_, [..], span_lo)) = method_call(earliest_replace_call) {
+        span_lint_and_sugg(
+            cx,
+            COLLAPSIBLE_STR_REPLACE,
+            expr.span.with_lo(span_lo.lo()),
+            "used consecutive `str::replace` call",
+            "replace with",
+            format!(
+                "replace([{}], {})",
+                from_arg_reprs.join(", "),
+                snippet(cx, to_arg.span, ".."),
+            ),
+            app,
+        );
+    }
+}
index 5ef08ca6290bae6adbc15a6887edbd755c040711..d59fefa1ddc0ebf68104498532f8da1f1c8c0e26 100644 (file)
@@ -7,18 +7,26 @@
 
 use super::EXPECT_USED;
 
-/// lint use of `expect()` for `Option`s and `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_expect_in_tests: bool) {
+/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`.
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    recv: &hir::Expr<'_>,
+    is_err: bool,
+    allow_expect_in_tests: bool,
+) {
     let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
-    let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
+    let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
         Some((EXPECT_USED, "an Option", "None", ""))
     } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
-        Some((EXPECT_USED, "a Result", "Err", "an "))
+        Some((EXPECT_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
     } else {
         None
     };
 
+    let method = if is_err { "expect_err" } else { "expect" };
+
     if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
         return;
     }
@@ -28,7 +36,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
             cx,
             lint,
             expr.span,
-            &format!("used `expect()` on `{kind}` value"),
+            &format!("used `{method}()` on `{kind}` value"),
             None,
             &format!("if this value is {none_prefix}`{none_value}`, it will panic"),
         );
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
new file mode 100644 (file)
index 0000000..4de77de
--- /dev/null
@@ -0,0 +1,39 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_slice_of_primitives;
+use clippy_utils::source::snippet_with_applicability;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+
+use super::GET_FIRST;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'_>,
+    arg: &'tcx hir::Expr<'_>,
+) {
+    if_chain! {
+        if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+        if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+        if cx.tcx.type_of(impl_id).is_slice();
+        if let Some(_) = is_slice_of_primitives(cx, recv);
+        if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind;
+        then {
+            let mut app = Applicability::MachineApplicable;
+            let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
+            span_lint_and_sugg(
+                cx,
+                GET_FIRST,
+                expr.span,
+                &format!("accessing first element with `{0}.get(0)`", slice_name),
+                "try",
+                format!("{}.first()", slice_name),
+                app,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
new file mode 100644 (file)
index 0000000..cea7b0d
--- /dev/null
@@ -0,0 +1,107 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::{get_expr_use_or_unification_node, is_lang_ctor, is_no_std_crate};
+
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::{OptionNone, OptionSome};
+use rustc_hir::{Expr, ExprKind, Node};
+use rustc_lint::LateContext;
+
+use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS};
+
+enum IterType {
+    Iter,
+    IterMut,
+    IntoIter,
+}
+
+impl IterType {
+    fn ref_prefix(&self) -> &'static str {
+        match self {
+            Self::Iter => "&",
+            Self::IterMut => "&mut ",
+            Self::IntoIter => "",
+        }
+    }
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) {
+    let item = match &recv.kind {
+        ExprKind::Array(v) if v.len() <= 1 => v.first(),
+        ExprKind::Path(p) => {
+            if is_lang_ctor(cx, p, OptionNone) {
+                None
+            } else {
+                return;
+            }
+        },
+        ExprKind::Call(f, some_args) if some_args.len() == 1 => {
+            if let ExprKind::Path(p) = &f.kind {
+                if is_lang_ctor(cx, p, OptionSome) {
+                    Some(&some_args[0])
+                } else {
+                    return;
+                }
+            } else {
+                return;
+            }
+        },
+        _ => return,
+    };
+    let iter_type = match method_name {
+        "iter" => IterType::Iter,
+        "iter_mut" => IterType::IterMut,
+        "into_iter" => IterType::IntoIter,
+        _ => return,
+    };
+
+    let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) {
+        Some((Node::Expr(parent), child_id)) => match parent.kind {
+            ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false,
+            ExprKind::If(_, _, _)
+            | ExprKind::Match(_, _, _)
+            | ExprKind::Closure(_)
+            | ExprKind::Ret(_)
+            | ExprKind::Break(_, _) => true,
+            _ => false,
+        },
+        Some((Node::Stmt(_) | Node::Local(_), _)) => false,
+        _ => true,
+    };
+
+    if is_unified {
+        return;
+    }
+
+    if let Some(i) = item {
+        let sugg = format!(
+            "{}::iter::once({}{})",
+            if is_no_std_crate(cx) { "core" } else { "std" },
+            iter_type.ref_prefix(),
+            snippet(cx, i.span, "...")
+        );
+        span_lint_and_sugg(
+            cx,
+            ITER_ON_SINGLE_ITEMS,
+            expr.span,
+            &format!("`{method_name}` call on a collection with only one item"),
+            "try",
+            sugg,
+            Applicability::MaybeIncorrect,
+        );
+    } else {
+        span_lint_and_sugg(
+            cx,
+            ITER_ON_EMPTY_COLLECTIONS,
+            expr.span,
+            &format!("`{method_name}` call on an empty collection"),
+            "try",
+            if is_no_std_crate(cx) {
+                "core::iter::empty()".to_string()
+            } else {
+                "std::iter::empty()".to_string()
+            },
+            Applicability::MaybeIncorrect,
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
new file mode 100644 (file)
index 0000000..ffd2f4a
--- /dev/null
@@ -0,0 +1,64 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_lang_ctor, path_to_local_id};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::{ResultErr, ResultOk};
+use rustc_hir::{Closure, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+
+use super::MANUAL_OK_OR;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    recv: &'tcx Expr<'_>,
+    or_expr: &'tcx Expr<'_>,
+    map_expr: &'tcx Expr<'_>,
+) {
+    if_chain! {
+        if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+        if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+        if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Option);
+        if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, [err_arg]) = or_expr.kind;
+        if is_lang_ctor(cx, err_path, ResultErr);
+        if is_ok_wrapping(cx, map_expr);
+        if let Some(recv_snippet) = snippet_opt(cx, recv.span);
+        if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span);
+        if let Some(indent) = indent_of(cx, expr.span);
+        then {
+            let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4));
+            span_lint_and_sugg(
+                cx,
+                MANUAL_OK_OR,
+                expr.span,
+                "this pattern reimplements `Option::ok_or`",
+                "replace with",
+                format!(
+                    "{}.ok_or({})",
+                    recv_snippet,
+                    reindented_err_arg_snippet
+                ),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
+
+fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool {
+    if let ExprKind::Path(ref qpath) = map_expr.kind {
+        if is_lang_ctor(cx, qpath, ResultOk) {
+            return true;
+        }
+    }
+    if_chain! {
+        if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind;
+        let body = cx.tcx.hir().body(body);
+        if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind;
+        if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind;
+        if is_lang_ctor(cx, ok_path, ResultOk);
+        then { path_to_local_id(ok_arg, param_id) } else { false }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
new file mode 100644 (file)
index 0000000..ffedda9
--- /dev/null
@@ -0,0 +1,122 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
+use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs, peel_blocks};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::mir::Mutability;
+use rustc_middle::ty;
+use rustc_middle::ty::adjustment::Adjust;
+use rustc_semver::RustcVersion;
+use rustc_span::symbol::Ident;
+use rustc_span::{sym, Span};
+
+use super::MAP_CLONE;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'_>,
+    e: &hir::Expr<'_>,
+    recv: &hir::Expr<'_>,
+    arg: &'tcx hir::Expr<'_>,
+    msrv: Option<RustcVersion>,
+) {
+    if_chain! {
+        if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id);
+        if cx.tcx.impl_of_method(method_id)
+            .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id), sym::Option))
+            || is_diag_trait_item(cx, method_id, sym::Iterator);
+        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);
+            match closure_body.params[0].pat.kind {
+                hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
+                    hir::BindingAnnotation::Unannotated, .., name, None
+                ) = inner.kind {
+                    if ident_eq(name, closure_expr) {
+                        lint_explicit_closure(cx, e.span, recv.span, true, msrv);
+                    }
+                },
+                hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
+                    match closure_expr.kind {
+                        hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
+                            if ident_eq(name, inner) {
+                                if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
+                                    lint_explicit_closure(cx, e.span, recv.span, true, msrv);
+                                }
+                            }
+                        },
+                        hir::ExprKind::MethodCall(method, [obj], _) => if_chain! {
+                            if ident_eq(name, obj) && method.ident.name == sym::clone;
+                            if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
+                            if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
+                            if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id);
+                            // no autoderefs
+                            if !cx.typeck_results().expr_adjustments(obj).iter()
+                                .any(|a| matches!(a.kind, Adjust::Deref(Some(..))));
+                            then {
+                                let obj_ty = cx.typeck_results().expr_ty(obj);
+                                if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
+                                    if matches!(mutability, Mutability::Not) {
+                                        let copy = is_copy(cx, *ty);
+                                        lint_explicit_closure(cx, e.span, recv.span, copy, msrv);
+                                    }
+                                } else {
+                                    lint_needless_cloning(cx, e.span, recv.span);
+                                }
+                            }
+                        },
+                        _ => {},
+                    }
+                },
+                _ => {},
+            }
+        }
+    }
+}
+
+fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool {
+    if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind {
+        path.segments.len() == 1 && path.segments[0].ident == name
+    } else {
+        false
+    }
+}
+
+fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
+    span_lint_and_sugg(
+        cx,
+        MAP_CLONE,
+        root.trim_start(receiver).unwrap(),
+        "you are needlessly cloning iterator elements",
+        "remove the `map` call",
+        String::new(),
+        Applicability::MachineApplicable,
+    );
+}
+
+fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: Option<RustcVersion>) {
+    let mut applicability = Applicability::MachineApplicable;
+
+    let (message, sugg_method) = if is_copy && meets_msrv(msrv, msrvs::ITERATOR_COPIED) {
+        ("you are using an explicit closure for copying elements", "copied")
+    } else {
+        ("you are using an explicit closure for cloning elements", "cloned")
+    };
+
+    span_lint_and_sugg(
+        cx,
+        MAP_CLONE,
+        replace,
+        message,
+        &format!("consider calling the dedicated `{}` method", sugg_method),
+        format!(
+            "{}.{}()",
+            snippet_with_applicability(cx, root, "..", &mut applicability),
+            sugg_method,
+        ),
+        applicability,
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
new file mode 100644 (file)
index 0000000..1fb6617
--- /dev/null
@@ -0,0 +1,34 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::MAP_ERR_IGNORE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'_>, e: &Expr<'_>, arg: &'tcx Expr<'_>) {
+    if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+        && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+        && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Result)
+        && let ExprKind::Closure(&Closure {
+            capture_clause: CaptureBy::Ref,
+            body,
+            fn_decl_span,
+            ..
+        }) = arg.kind
+        && let closure_body = cx.tcx.hir().body(body)
+        && let [param] = closure_body.params
+        && let PatKind::Wild = param.pat.kind
+    {
+        // span the area of the closure capture and warn that the
+        // original error will be thrown away
+        span_lint_and_help(
+            cx,
+            MAP_ERR_IGNORE,
+            fn_decl_span,
+            "`map_err(|_|...` wildcard pattern discards the original error",
+            None,
+            "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
+        );
+    }
+}
index 5ac6b09f0aa27bff22fa87c05292791f0a13f1b0..a0d190a58aff9a7f10478600f0d8ddab1b3b2840 100644 (file)
@@ -1,5 +1,8 @@
 mod bind_instead_of_map;
+mod bytecount;
+mod bytes_count_to_len;
 mod bytes_nth;
+mod case_sensitive_file_extension_comparisons;
 mod chars_cmp;
 mod chars_cmp_with_unwrap;
 mod chars_last_cmp;
@@ -9,6 +12,7 @@
 mod clone_on_copy;
 mod clone_on_ref_ptr;
 mod cloned_instead_of_copied;
+mod collapsible_str_replace;
 mod err_expect;
 mod expect_fun_call;
 mod expect_used;
@@ -21,6 +25,7 @@
 mod flat_map_identity;
 mod flat_map_option;
 mod from_iter_instead_of_collect;
+mod get_first;
 mod get_last_with_len;
 mod get_unwrap;
 mod implicit_clone;
 mod iter_next_slice;
 mod iter_nth;
 mod iter_nth_zero;
+mod iter_on_single_or_empty_collections;
 mod iter_overeager_cloned;
 mod iter_skip_next;
 mod iter_with_drain;
 mod iterator_step_by_zero;
+mod manual_ok_or;
 mod manual_saturating_arithmetic;
 mod manual_str_repeat;
+mod map_clone;
 mod map_collect_result_unit;
+mod map_err_ignore;
 mod map_flatten;
 mod map_identity;
 mod map_unwrap_or;
+mod mut_mutex_lock;
 mod needless_option_as_deref;
 mod needless_option_take;
 mod no_effect_replace;
 mod obfuscated_if_else;
 mod ok_expect;
+mod open_options;
 mod option_as_ref_deref;
 mod option_map_or_none;
 mod option_map_unwrap_or;
 mod or_fun_call;
 mod or_then_unwrap;
+mod path_buf_push_overwrite;
+mod range_zip_with_len;
+mod repeat_once;
 mod search_is_some;
 mod single_char_add_str;
 mod single_char_insert_string;
 mod single_char_pattern;
 mod single_char_push_string;
 mod skip_while_next;
+mod stable_sort_primitive;
 mod str_splitn;
 mod string_extend_chars;
 mod suspicious_map;
 mod suspicious_splitn;
+mod suspicious_to_owned;
 mod uninit_assumed_init;
+mod unit_hash;
 mod unnecessary_filter_map;
 mod unnecessary_fold;
 mod unnecessary_iter_cloned;
 mod unnecessary_join;
 mod unnecessary_lazy_eval;
+mod unnecessary_sort_by;
 mod unnecessary_to_owned;
 mod unwrap_or_else_default;
 mod unwrap_used;
 mod useless_asref;
 mod utils;
+mod vec_resize_to_zero;
+mod verbose_file_reads;
 mod wrong_self_convention;
 mod zst_offset;
 
 use bind_instead_of_map::BindInsteadOfMap;
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
+use clippy_utils::ty::{contains_adt_constructor, implements_trait, is_copy, is_type_diagnostic_item};
+use clippy_utils::{
+    contains_return, get_trait_def_id, is_trait_method, iter_input_pats, meets_msrv, msrvs, paths, return_ty,
+};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
     "used `cloned` where `copied` could be used instead"
 }
 
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// let hello = "hesuo worpd"
+    ///     .replace('s', "l")
+    ///     .replace("u", "l")
+    ///     .replace('p', "l");
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l");
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub COLLAPSIBLE_STR_REPLACE,
+    perf,
+    "collapse consecutive calls to str::replace (2 or more) into a single call"
+}
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for usage of `_.cloned().<func>()` where call to `.cloned()` can be postponed.
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `.unwrap()` calls on `Option`s and on `Result`s.
+    /// 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,
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `.expect()` calls on `Option`s and `Result`s.
+    /// 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.
     "replace `.iter().count()` with `.len()`"
 }
 
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// # use std::borrow::Cow;
+    /// let s = "Hello world!";
+    /// let cow = Cow::Borrowed(s);
+    ///
+    /// let data = cow.to_owned();
+    /// assert!(matches!(data, Cow::Borrowed(_)))
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::borrow::Cow;
+    /// let s = "Hello world!";
+    /// let cow = Cow::Borrowed(s);
+    ///
+    /// let data = cow.clone();
+    /// assert!(matches!(data, Cow::Borrowed(_)))
+    /// ```
+    /// or
+    /// ```rust
+    /// # use std::borrow::Cow;
+    /// let s = "Hello world!";
+    /// let cow = Cow::Borrowed(s);
+    ///
+    /// let data = cow.into_owned();
+    /// assert!(matches!(data, String))
+    /// ```
+    #[clippy::version = "1.65.0"]
+    pub SUSPICIOUS_TO_OWNED,
+    suspicious,
+    "calls to `to_owned` on a `Cow<'_, _>` might not do what they are expected"
+}
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for calls to [`splitn`]
     /// "1234".replace("12", "12");
     /// "1234".replacen("12", "12", 1);
     /// ```
-    #[clippy::version = "1.62.0"]
+    #[clippy::version = "1.63.0"]
     pub NO_EFFECT_REPLACE,
     suspicious,
     "replace with no effect"
     more clearly with `if .. else ..`"
 }
 
+declare_clippy_lint! {
+    /// ### 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
+    ///
+    /// ```rust
+    /// let a = [123].iter();
+    /// let b = Some(123).into_iter();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// 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
+    #[clippy::version = "1.64.0"]
+    pub ITER_ON_SINGLE_ITEMS,
+    nursery,
+    "Iterator for array of length 1"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    ///
+    /// ```rust
+    /// use std::{slice, option};
+    /// let a: slice::Iter<i32> = [].iter();
+    /// let f: option::IntoIter<i32> = None.into_iter();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// 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
+    #[clippy::version = "1.64.0"]
+    pub ITER_ON_EMPTY_COLLECTIONS,
+    nursery,
+    "Iterator for empty array"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// # let vec = vec![1_u8];
+    /// let count = vec.iter().filter(|x| **x == 0u8).count();
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// # let vec = vec![1_u8];
+    /// let count = bytecount::count(&vec, 0u8);
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub NAIVE_BYTECOUNT,
+    pedantic,
+    "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// "hello".bytes().count();
+    /// String::from("hello").bytes().count();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// "hello".len();
+    /// String::from("hello").len();
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub BYTES_COUNT_TO_LEN,
+    complexity,
+    "Using `bytes().count()` when `len()` performs the same functionality"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// fn is_rust_file(filename: &str) -> bool {
+    ///     filename.ends_with(".rs")
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// 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"))
+    /// }
+    /// ```
+    #[clippy::version = "1.51.0"]
+    pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+    pedantic,
+    "Checks for calls to ends_with with case-sensitive file extensions"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// let x = vec![2, 3, 5];
+    /// let first_element = x.get(0);
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// let x = vec![2, 3, 5];
+    /// let first_element = x.first();
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub GET_FIRST,
+    style,
+    "Using `x.get(0)` when `x.first()` is simpler"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Finds patterns that reimplement `Option::ok_or`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Concise code helps focusing on behavior instead of boilerplate.
+    ///
+    /// ### Examples
+    /// ```rust
+    /// let foo: Option<i32> = None;
+    /// foo.map_or(Err("error"), |v| Ok(v));
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// let foo: Option<i32> = None;
+    /// foo.ok_or("error");
+    /// ```
+    #[clippy::version = "1.49.0"]
+    pub MANUAL_OK_OR,
+    pedantic,
+    "finds patterns that can be encoded more concisely with `Option::ok_or`"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// let x = vec![42, 43];
+    /// let y = x.iter();
+    /// let z = y.map(|i| *i);
+    /// ```
+    ///
+    /// The correct use would be:
+    ///
+    /// ```rust
+    /// let x = vec![42, 43];
+    /// let y = x.iter();
+    /// let z = y.cloned();
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub MAP_CLONE,
+    style,
+    "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
+}
+
+declare_clippy_lint! {
+    /// ### 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:
+    /// ```rust
+    /// 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))
+    ///             }
+    ///         })
+    /// }
+    /// ```
+    #[clippy::version = "1.48.0"]
+    pub MAP_ERR_IGNORE,
+    restriction,
+    "`map_err` should not ignore the original error"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// 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:
+    /// ```rust
+    /// 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;
+    /// ```
+    #[clippy::version = "1.49.0"]
+    pub MUT_MUTEX_LOCK,
+    style,
+    "`&mut Mutex::lock` does unnecessary locking"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// use std::fs::OpenOptions;
+    ///
+    /// OpenOptions::new().read(true).truncate(true);
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub NONSENSICAL_OPEN_OPTIONS,
+    correctness,
+    "nonsensical combination of options for opening a file"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// use std::path::PathBuf;
+    ///
+    /// let mut x = PathBuf::from("/foo");
+    /// x.push("/bar");
+    /// assert_eq!(x, PathBuf::from("/bar"));
+    /// ```
+    /// Could be written:
+    ///
+    /// ```rust
+    /// use std::path::PathBuf;
+    ///
+    /// let mut x = PathBuf::from("/foo");
+    /// x.push("bar");
+    /// assert_eq!(x, PathBuf::from("/foo/bar"));
+    /// ```
+    #[clippy::version = "1.36.0"]
+    pub PATH_BUF_PUSH_OVERWRITE,
+    nursery,
+    "calling `push` with file system root on `PathBuf` can overwrite it"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// # let x = vec![1];
+    /// let _ = x.iter().zip(0..x.len());
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// # let x = vec![1];
+    /// let _ = x.iter().enumerate();
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub RANGE_ZIP_WITH_LEN,
+    complexity,
+    "zipping iterator with a range when `enumerate()` would do"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// fn main() {
+    ///     let x = String::from("hello world").repeat(1);
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn main() {
+    ///     let x = String::from("hello world").clone();
+    /// }
+    /// ```
+    #[clippy::version = "1.47.0"]
+    pub REPEAT_ONCE,
+    complexity,
+    "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// let mut vec = vec![2, 1, 3];
+    /// vec.sort();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let mut vec = vec![2, 1, 3];
+    /// vec.sort_unstable();
+    /// ```
+    #[clippy::version = "1.47.0"]
+    pub STABLE_SORT_PRIMITIVE,
+    pedantic,
+    "use of sort() when sort_unstable() is equivalent"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// # use std::hash::Hash;
+    /// # use std::collections::hash_map::DefaultHasher;
+    /// # enum Foo { Empty, WithValue(u8) }
+    /// # use Foo::*;
+    /// # let mut state = DefaultHasher::new();
+    /// # let my_enum = Foo::Empty;
+    /// match my_enum {
+    ///        Empty => ().hash(&mut state),
+    ///        WithValue(x) => x.hash(&mut state),
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::hash::Hash;
+    /// # use std::collections::hash_map::DefaultHasher;
+    /// # enum Foo { Empty, WithValue(u8) }
+    /// # use Foo::*;
+    /// # let mut state = DefaultHasher::new();
+    /// # let my_enum = Foo::Empty;
+    /// match my_enum {
+    ///        Empty => 0_u8.hash(&mut state),
+    ///        WithValue(x) => x.hash(&mut state),
+    /// }
+    /// ```
+    #[clippy::version = "1.58.0"]
+    pub UNIT_HASH,
+    correctness,
+    "hashing a unit value, which does nothing"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// # struct A;
+    /// # impl A { fn foo(&self) {} }
+    /// # let mut vec: Vec<A> = Vec::new();
+    /// vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # struct A;
+    /// # impl A { fn foo(&self) {} }
+    /// # let mut vec: Vec<A> = Vec::new();
+    /// vec.sort_by_key(|a| a.foo());
+    /// ```
+    #[clippy::version = "1.46.0"]
+    pub UNNECESSARY_SORT_BY,
+    complexity,
+    "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Finds occurrences of `Vec::resize(0, an_int)`
+    ///
+    /// ### Why is this bad?
+    /// This is probably an argument inversion mistake.
+    ///
+    /// ### Example
+    /// ```rust
+    /// vec!(1, 2, 3, 4, 5).resize(0, 5)
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// vec!(1, 2, 3, 4, 5).clear()
+    /// ```
+    #[clippy::version = "1.46.0"]
+    pub VEC_RESIZE_TO_ZERO,
+    correctness,
+    "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake"
+}
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust,no_run
+    /// # use std::io::Read;
+    /// # use std::fs::File;
+    /// 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
+    /// ```rust,no_run
+    /// # use std::fs;
+    /// let mut bytes = fs::read("foo.txt").unwrap();
+    /// ```
+    #[clippy::version = "1.44.0"]
+    pub VERBOSE_FILE_READS,
+    restriction,
+    "use of `File::read_to_end` or `File::read_to_string`"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Option<RustcVersion>,
@@ -2347,6 +3078,7 @@ pub fn new(
     CLONE_ON_COPY,
     CLONE_ON_REF_PTR,
     CLONE_DOUBLE_REF,
+    COLLAPSIBLE_STR_REPLACE,
     ITER_OVEREAGER_CLONED,
     CLONED_INSTEAD_OF_COPIED,
     FLAT_MAP_OPTION,
@@ -2393,6 +3125,7 @@ pub fn new(
     FROM_ITER_INSTEAD_OF_COLLECT,
     INSPECT_FOR_EACH,
     IMPLICIT_CLONE,
+    SUSPICIOUS_TO_OWNED,
     SUSPICIOUS_SPLITN,
     MANUAL_STR_REPEAT,
     EXTEND_WITH_DRAIN,
@@ -2406,6 +3139,25 @@ pub fn new(
     NEEDLESS_OPTION_TAKE,
     NO_EFFECT_REPLACE,
     OBFUSCATED_IF_ELSE,
+    ITER_ON_SINGLE_ITEMS,
+    ITER_ON_EMPTY_COLLECTIONS,
+    NAIVE_BYTECOUNT,
+    BYTES_COUNT_TO_LEN,
+    CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+    GET_FIRST,
+    MANUAL_OK_OR,
+    MAP_CLONE,
+    MAP_ERR_IGNORE,
+    MUT_MUTEX_LOCK,
+    NONSENSICAL_OPEN_OPTIONS,
+    PATH_BUF_PUSH_OVERWRITE,
+    RANGE_ZIP_WITH_LEN,
+    REPEAT_ONCE,
+    STABLE_SORT_PRIMITIVE,
+    UNIT_HASH,
+    UNNECESSARY_SORT_BY,
+    VEC_RESIZE_TO_ZERO,
+    VERBOSE_FILE_READS,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -2541,7 +3293,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
                 if contains_adt_constructor(ret_ty, self_adt) {
                     return;
                 }
-            } else if contains_ty(ret_ty, self_ty) {
+            } else if ret_ty.contains(self_ty) {
                 return;
             }
 
@@ -2559,7 +3311,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
                             if contains_adt_constructor(assoc_ty, self_adt) {
                                 return;
                             }
-                        } else if contains_ty(assoc_ty, self_ty) {
+                        } else if assoc_ty.contains(self_ty) {
                             return;
                         }
                     }
@@ -2608,7 +3360,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
             if let TraitItemKind::Fn(_, _) = item.kind;
             let ret_ty = return_ty(cx, item.hir_id());
             let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder();
-            if !contains_ty(ret_ty, self_ty);
+            if !ret_ty.contains(self_ty);
 
             then {
                 span_lint(
@@ -2660,22 +3412,30 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     },
                     _ => {},
                 },
-                ("count", []) => match method_call(recv) {
+                ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
                     Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
                     Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
                         iter_count::check(cx, expr, recv2, name2);
                     },
                     Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
+                    Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg),
+                    Some(("bytes", [recv2], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
                     _ => {},
                 },
                 ("drain", [arg]) => {
                     iter_with_drain::check(cx, expr, recv, span, arg);
                 },
+                ("ends_with", [arg]) => {
+                    if let ExprKind::MethodCall(_, _, span) = expr.kind {
+                        case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
+                    }
+                },
                 ("expect", [_]) => match method_call(recv) {
                     Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
                     Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
-                    _ => expect_used::check(cx, expr, recv, self.allow_expect_in_tests),
+                    _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
                 },
+                ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
                 ("extend", [arg]) => {
                     string_extend_chars::check(cx, expr, recv, arg);
                     extend_with_drain::check(cx, expr, recv, arg);
@@ -2702,12 +3462,21 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         inspect_for_each::check(cx, expr, span2);
                     }
                 },
-                ("get", [arg]) => get_last_with_len::check(cx, expr, recv, arg),
+                ("get", [arg]) => {
+                    get_first::check(cx, expr, recv, arg);
+                    get_last_with_len::check(cx, expr, recv, arg);
+                },
                 ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
+                ("hash", [arg]) => {
+                    unit_hash::check(cx, expr, recv, arg);
+                },
                 ("is_file", []) => filetype_is_file::check(cx, expr, recv),
                 ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
                 ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
                 ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
+                ("iter" | "iter_mut" | "into_iter", []) => {
+                    iter_on_single_or_empty_collections::check(cx, expr, name, recv);
+                },
                 ("join", [join_arg]) => {
                     if let Some(("collect", _, span)) = method_call(recv) {
                         unnecessary_join::check(cx, expr, recv, join_arg, span);
@@ -2720,7 +3489,15 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         }
                     }
                 },
+                ("lock", []) => {
+                    mut_mutex_lock::check(cx, expr, recv, span);
+                },
                 (name @ ("map" | "map_err"), [m_arg]) => {
+                    if name == "map" {
+                        map_clone::check(cx, expr, recv, m_arg, self.msrv);
+                    } else {
+                        map_err_ignore::check(cx, expr, m_arg);
+                    }
                     if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
                         match (name, args) {
                             ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
@@ -2736,7 +3513,10 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     }
                     map_identity::check(cx, expr, recv, m_arg, name, span);
                 },
-                ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
+                ("map_or", [def, map]) => {
+                    option_map_or_none::check(cx, expr, recv, def, map);
+                    manual_ok_or::check(cx, expr, recv, def, map);
+                },
                 ("next", []) => {
                     if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
                         match (name2, args2) {
@@ -2758,11 +3538,46 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     _ => iter_nth_zero::check(cx, expr, recv, n_arg),
                 },
                 ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
+                ("open", [_]) => {
+                    open_options::check(cx, expr, recv);
+                },
                 ("or_else", [arg]) => {
                     if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
                         unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
                     }
                 },
+                ("push", [arg]) => {
+                    path_buf_push_overwrite::check(cx, expr, arg);
+                },
+                ("read_to_end", [_]) => {
+                    verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG);
+                },
+                ("read_to_string", [_]) => {
+                    verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG);
+                },
+                ("repeat", [arg]) => {
+                    repeat_once::check(cx, expr, recv, arg);
+                },
+                (name @ ("replace" | "replacen"), [arg1, arg2] | [arg1, arg2, _]) => {
+                    no_effect_replace::check(cx, expr, arg1, arg2);
+
+                    // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint
+                    if name == "replace" && let Some(("replace", ..)) = method_call(recv) {
+                        collapsible_str_replace::check(cx, expr, arg1, arg2);
+                    }
+                },
+                ("resize", [count_arg, default_arg]) => {
+                    vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
+                },
+                ("sort", []) => {
+                    stable_sort_primitive::check(cx, expr, recv);
+                },
+                ("sort_by", [arg]) => {
+                    unnecessary_sort_by::check(cx, expr, recv, arg, false);
+                },
+                ("sort_unstable_by", [arg]) => {
+                    unnecessary_sort_by::check(cx, expr, recv, arg, true);
+                },
                 ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
                     if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
@@ -2789,7 +3604,12 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     }
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
                 },
-                ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
+                ("to_owned", []) => {
+                    if !suspicious_to_owned::check(cx, expr, recv) {
+                        implicit_clone::check(cx, name, expr, recv);
+                    }
+                },
+                ("to_os_string" | "to_path_buf" | "to_vec", []) => {
                     implicit_clone::check(cx, name, expr, recv);
                 },
                 ("unwrap", []) => {
@@ -2805,8 +3625,9 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         },
                         _ => {},
                     }
-                    unwrap_used::check(cx, expr, recv, self.allow_unwrap_in_tests);
+                    unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
                 },
+                ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
                 ("unwrap_or", [u_arg]) => match method_call(recv) {
                     Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
                         manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
@@ -2827,8 +3648,12 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
                     },
                 },
-                ("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => {
-                    no_effect_replace::check(cx, expr, arg1, arg2);
+                ("zip", [arg]) => {
+                    if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind
+                        && name.ident.name == sym::iter
+                    {
+                        range_zip_with_len::check(cx, expr, iter_recv, arg);
+                    }
                 },
                 _ => {},
             }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
new file mode 100644 (file)
index 0000000..bd8458a
--- /dev/null
@@ -0,0 +1,30 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, Mutability};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::{sym, Span};
+
+use super::MUT_MUTEX_LOCK;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) {
+    if_chain! {
+        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);
+        if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Mutex);
+        then {
+            span_lint_and_sugg(
+                cx,
+                MUT_MUTEX_LOCK,
+                name_span,
+                "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference",
+                "change this to",
+                "get_mut".to_owned(),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
new file mode 100644 (file)
index 0000000..c311282
--- /dev/null
@@ -0,0 +1,178 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::paths;
+use clippy_utils::ty::match_type;
+use rustc_ast::ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::source_map::{Span, Spanned};
+
+use super::NONSENSICAL_OPEN_OPTIONS;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
+    if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+        && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+        && match_type(cx, cx.tcx.type_of(impl_id), &paths::OPEN_OPTIONS)
+    {
+        let mut options = Vec::new();
+        get_open_options(cx, recv, &mut options);
+        check_open_options(cx, &options, e.span);
+    }
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+enum Argument {
+    True,
+    False,
+    Unknown,
+}
+
+#[derive(Debug)]
+enum OpenOption {
+    Write,
+    Read,
+    Truncate,
+    Create,
+    Append,
+}
+
+fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
+    if let ExprKind::MethodCall(path, arguments, _) = argument.kind {
+        let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).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() >= 2 {
+            let argument_option = match arguments[1].kind {
+                ExprKind::Lit(ref span) => {
+                    if let Spanned {
+                        node: LitKind::Bool(lit),
+                        ..
+                    } = *span
+                    {
+                        if lit { Argument::True } else { Argument::False }
+                    } else {
+                        // The function is called with a literal which is not a boolean literal.
+                        // This is theoretically possible, but not very likely.
+                        return;
+                    }
+                },
+                _ => Argument::Unknown,
+            };
+
+            match path.ident.as_str() {
+                "create" => {
+                    options.push((OpenOption::Create, argument_option));
+                },
+                "append" => {
+                    options.push((OpenOption::Append, argument_option));
+                },
+                "truncate" => {
+                    options.push((OpenOption::Truncate, argument_option));
+                },
+                "read" => {
+                    options.push((OpenOption::Read, argument_option));
+                },
+                "write" => {
+                    options.push((OpenOption::Write, argument_option));
+                },
+                _ => (),
+            }
+
+            get_open_options(cx, &arguments[0], options);
+        }
+    }
+}
+
+fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], span: Span) {
+    let (mut create, mut append, mut truncate, mut read, mut write) = (false, false, false, false, false);
+    let (mut create_arg, mut append_arg, mut truncate_arg, mut read_arg, mut write_arg) =
+        (false, false, false, false, false);
+    // This code is almost duplicated (oh, the irony), but I haven't found a way to
+    // unify it.
+
+    for option in options {
+        match *option {
+            (OpenOption::Create, arg) => {
+                if create {
+                    span_lint(
+                        cx,
+                        NONSENSICAL_OPEN_OPTIONS,
+                        span,
+                        "the method `create` is called more than once",
+                    );
+                } else {
+                    create = true;
+                }
+                create_arg = create_arg || (arg == Argument::True);
+            },
+            (OpenOption::Append, arg) => {
+                if append {
+                    span_lint(
+                        cx,
+                        NONSENSICAL_OPEN_OPTIONS,
+                        span,
+                        "the method `append` is called more than once",
+                    );
+                } else {
+                    append = true;
+                }
+                append_arg = append_arg || (arg == Argument::True);
+            },
+            (OpenOption::Truncate, arg) => {
+                if truncate {
+                    span_lint(
+                        cx,
+                        NONSENSICAL_OPEN_OPTIONS,
+                        span,
+                        "the method `truncate` is called more than once",
+                    );
+                } else {
+                    truncate = true;
+                }
+                truncate_arg = truncate_arg || (arg == Argument::True);
+            },
+            (OpenOption::Read, arg) => {
+                if read {
+                    span_lint(
+                        cx,
+                        NONSENSICAL_OPEN_OPTIONS,
+                        span,
+                        "the method `read` is called more than once",
+                    );
+                } else {
+                    read = true;
+                }
+                read_arg = read_arg || (arg == Argument::True);
+            },
+            (OpenOption::Write, arg) => {
+                if write {
+                    span_lint(
+                        cx,
+                        NONSENSICAL_OPEN_OPTIONS,
+                        span,
+                        "the method `write` is called more than once",
+                    );
+                } else {
+                    write = true;
+                }
+                write_arg = write_arg || (arg == Argument::True);
+            },
+        }
+    }
+
+    if read && truncate && read_arg && truncate_arg && !(write && write_arg) {
+        span_lint(
+            cx,
+            NONSENSICAL_OPEN_OPTIONS,
+            span,
+            "file opened with `truncate` and `read`",
+        );
+    }
+    if append && truncate && append_arg && truncate_arg {
+        span_lint(
+            cx,
+            NONSENSICAL_OPEN_OPTIONS,
+            span,
+            "file opened with `append` and `truncate`",
+        );
+    }
+}
index 6c641af59f92b9c6a3f1b6941c01305f8b8bd464..3c4002a3aef99b86fc175c86b343c9530cfac29e 100644 (file)
@@ -78,7 +78,7 @@ pub(super) fn check<'tcx>(
                     map_span,
                     String::from(if unwrap_snippet_none { "and_then" } else { "map_or" }),
                 ),
-                (expr.span.with_lo(unwrap_recv.span.hi()), String::from("")),
+                (expr.span.with_lo(unwrap_recv.span.hi()), String::new()),
             ];
 
             if !unwrap_snippet_none {
diff --git a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
new file mode 100644 (file)
index 0000000..0cc28c0
--- /dev/null
@@ -0,0 +1,37 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+use std::path::{Component, Path};
+
+use super::PATH_BUF_PUSH_OVERWRITE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
+    if_chain! {
+        if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+        if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+        if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::PathBuf);
+        if let ExprKind::Lit(ref lit) = arg.kind;
+        if let LitKind::Str(ref path_lit, _) = lit.node;
+        if let pushed_path = Path::new(path_lit.as_str());
+        if let Some(pushed_path_lit) = pushed_path.to_str();
+        if pushed_path.has_root();
+        if let Some(root) = pushed_path.components().next();
+        if root == Component::RootDir;
+        then {
+            span_lint_and_sugg(
+                cx,
+                PATH_BUF_PUSH_OVERWRITE,
+                lit.span,
+                "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition",
+                "try",
+                format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
new file mode 100644 (file)
index 0000000..00a2a0d
--- /dev/null
@@ -0,0 +1,34 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::source::snippet;
+use clippy_utils::{higher, SpanlessEq};
+use clippy_utils::{is_integer_const, is_trait_method};
+use if_chain::if_chain;
+use rustc_hir::{Expr, ExprKind, QPath};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::RANGE_ZIP_WITH_LEN;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, zip_arg: &'tcx Expr<'_>) {
+    if_chain! {
+        if is_trait_method(cx, expr, sym::Iterator);
+        // range expression in `.zip()` call: `0..x.len()`
+        if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
+        if is_integer_const(cx, start, 0);
+        // `.len()` call
+        if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind;
+        if len_path.ident.name == sym::len;
+        // `.iter()` and `.len()` called on same `Path`
+        if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind;
+        if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind;
+        if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
+        then {
+            span_lint(cx,
+                RANGE_ZIP_WITH_LEN,
+                expr.span,
+                &format!("it is more idiomatic to use `{}.iter().enumerate()`",
+                    snippet(cx, recv.span, "_"))
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
new file mode 100644 (file)
index 0000000..0a14f92
--- /dev/null
@@ -0,0 +1,52 @@
+use clippy_utils::consts::{constant_context, Constant};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::REPEAT_ONCE;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    recv: &'tcx Expr<'_>,
+    repeat_arg: &'tcx Expr<'_>,
+) {
+    if constant_context(cx, cx.typeck_results()).expr(repeat_arg) == Some(Constant::Int(1)) {
+        let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+        if ty.is_str() {
+            span_lint_and_sugg(
+                cx,
+                REPEAT_ONCE,
+                expr.span,
+                "calling `repeat(1)` on str",
+                "consider using `.to_string()` instead",
+                format!("{}.to_string()", snippet(cx, recv.span, r#""...""#)),
+                Applicability::MachineApplicable,
+            );
+        } else if ty.builtin_index().is_some() {
+            span_lint_and_sugg(
+                cx,
+                REPEAT_ONCE,
+                expr.span,
+                "calling `repeat(1)` on slice",
+                "consider using `.to_vec()` instead",
+                format!("{}.to_vec()", snippet(cx, recv.span, r#""...""#)),
+                Applicability::MachineApplicable,
+            );
+        } else if is_type_diagnostic_item(cx, ty, sym::String) {
+            span_lint_and_sugg(
+                cx,
+                REPEAT_ONCE,
+                expr.span,
+                "calling `repeat(1)` on a string literal",
+                "consider using `.clone()` instead",
+                format!("{}.clone()", snippet(cx, recv.span, r#""...""#)),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
new file mode 100644 (file)
index 0000000..91951c6
--- /dev/null
@@ -0,0 +1,31 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_slice_of_primitives;
+use clippy_utils::source::snippet_with_context;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+
+use super::STABLE_SORT_PRIMITIVE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
+    if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+        && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+        && cx.tcx.type_of(impl_id).is_slice()
+        && let Some(slice_type) = is_slice_of_primitives(cx, recv)
+    {
+        span_lint_and_then(
+            cx,
+            STABLE_SORT_PRIMITIVE,
+            e.span,
+            &format!("used `sort` on primitive type `{}`", slice_type),
+            |diag| {
+                let mut app = Applicability::MachineApplicable;
+                let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0;
+                diag.span_suggestion(e.span, "try", format!("{}.sort_unstable()", recv_snip), app);
+                diag.note(
+                    "an unstable sort typically performs faster without any observable difference for this data type",
+                );
+            },
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
new file mode 100644 (file)
index 0000000..6b306fb
--- /dev/null
@@ -0,0 +1,36 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_diag_trait_item;
+use clippy_utils::source::snippet_with_context;
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::sym;
+
+use super::SUSPICIOUS_TO_OWNED;
+
+pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -> bool {
+    if_chain! {
+        if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+        if is_diag_trait_item(cx, method_def_id, sym::ToOwned);
+        let input_type = cx.typeck_results().expr_ty(expr);
+        if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind();
+        if cx.tcx.is_diagnostic_item(sym::Cow, adt.did());
+        then {
+            let mut app = Applicability::MaybeIncorrect;
+            let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
+            span_lint_and_sugg(
+                cx,
+                SUSPICIOUS_TO_OWNED,
+                expr.span,
+                &format!("this `to_owned` call clones the {0} itself and does not cause the {0} contents to become owned", input_type),
+                "consider using, depending on intent",
+                format!("{0}.clone()` or `{0}.into_owned()", recv_snip),
+                app,
+            );
+            return true;
+        }
+    }
+    false
+}
index 77d21f1d3730c66afeb7ac64f42ea735dd1e611e..a1c6294737cf87225631efca472c0ed5f03e93cf 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_expr_diagnostic_item, ty::is_uninit_value_valid_for_ty};
+use clippy_utils::{is_path_diagnostic_item, ty::is_uninit_value_valid_for_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
     if_chain! {
         if let hir::ExprKind::Call(callee, args) = recv.kind;
         if args.is_empty();
-        if is_expr_diagnostic_item(cx, callee, sym::maybe_uninit_uninit);
+        if is_path_diagnostic_item(cx, callee, sym::maybe_uninit_uninit);
         if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr));
         then {
             span_lint(
diff --git a/src/tools/clippy/clippy_lints/src/methods/unit_hash.rs b/src/tools/clippy/clippy_lints/src/methods/unit_hash.rs
new file mode 100644 (file)
index 0000000..3c7955b
--- /dev/null
@@ -0,0 +1,29 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_trait_method;
+use clippy_utils::source::snippet;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::UNIT_HASH;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
+    if is_trait_method(cx, expr, sym::Hash) && cx.typeck_results().expr_ty(recv).is_unit() {
+        span_lint_and_then(
+            cx,
+            UNIT_HASH,
+            expr.span,
+            "this call to `hash` on the unit type will do nothing",
+            |diag| {
+                diag.span_suggestion(
+                    expr.span,
+                    "remove the call to `hash` or consider using",
+                    format!("0_u8.hash({})", snippet(cx, arg.span, ".."),),
+                    Applicability::MaybeIncorrect,
+                );
+                diag.note("the implementation of `Hash` for `()` is a no-op");
+            },
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
new file mode 100644 (file)
index 0000000..1966990
--- /dev/null
@@ -0,0 +1,224 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_trait_method;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::implements_trait;
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, subst::GenericArgKind};
+use rustc_span::sym;
+use rustc_span::symbol::Ident;
+use std::iter;
+
+use super::UNNECESSARY_SORT_BY;
+
+enum LintTrigger {
+    Sort(SortDetection),
+    SortByKey(SortByKeyDetection),
+}
+
+struct SortDetection {
+    vec_name: String,
+}
+
+struct SortByKeyDetection {
+    vec_name: String,
+    closure_arg: String,
+    closure_body: String,
+    reverse: bool,
+}
+
+/// Detect if the two expressions are mirrored (identical, except one
+/// contains a and the other replaces it with b)
+fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool {
+    match (&a_expr.kind, &b_expr.kind) {
+        // Two boxes with mirrored contents
+        (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => {
+            mirrored_exprs(left_expr, a_ident, right_expr, b_ident)
+        },
+        // Two arrays with mirrored contents
+        (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => {
+            iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
+        },
+        // The two exprs are function calls.
+        // Check to see that the function itself and its arguments are mirrored
+        (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => {
+            mirrored_exprs(left_expr, a_ident, right_expr, b_ident)
+                && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
+        },
+        // The two exprs are method calls.
+        // Check to see that the function is the same and the arguments are mirrored
+        // This is enough because the receiver of the method is listed in the arguments
+        (ExprKind::MethodCall(left_segment, left_args, _), ExprKind::MethodCall(right_segment, right_args, _)) => {
+            left_segment.ident == right_segment.ident
+                && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
+        },
+        // Two tuples with mirrored contents
+        (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => {
+            iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
+        },
+        // Two binary ops, which are the same operation and which have mirrored arguments
+        (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => {
+            left_op.node == right_op.node
+                && mirrored_exprs(left_left, a_ident, right_left, b_ident)
+                && mirrored_exprs(left_right, a_ident, right_right, b_ident)
+        },
+        // Two unary ops, which are the same operation and which have the same argument
+        (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) => {
+            left_op == right_op && mirrored_exprs(left_expr, a_ident, right_expr, b_ident)
+        },
+        // The two exprs are literals of some kind
+        (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node,
+        (ExprKind::Cast(left, _), ExprKind::Cast(right, _)) => mirrored_exprs(left, a_ident, right, b_ident),
+        (ExprKind::DropTemps(left_block), ExprKind::DropTemps(right_block)) => {
+            mirrored_exprs(left_block, a_ident, right_block, b_ident)
+        },
+        (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => {
+            left_ident.name == right_ident.name && mirrored_exprs(left_expr, a_ident, right_expr, right_ident)
+        },
+        // Two paths: either one is a and the other is b, or they're identical to each other
+        (
+            ExprKind::Path(QPath::Resolved(
+                _,
+                Path {
+                    segments: left_segments,
+                    ..
+                },
+            )),
+            ExprKind::Path(QPath::Resolved(
+                _,
+                Path {
+                    segments: right_segments,
+                    ..
+                },
+            )),
+        ) => {
+            (iter::zip(*left_segments, *right_segments).all(|(left, right)| left.ident == right.ident)
+                && left_segments
+                    .iter()
+                    .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident))
+                || (left_segments.len() == 1
+                    && &left_segments[0].ident == a_ident
+                    && right_segments.len() == 1
+                    && &right_segments[0].ident == b_ident)
+        },
+        // Matching expressions, but one or both is borrowed
+        (
+            ExprKind::AddrOf(left_kind, Mutability::Not, left_expr),
+            ExprKind::AddrOf(right_kind, Mutability::Not, right_expr),
+        ) => left_kind == right_kind && mirrored_exprs(left_expr, a_ident, right_expr, b_ident),
+        (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) => mirrored_exprs(a_expr, a_ident, right_expr, b_ident),
+        (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => mirrored_exprs(left_expr, a_ident, b_expr, b_ident),
+        _ => false,
+    }
+}
+
+fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) -> Option<LintTrigger> {
+    if_chain! {
+        if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+        if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+        if cx.tcx.type_of(impl_id).is_slice();
+        if let ExprKind::Closure(&Closure { body, .. }) = arg.kind;
+        if let closure_body = cx.tcx.hir().body(body);
+        if let &[
+            Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
+            Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
+        ] = &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);
+        then {
+            let (closure_body, closure_arg, reverse) = if mirrored_exprs(
+                left_expr,
+                left_ident,
+                right_expr,
+                right_ident
+            ) {
+                (Sugg::hir(cx, left_expr, "..").to_string(), left_ident.name.to_string(), false)
+            } else if mirrored_exprs(left_expr, right_ident, right_expr, left_ident) {
+                (Sugg::hir(cx, left_expr, "..").to_string(), right_ident.name.to_string(), true)
+            } else {
+                return None;
+            };
+            let vec_name = Sugg::hir(cx, recv, "..").to_string();
+
+            if_chain! {
+                if let ExprKind::Path(QPath::Resolved(_, Path {
+                    segments: [PathSegment { ident: left_name, .. }], ..
+                })) = &left_expr.kind;
+                if left_name == left_ident;
+                if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
+                    implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
+                });
+                then {
+                    return Some(LintTrigger::Sort(SortDetection { vec_name }));
+                }
+            }
+
+            if !expr_borrows(cx, left_expr) {
+                return Some(LintTrigger::SortByKey(SortByKeyDetection {
+                    vec_name,
+                    closure_arg,
+                    closure_body,
+                    reverse,
+                }));
+            }
+        }
+    }
+
+    None
+}
+
+fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.typeck_results().expr_ty(expr);
+    matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
+}
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    recv: &'tcx Expr<'_>,
+    arg: &'tcx Expr<'_>,
+    is_unstable: bool,
+) {
+    match detect_lint(cx, expr, recv, arg) {
+        Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg(
+            cx,
+            UNNECESSARY_SORT_BY,
+            expr.span,
+            "use Vec::sort_by_key here instead",
+            "try",
+            format!(
+                "{}.sort{}_by_key(|{}| {})",
+                trigger.vec_name,
+                if is_unstable { "_unstable" } else { "" },
+                trigger.closure_arg,
+                if trigger.reverse {
+                    format!("std::cmp::Reverse({})", trigger.closure_body)
+                } else {
+                    trigger.closure_body.to_string()
+                },
+            ),
+            if trigger.reverse {
+                Applicability::MaybeIncorrect
+            } else {
+                Applicability::MachineApplicable
+            },
+        ),
+        Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg(
+            cx,
+            UNNECESSARY_SORT_BY,
+            expr.span,
+            "use Vec::sort here instead",
+            "try",
+            format!(
+                "{}.sort{}()",
+                trigger.vec_name,
+                if is_unstable { "_unstable" } else { "" },
+            ),
+            Applicability::MachineApplicable,
+        ),
+        None => {},
+    }
+}
index b3276f1394ed2f7bcb0f4bcd3ad5bea8322717ce..44bf84352943853bddfa26628e7515617a93e14f 100644 (file)
@@ -3,11 +3,10 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{
-    contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs,
+    get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, peel_mid_ty_refs,
 };
-use clippy_utils::{meets_msrv, msrvs};
-
 use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item};
+use clippy_utils::{meets_msrv, msrvs};
 use rustc_errors::Applicability;
 use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -279,7 +278,19 @@ fn check_other_call_arg<'tcx>(
                 &trait_predicate.trait_ref.substs.iter().skip(1).collect::<Vec<_>>()[..],
                 call_substs,
             );
-            implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_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
         };
@@ -292,7 +303,7 @@ fn check_other_call_arg<'tcx>(
         // (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
-            || !contains_ty(fn_sig.output(), input);
+            || !fn_sig.output().contains(input);
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
             span_lint_and_sugg(
@@ -360,25 +371,15 @@ fn get_input_traits_and_projections<'tcx>(
 ) -> (Vec<TraitPredicate<'tcx>>, Vec<ProjectionPredicate<'tcx>>) {
     let mut trait_predicates = Vec::new();
     let mut projection_predicates = Vec::new();
-    for (predicate, _) in cx.tcx.predicates_of(callee_def_id).predicates.iter() {
-        // `substs` should have 1 + n elements. The first is the type on the left hand side of an
-        // `as`. The remaining n are trait parameters.
-        let is_input_substs = |substs: SubstsRef<'tcx>| {
-            if_chain! {
-                if let Some(arg) = substs.iter().next();
-                if let GenericArgKind::Type(arg_ty) = arg.unpack();
-                if arg_ty == input;
-                then { true } else { false }
-            }
-        };
+    for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() {
         match predicate.kind().skip_binder() {
             PredicateKind::Trait(trait_predicate) => {
-                if is_input_substs(trait_predicate.trait_ref.substs) {
+                if trait_predicate.trait_ref.self_ty() == input {
                     trait_predicates.push(trait_predicate);
                 }
             },
             PredicateKind::Projection(projection_predicate) => {
-                if is_input_substs(projection_predicate.projection_ty.substs) {
+                if projection_predicate.projection_ty.self_ty() == input {
                     projection_predicates.push(projection_predicate);
                 }
             },
index ce1a52e5480afb81226859153023754301935f84..ee17f2d7889ee9f93b6f619bf0100d982a62ec3e 100644 (file)
@@ -7,18 +7,26 @@
 
 use super::{EXPECT_USED, UNWRAP_USED};
 
-/// lint use of `unwrap()` for `Option`s and `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) {
+/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`.
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    recv: &hir::Expr<'_>,
+    is_err: bool,
+    allow_unwrap_in_tests: bool,
+) {
     let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
-    let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
+    let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
         Some((UNWRAP_USED, "an Option", "None", ""))
     } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
-        Some((UNWRAP_USED, "a Result", "Err", "an "))
+        Some((UNWRAP_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
     } else {
         None
     };
 
+    let method_suffix = if is_err { "_err" } else { "" };
+
     if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
         return;
     }
@@ -27,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
             format!(
                 "if you don't want to handle the `{none_value}` case gracefully, consider \
-                using `expect()` to provide a better panic message"
+                using `expect{method_suffix}()` to provide a better panic message"
             )
         } else {
             format!("if this value is {none_prefix}`{none_value}`, it will panic")
@@ -37,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
             cx,
             lint,
             expr.span,
-            &format!("used `unwrap()` on `{kind}` value"),
+            &format!("used `unwrap{method_suffix}()` on `{kind}` value"),
             None,
             &help,
         );
diff --git a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
new file mode 100644 (file)
index 0000000..02d8364
--- /dev/null
@@ -0,0 +1,45 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+use rustc_span::{sym, Span};
+
+use super::VEC_RESIZE_TO_ZERO;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    count_arg: &'tcx Expr<'_>,
+    default_arg: &'tcx Expr<'_>,
+    name_span: Span,
+) {
+    if_chain! {
+        if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+        if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+        if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Vec);
+        if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind;
+        if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind;
+        then {
+            let method_call_span = expr.span.with_lo(name_span.lo());
+            span_lint_and_then(
+                cx,
+                VEC_RESIZE_TO_ZERO,
+                expr.span,
+                "emptying a vector with `resize`",
+                |db| {
+                    db.help("the arguments may be inverted...");
+                    db.span_suggestion(
+                        method_call_span,
+                        "...or you can empty the vector with",
+                        "clear()".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                },
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
new file mode 100644 (file)
index 0000000..2fe5ae9
--- /dev/null
@@ -0,0 +1,28 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_trait_method;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_hir::{Expr, ExprKind, QPath};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::VERBOSE_FILE_READS;
+
+pub(super) const READ_TO_END_MSG: (&str, &str) = ("use of `File::read_to_end`", "consider using `fs::read` instead");
+pub(super) const READ_TO_STRING_MSG: (&str, &str) = (
+    "use of `File::read_to_string`",
+    "consider using `fs::read_to_string` instead",
+);
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    recv: &'tcx Expr<'_>,
+    (msg, help): (&str, &str),
+) {
+    if is_trait_method(cx, expr, sym::IoRead)
+        && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _)))
+        && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(recv).peel_refs(), sym::File)
+    {
+        span_lint_and_help(cx, VERBOSE_FILE_READS, expr.span, msg, None, help);
+    }
+}
index df044538fe19d36b825bcd5d858c9833a6308961..7c4ae746e90e91894f9c604dadc53254cb48fb52 100644 (file)
@@ -46,7 +46,7 @@ fn span_lint(cx: &EarlyContext<'_>, span: Span, only_one: bool) {
             "these patterns are unneeded as the `..` pattern can match those elements"
         },
         if only_one { "remove it" } else { "remove them" },
-        "".to_string(),
+        String::new(),
         Applicability::MachineApplicable,
     );
 }
index f763e0d24c9444206a8d14b599a411f3067d610e..020efeaebf02905dd46bb0b0a7ef0c5fa7f91853 100644 (file)
@@ -40,7 +40,7 @@
     /// }
     /// impl<A, B> Foo<A, B> {}
     /// ```
-    #[clippy::version = "1.62.0"]
+    #[clippy::version = "1.63.0"]
     pub MISMATCHING_TYPE_PARAM_ORDER,
     pedantic,
     "type parameter positioned inconsistently between type def and impl block"
diff --git a/src/tools/clippy/clippy_lints/src/multi_assignments.rs b/src/tools/clippy/clippy_lints/src/multi_assignments.rs
new file mode 100644 (file)
index 0000000..81eb1a0
--- /dev/null
@@ -0,0 +1,65 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    ///# let (a, b);
+    /// a = b = 42;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    ///# let (a, b);
+    /// b = 42;
+    /// a = b;
+    /// ```
+    #[clippy::version = "1.65.0"]
+    pub MULTI_ASSIGNMENTS,
+    suspicious,
+    "instead of using `a = b = c;` use `a = c; b = c;`"
+}
+
+declare_lint_pass!(MultiAssignments => [MULTI_ASSIGNMENTS]);
+
+fn strip_paren_blocks(expr: &Expr) -> &Expr {
+    match &expr.kind {
+        ExprKind::Paren(e) => strip_paren_blocks(e),
+        ExprKind::Block(b, _) => {
+            if let [
+                Stmt {
+                    kind: StmtKind::Expr(e),
+                    ..
+                },
+            ] = &b.stmts[..]
+            {
+                strip_paren_blocks(e)
+            } else {
+                expr
+            }
+        },
+        _ => expr,
+    }
+}
+
+impl EarlyLintPass for MultiAssignments {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        if let ExprKind::Assign(target, source, _) = &expr.kind {
+            if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(target).kind {
+                span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively");
+            };
+            if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(source).kind {
+                span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively");
+            }
+        };
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs
deleted file mode 100644 (file)
index b7f981f..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, Mutability};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// 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:
-    /// ```rust
-    /// 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;
-    /// ```
-    #[clippy::version = "1.49.0"]
-    pub MUT_MUTEX_LOCK,
-    style,
-    "`&mut Mutex::lock` does unnecessary locking"
-}
-
-declare_lint_pass!(MutMutexLock => [MUT_MUTEX_LOCK]);
-
-impl<'tcx> LateLintPass<'tcx> for MutMutexLock {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>) {
-        if_chain! {
-            if let ExprKind::MethodCall(path, [self_arg, ..], _) = &ex.kind;
-            if path.ident.name == sym!(lock);
-            let ty = cx.typeck_results().expr_ty(self_arg);
-            if let ty::Ref(_, inner_ty, Mutability::Mut) = ty.kind();
-            if is_type_diagnostic_item(cx, *inner_ty, sym::Mutex);
-            then {
-                span_lint_and_sugg(
-                    cx,
-                    MUT_MUTEX_LOCK,
-                    path.ident.span,
-                    "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference",
-                    "change this to",
-                    "get_mut".to_owned(),
-                    Applicability::MaybeIncorrect,
-                );
-            }
-        }
-    }
-}
index 413a740be25a529c0fe8fb64361dd38d567de634..774a3540d1e0c41bef19b00f44b955664de5c743 100644 (file)
@@ -1,25 +1,16 @@
-use std::collections::VecDeque;
-
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_lint_allowed;
-use itertools::{izip, Itertools};
-use rustc_ast::{walk_list, Label, Mutability};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{get_expr_use_or_unification_node, get_parent_node, path_def_id, path_to_local, path_to_local_id};
+use core::cell::Cell;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
-use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
-use rustc_hir::intravisit::{walk_expr, walk_stmt, FnKind, Visitor};
-use rustc_hir::{
-    Arm, Block, Body, Closure, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path,
-    PathSegment, QPath, Stmt, StmtKind, TyKind, UnOp,
-};
+use rustc_hir::hir_id::HirIdMap;
+use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_middle::ty::{Ty, TyCtxt, TypeckResults};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::kw;
-use rustc_span::symbol::Ident;
+use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
+use rustc_middle::ty::{self, ConstKind};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.61.0"]
     pub ONLY_USED_IN_RECURSION,
-    nursery,
+    complexity,
     "arguments that is only used in recursion can be removed"
 }
-declare_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]);
-
-impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        kind: FnKind<'tcx>,
-        decl: &'tcx rustc_hir::FnDecl<'tcx>,
-        body: &'tcx Body<'tcx>,
-        _: Span,
-        id: HirId,
-    ) {
-        if is_lint_allowed(cx, ONLY_USED_IN_RECURSION, id) {
-            return;
-        }
-        if let FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) = kind {
-            let def_id = id.owner.to_def_id();
-            let data = cx.tcx.def_path(def_id).data;
-
-            if data.len() > 1 {
-                match data.get(data.len() - 2) {
-                    Some(DisambiguatedDefPathData {
-                        data: DefPathData::Impl,
-                        disambiguator,
-                    }) if *disambiguator != 0 => return,
-                    _ => {},
-                }
-            }
-
-            let has_self = !matches!(decl.implicit_self, ImplicitSelfKind::None);
-
-            let ty_res = cx.typeck_results();
-            let param_span = body
-                .params
-                .iter()
-                .flat_map(|param| {
-                    let mut v = Vec::new();
-                    param.pat.each_binding(|_, hir_id, span, ident| {
-                        v.push((hir_id, span, ident));
-                    });
-                    v
-                })
-                .skip(if has_self { 1 } else { 0 })
-                .filter(|(_, _, ident)| !ident.name.as_str().starts_with('_'))
-                .collect_vec();
-
-            let params = body.params.iter().map(|param| param.pat).collect();
-
-            let mut visitor = SideEffectVisit {
-                graph: FxHashMap::default(),
-                has_side_effect: FxHashSet::default(),
-                ret_vars: Vec::new(),
-                contains_side_effect: false,
-                break_vars: FxHashMap::default(),
-                params,
-                fn_ident: ident,
-                fn_def_id: def_id,
-                is_method: matches!(kind, FnKind::Method(..)),
-                has_self,
-                ty_res,
-                tcx: cx.tcx,
-                visited_exprs: FxHashSet::default(),
-            };
-
-            visitor.visit_expr(&body.value);
-            let vars = std::mem::take(&mut visitor.ret_vars);
-            // this would set the return variables to side effect
-            visitor.add_side_effect(vars);
-
-            let mut queue = visitor.has_side_effect.iter().copied().collect::<VecDeque<_>>();
-
-            // a simple BFS to check all the variables that have side effect
-            while let Some(id) = queue.pop_front() {
-                if let Some(next) = visitor.graph.get(&id) {
-                    for i in next {
-                        if !visitor.has_side_effect.contains(i) {
-                            visitor.has_side_effect.insert(*i);
-                            queue.push_back(*i);
-                        }
-                    }
-                }
-            }
-
-            for (id, span, ident) in param_span {
-                // if the variable is not used in recursion, it would be marked as unused
-                if !visitor.has_side_effect.contains(&id) {
-                    let mut queue = VecDeque::new();
-                    let mut visited = FxHashSet::default();
-
-                    queue.push_back(id);
-
-                    // a simple BFS to check the graph can reach to itself
-                    // if it can't, it means the variable is never used in recursion
-                    while let Some(id) = queue.pop_front() {
-                        if let Some(next) = visitor.graph.get(&id) {
-                            for i in next {
-                                if !visited.contains(i) {
-                                    visited.insert(id);
-                                    queue.push_back(*i);
-                                }
-                            }
-                        }
-                    }
+impl_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]);
+
+#[derive(Clone, Copy)]
+enum FnKind {
+    Fn,
+    TraitFn,
+    // This is a hack. Ideally we would store a `SubstsRef<'tcx>` type here, but a lint pass must be `'static`.
+    // Substitutions are, however, interned. This allows us to store the pointer as a `usize` when comparing for
+    // equality.
+    ImplTraitFn(usize),
+}
 
-                    if visited.contains(&id) {
-                        span_lint_and_sugg(
-                            cx,
-                            ONLY_USED_IN_RECURSION,
-                            span,
-                            "parameter is only used in recursion",
-                            "if this is intentional, prefix with an underscore",
-                            format!("_{}", ident.name.as_str()),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-            }
+struct Param {
+    /// The function this is a parameter for.
+    fn_id: DefId,
+    fn_kind: FnKind,
+    /// The index of this parameter.
+    idx: usize,
+    ident: Ident,
+    /// Whether this parameter should be linted. Set by `Params::flag_for_linting`.
+    apply_lint: Cell<bool>,
+    /// All the uses of this parameter.
+    uses: Vec<Usage>,
+}
+impl Param {
+    fn new(fn_id: DefId, fn_kind: FnKind, idx: usize, ident: Ident) -> Self {
+        Self {
+            fn_id,
+            fn_kind,
+            idx,
+            ident,
+            apply_lint: Cell::new(true),
+            uses: Vec::new(),
         }
     }
 }
 
-pub fn is_primitive(ty: Ty<'_>) -> bool {
-    let ty = ty.peel_refs();
-    ty.is_primitive() || ty.is_str()
+#[derive(Debug)]
+struct Usage {
+    span: Span,
+    idx: usize,
 }
-
-pub fn is_array(ty: Ty<'_>) -> bool {
-    let ty = ty.peel_refs();
-    ty.is_array() || ty.is_array_slice()
+impl Usage {
+    fn new(span: Span, idx: usize) -> Self {
+        Self { span, idx }
+    }
 }
 
-/// This builds the graph of side effect.
-/// The edge `a -> b` means if `a` has side effect, `b` will have side effect.
-///
-/// There are some example in following code:
-/// ```rust, ignore
-/// let b = 1;
-/// let a = b; // a -> b
-/// let (c, d) = (a, b); // c -> b, d -> b
-///
-/// let e = if a == 0 { // e -> a
-///     c // e -> c
-/// } else {
-///     d // e -> d
-/// };
-/// ```
-pub struct SideEffectVisit<'tcx> {
-    graph: FxHashMap<HirId, FxHashSet<HirId>>,
-    has_side_effect: FxHashSet<HirId>,
-    // bool for if the variable was dereferenced from mutable reference
-    ret_vars: Vec<(HirId, bool)>,
-    contains_side_effect: bool,
-    // break label
-    break_vars: FxHashMap<Ident, Vec<(HirId, bool)>>,
-    params: Vec<&'tcx Pat<'tcx>>,
-    fn_ident: Ident,
-    fn_def_id: DefId,
-    is_method: bool,
-    has_self: bool,
-    ty_res: &'tcx TypeckResults<'tcx>,
-    tcx: TyCtxt<'tcx>,
-    visited_exprs: FxHashSet<HirId>,
+/// The parameters being checked by the lint, indexed by both the parameter's `HirId` and the
+/// `DefId` of the function paired with the parameter's index.
+#[derive(Default)]
+struct Params {
+    params: Vec<Param>,
+    by_id: HirIdMap<usize>,
+    by_fn: FxHashMap<(DefId, usize), usize>,
 }
-
-impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> {
-    fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) {
-        match s.kind {
-            StmtKind::Local(Local {
-                pat, init: Some(init), ..
-            }) => {
-                self.visit_pat_expr(pat, init, false);
-            },
-            StmtKind::Item(_) | StmtKind::Expr(_) | StmtKind::Semi(_) => {
-                walk_stmt(self, s);
-            },
-            StmtKind::Local(_) => {},
-        }
-        self.ret_vars.clear();
+impl Params {
+    fn insert(&mut self, param: Param, id: HirId) {
+        let idx = self.params.len();
+        self.by_id.insert(id, idx);
+        self.by_fn.insert((param.fn_id, param.idx), idx);
+        self.params.push(param);
     }
 
-    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
-        if !self.visited_exprs.insert(ex.hir_id) {
-            return;
-        }
-        match ex.kind {
-            ExprKind::Array(exprs) | ExprKind::Tup(exprs) => {
-                self.ret_vars = exprs
-                    .iter()
-                    .flat_map(|expr| {
-                        self.visit_expr(expr);
-                        std::mem::take(&mut self.ret_vars)
-                    })
-                    .collect();
-            },
-            ExprKind::Call(callee, args) => self.visit_fn(callee, args),
-            ExprKind::MethodCall(path, args, _) => self.visit_method_call(path, args),
-            ExprKind::Binary(_, lhs, rhs) => {
-                self.visit_bin_op(lhs, rhs);
-            },
-            ExprKind::Unary(op, expr) => self.visit_un_op(op, expr),
-            ExprKind::Let(Let { pat, init, .. }) => self.visit_pat_expr(pat, init, false),
-            ExprKind::If(bind, then_expr, else_expr) => {
-                self.visit_if(bind, then_expr, else_expr);
-            },
-            ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms),
-            // since analysing the closure is not easy, just set all variables in it to side-effect
-            ExprKind::Closure(&Closure { body, .. }) => {
-                let body = self.tcx.hir().body(body);
-                self.visit_body(body);
-                let vars = std::mem::take(&mut self.ret_vars);
-                self.add_side_effect(vars);
-            },
-            ExprKind::Loop(block, label, _, _) | ExprKind::Block(block, label) => {
-                self.visit_block_label(block, label);
-            },
-            ExprKind::Assign(bind, expr, _) => {
-                self.visit_assign(bind, expr);
-            },
-            ExprKind::AssignOp(_, bind, expr) => {
-                self.visit_assign(bind, expr);
-                self.visit_bin_op(bind, expr);
-            },
-            ExprKind::Field(expr, _) => {
-                self.visit_expr(expr);
-                if matches!(self.ty_res.expr_ty(expr).kind(), ty::Ref(_, _, Mutability::Mut)) {
-                    self.ret_vars.iter_mut().for_each(|(_, b)| *b = true);
-                }
-            },
-            ExprKind::Index(expr, index) => {
-                self.visit_expr(expr);
-                let mut vars = std::mem::take(&mut self.ret_vars);
-                self.visit_expr(index);
-                self.ret_vars.append(&mut vars);
-
-                if !is_array(self.ty_res.expr_ty(expr)) {
-                    self.add_side_effect(self.ret_vars.clone());
-                } else if matches!(self.ty_res.expr_ty(expr).kind(), ty::Ref(_, _, Mutability::Mut)) {
-                    self.ret_vars.iter_mut().for_each(|(_, b)| *b = true);
-                }
-            },
-            ExprKind::Break(dest, Some(expr)) => {
-                self.visit_expr(expr);
-                if let Some(label) = dest.label {
-                    self.break_vars
-                        .entry(label.ident)
-                        .or_insert(Vec::new())
-                        .append(&mut self.ret_vars);
-                }
-                self.contains_side_effect = true;
-            },
-            ExprKind::Ret(Some(expr)) => {
-                self.visit_expr(expr);
-                let vars = std::mem::take(&mut self.ret_vars);
-                self.add_side_effect(vars);
-                self.contains_side_effect = true;
-            },
-            ExprKind::Break(_, None) | ExprKind::Continue(_) | ExprKind::Ret(None) => {
-                self.contains_side_effect = true;
-            },
-            ExprKind::Struct(_, exprs, expr) => {
-                let mut ret_vars = exprs
-                    .iter()
-                    .flat_map(|field| {
-                        self.visit_expr(field.expr);
-                        std::mem::take(&mut self.ret_vars)
-                    })
-                    .collect();
-
-                walk_list!(self, visit_expr, expr);
-                self.ret_vars.append(&mut ret_vars);
-            },
-            _ => walk_expr(self, ex),
+    fn remove_by_id(&mut self, id: HirId) {
+        if let Some(param) = self.get_by_id_mut(id) {
+            param.uses = Vec::new();
+            let key = (param.fn_id, param.idx);
+            self.by_fn.remove(&key);
+            self.by_id.remove(&id);
         }
     }
 
-    fn visit_path(&mut self, path: &'tcx Path<'tcx>, _id: HirId) {
-        if let Res::Local(id) = path.res {
-            self.ret_vars.push((id, false));
-        }
+    fn get_by_id_mut(&mut self, id: HirId) -> Option<&mut Param> {
+        self.params.get_mut(*self.by_id.get(&id)?)
     }
-}
 
-impl<'tcx> SideEffectVisit<'tcx> {
-    fn visit_assign(&mut self, lhs: &'tcx Expr<'tcx>, rhs: &'tcx Expr<'tcx>) {
-        // Just support array and tuple unwrapping for now.
-        //
-        // ex) `(a, b) = (c, d);`
-        // The graph would look like this:
-        //   a -> c
-        //   b -> d
-        //
-        // This would minimize the connection of the side-effect graph.
-        match (&lhs.kind, &rhs.kind) {
-            (ExprKind::Array(lhs), ExprKind::Array(rhs)) | (ExprKind::Tup(lhs), ExprKind::Tup(rhs)) => {
-                // if not, it is a compile error
-                debug_assert!(lhs.len() == rhs.len());
-                izip!(*lhs, *rhs).for_each(|(lhs, rhs)| self.visit_assign(lhs, rhs));
-            },
-            // in other assigns, we have to connect all each other
-            // because they can be connected somehow
-            _ => {
-                self.visit_expr(lhs);
-                let lhs_vars = std::mem::take(&mut self.ret_vars);
-                self.visit_expr(rhs);
-                let rhs_vars = std::mem::take(&mut self.ret_vars);
-                self.connect_assign(&lhs_vars, &rhs_vars, false);
-            },
-        }
+    fn get_by_fn(&self, id: DefId, idx: usize) -> Option<&Param> {
+        self.params.get(*self.by_fn.get(&(id, idx))?)
     }
 
-    fn visit_block_label(&mut self, block: &'tcx Block<'tcx>, label: Option<Label>) {
-        self.visit_block(block);
-        let _ = label.and_then(|label| {
-            self.break_vars
-                .remove(&label.ident)
-                .map(|mut break_vars| self.ret_vars.append(&mut break_vars))
-        });
-    }
-
-    fn visit_bin_op(&mut self, lhs: &'tcx Expr<'tcx>, rhs: &'tcx Expr<'tcx>) {
-        self.visit_expr(lhs);
-        let mut ret_vars = std::mem::take(&mut self.ret_vars);
-        self.visit_expr(rhs);
-        self.ret_vars.append(&mut ret_vars);
-
-        // the binary operation between non primitive values are overloaded operators
-        // so they can have side-effects
-        if !is_primitive(self.ty_res.expr_ty(lhs)) || !is_primitive(self.ty_res.expr_ty(rhs)) {
-            self.ret_vars.iter().for_each(|id| {
-                self.has_side_effect.insert(id.0);
-            });
-            self.contains_side_effect = true;
-        }
+    fn clear(&mut self) {
+        self.params.clear();
+        self.by_id.clear();
+        self.by_fn.clear();
     }
 
-    fn visit_un_op(&mut self, op: UnOp, expr: &'tcx Expr<'tcx>) {
-        self.visit_expr(expr);
-        let ty = self.ty_res.expr_ty(expr);
-        // dereferencing a reference has no side-effect
-        if !is_primitive(ty) && !matches!((op, ty.kind()), (UnOp::Deref, ty::Ref(..))) {
-            self.add_side_effect(self.ret_vars.clone());
-        }
-
-        if matches!((op, ty.kind()), (UnOp::Deref, ty::Ref(_, _, Mutability::Mut))) {
-            self.ret_vars.iter_mut().for_each(|(_, b)| *b = true);
+    /// Sets the `apply_lint` flag on each parameter.
+    fn flag_for_linting(&mut self) {
+        // Stores the list of parameters currently being resolved. Needed to avoid cycles.
+        let mut eval_stack = Vec::new();
+        for param in &self.params {
+            self.try_disable_lint_for_param(param, &mut eval_stack);
         }
     }
 
-    fn visit_pat_expr(&mut self, pat: &'tcx Pat<'tcx>, expr: &'tcx Expr<'tcx>, connect_self: bool) {
-        match (&pat.kind, &expr.kind) {
-            (PatKind::Tuple(pats, _), ExprKind::Tup(exprs)) => {
-                self.ret_vars = izip!(*pats, *exprs)
-                    .flat_map(|(pat, expr)| {
-                        self.visit_pat_expr(pat, expr, connect_self);
-                        std::mem::take(&mut self.ret_vars)
-                    })
-                    .collect();
-            },
-            (PatKind::Slice(front_exprs, _, back_exprs), ExprKind::Array(exprs)) => {
-                let mut vars = izip!(*front_exprs, *exprs)
-                    .flat_map(|(pat, expr)| {
-                        self.visit_pat_expr(pat, expr, connect_self);
-                        std::mem::take(&mut self.ret_vars)
-                    })
-                    .collect();
-                self.ret_vars = izip!(back_exprs.iter().rev(), exprs.iter().rev())
-                    .flat_map(|(pat, expr)| {
-                        self.visit_pat_expr(pat, expr, connect_self);
-                        std::mem::take(&mut self.ret_vars)
-                    })
-                    .collect();
-                self.ret_vars.append(&mut vars);
-            },
-            _ => {
-                let mut lhs_vars = Vec::new();
-                pat.each_binding(|_, id, _, _| lhs_vars.push((id, false)));
-                self.visit_expr(expr);
-                let rhs_vars = std::mem::take(&mut self.ret_vars);
-                self.connect_assign(&lhs_vars, &rhs_vars, connect_self);
-                self.ret_vars = rhs_vars;
-            },
+    // Use by calling `flag_for_linting`.
+    fn try_disable_lint_for_param(&self, param: &Param, eval_stack: &mut Vec<usize>) -> bool {
+        if !param.apply_lint.get() {
+            true
+        } else if param.uses.is_empty() {
+            // Don't lint on unused parameters.
+            param.apply_lint.set(false);
+            true
+        } else if eval_stack.contains(&param.idx) {
+            // Already on the evaluation stack. Returning false will continue to evaluate other dependencies.
+            false
+        } else {
+            eval_stack.push(param.idx);
+            // Check all cases when used at a different parameter index.
+            // Needed to catch cases like: `fn f(x: u32, y: u32) { f(y, x) }`
+            for usage in param.uses.iter().filter(|u| u.idx != param.idx) {
+                if self
+                    .get_by_fn(param.fn_id, usage.idx)
+                    // If the parameter can't be found, then it's used for more than just recursion.
+                    .map_or(true, |p| self.try_disable_lint_for_param(p, eval_stack))
+                {
+                    param.apply_lint.set(false);
+                    eval_stack.pop();
+                    return true;
+                }
+            }
+            eval_stack.pop();
+            false
         }
     }
+}
 
-    fn visit_fn(&mut self, callee: &'tcx Expr<'tcx>, args: &'tcx [Expr<'tcx>]) {
-        self.visit_expr(callee);
-        let mut ret_vars = std::mem::take(&mut self.ret_vars);
-        self.add_side_effect(ret_vars.clone());
-
-        let mut is_recursive = false;
-
-        if_chain! {
-            if !self.has_self;
-            if let ExprKind::Path(QPath::Resolved(_, path)) = callee.kind;
-            if let Res::Def(DefKind::Fn, def_id) = path.res;
-            if self.fn_def_id == def_id;
-            then {
-                is_recursive = true;
-            }
-        }
+#[derive(Default)]
+pub struct OnlyUsedInRecursion {
+    /// Track the top-level body entered. Needed to delay reporting when entering nested bodies.
+    entered_body: Option<HirId>,
+    params: Params,
+}
 
-        if_chain! {
-            if !self.has_self && self.is_method;
-            if let ExprKind::Path(QPath::TypeRelative(ty, segment)) = callee.kind;
-            if segment.ident == self.fn_ident;
-            if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
-            if let Res::SelfTy{ .. } = path.res;
-            then {
-                is_recursive = true;
-            }
+impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
+    fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
+        if body.value.span.from_expansion() {
+            return;
         }
-
-        if is_recursive {
-            izip!(self.params.clone(), args).for_each(|(pat, expr)| {
-                self.visit_pat_expr(pat, expr, true);
-                self.ret_vars.clear();
-            });
-        } else {
-            // This would set arguments used in closure that does not have side-effect.
-            // Closure itself can be detected whether there is a side-effect, but the
-            // value of variable that is holding closure can change.
-            // So, we just check the variables.
-            self.ret_vars = args
-                .iter()
-                .flat_map(|expr| {
-                    self.visit_expr(expr);
-                    std::mem::take(&mut self.ret_vars)
-                })
-                .collect_vec()
-                .into_iter()
-                .map(|id| {
-                    self.has_side_effect.insert(id.0);
-                    id
-                })
-                .collect();
-            self.contains_side_effect = true;
+        // `skip_params` is either `0` or `1` to skip the `self` parameter in trait functions.
+        // It can't be renamed, and it can't be removed without removing it from multiple functions.
+        let (fn_id, fn_kind, skip_params) = match get_parent_node(cx.tcx, body.value.hir_id) {
+            Some(Node::Item(i)) => (i.def_id.to_def_id(), FnKind::Fn, 0),
+            Some(Node::TraitItem(&TraitItem {
+                kind: TraitItemKind::Fn(ref sig, _),
+                def_id,
+                ..
+            })) => (
+                def_id.to_def_id(),
+                FnKind::TraitFn,
+                if sig.decl.implicit_self.has_implicit_self() {
+                    1
+                } else {
+                    0
+                },
+            ),
+            Some(Node::ImplItem(&ImplItem {
+                kind: ImplItemKind::Fn(ref sig, _),
+                def_id,
+                ..
+            })) => {
+                #[allow(trivial_casts)]
+                if let Some(Node::Item(item)) = get_parent_node(cx.tcx, cx.tcx.hir().local_def_id_to_hir_id(def_id))
+                    && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.def_id)
+                    && let Some(trait_item_id) = cx.tcx.associated_item(def_id).trait_item_def_id
+                {
+                    (
+                        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
+                        },
+                    )
+                } else {
+                    (def_id.to_def_id(), FnKind::Fn, 0)
+                }
+            },
+            _ => return,
+        };
+        body.params
+            .iter()
+            .enumerate()
+            .skip(skip_params)
+            .filter_map(|(idx, p)| match p.pat.kind {
+                PatKind::Binding(_, id, ident, None) if !ident.as_str().starts_with('_') => {
+                    Some((id, Param::new(fn_id, fn_kind, idx, ident)))
+                },
+                _ => None,
+            })
+            .for_each(|(id, param)| self.params.insert(param, id));
+        if self.entered_body.is_none() {
+            self.entered_body = Some(body.value.hir_id);
         }
-
-        self.ret_vars.append(&mut ret_vars);
     }
 
-    fn visit_method_call(&mut self, path: &'tcx PathSegment<'tcx>, args: &'tcx [Expr<'tcx>]) {
-        if_chain! {
-            if self.is_method;
-            if path.ident == self.fn_ident;
-            if let ExprKind::Path(QPath::Resolved(_, path)) = args.first().unwrap().kind;
-            if let Res::Local(..) = path.res;
-            let ident = path.segments.last().unwrap().ident;
-            if ident.name == kw::SelfLower;
-            then {
-                izip!(self.params.clone(), args.iter())
-                    .for_each(|(pat, expr)| {
-                        self.visit_pat_expr(pat, expr, true);
-                        self.ret_vars.clear();
-                    });
-            } else {
-                self.ret_vars = args
-                    .iter()
-                    .flat_map(|expr| {
-                        self.visit_expr(expr);
-                        std::mem::take(&mut self.ret_vars)
-                    })
-                    .collect_vec()
-                    .into_iter()
-                    .map(|a| {
-                        self.has_side_effect.insert(a.0);
-                        a
-                    })
-                    .collect();
-                self.contains_side_effect = true;
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) {
+        if let Some(id) = path_to_local(e)
+            && let Some(param) = self.params.get_by_id_mut(id)
+        {
+            let typeck = cx.typeck_results();
+            let span = e.span;
+            let mut e = e;
+            loop {
+                match get_expr_use_or_unification_node(cx.tcx, e) {
+                    None | Some((Node::Stmt(_), _)) => return,
+                    Some((Node::Expr(parent), child_id)) => match parent.kind {
+                        // Recursive call. Track which index the parameter is used in.
+                        ExprKind::Call(callee, args)
+                            if path_def_id(cx, callee).map_or(false, |id| {
+                                id == param.fn_id
+                                    && has_matching_substs(param.fn_kind, typeck.node_substs(callee.hir_id))
+                            }) =>
+                        {
+                            if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) {
+                                param.uses.push(Usage::new(span, idx));
+                            }
+                            return;
+                        },
+                        ExprKind::MethodCall(_, args, _)
+                            if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| {
+                                id == param.fn_id
+                                    && has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id))
+                            }) =>
+                        {
+                            if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) {
+                                param.uses.push(Usage::new(span, idx));
+                            }
+                            return;
+                        },
+                        // Assignment to a parameter is fine.
+                        ExprKind::Assign(lhs, _, _) | ExprKind::AssignOp(_, lhs, _) if lhs.hir_id == child_id => {
+                            return;
+                        },
+                        // Parameter update e.g. `x = x + 1`
+                        ExprKind::Assign(lhs, rhs, _) | ExprKind::AssignOp(_, lhs, rhs)
+                            if rhs.hir_id == child_id && path_to_local_id(lhs, id) =>
+                        {
+                            return;
+                        },
+                        // Side-effect free expressions. Walk to the parent expression.
+                        ExprKind::Binary(_, lhs, rhs)
+                            if typeck.expr_ty(lhs).is_primitive() && typeck.expr_ty(rhs).is_primitive() =>
+                        {
+                            e = parent;
+                            continue;
+                        },
+                        ExprKind::Unary(_, arg) if typeck.expr_ty(arg).is_primitive() => {
+                            e = parent;
+                            continue;
+                        },
+                        ExprKind::AddrOf(..) | ExprKind::Cast(..) => {
+                            e = parent;
+                            continue;
+                        },
+                        // Only allow field accesses without auto-deref
+                        ExprKind::Field(..) if typeck.adjustments().get(child_id).is_none() => {
+                            e = parent;
+                            continue
+                        }
+                        _ => (),
+                    },
+                    _ => (),
+                }
+                self.params.remove_by_id(id);
+                return;
             }
         }
     }
 
-    fn visit_if(&mut self, bind: &'tcx Expr<'tcx>, then_expr: &'tcx Expr<'tcx>, else_expr: Option<&'tcx Expr<'tcx>>) {
-        let contains_side_effect = self.contains_side_effect;
-        self.contains_side_effect = false;
-        self.visit_expr(bind);
-        let mut vars = std::mem::take(&mut self.ret_vars);
-        self.visit_expr(then_expr);
-        let mut then_vars = std::mem::take(&mut self.ret_vars);
-        walk_list!(self, visit_expr, else_expr);
-        if self.contains_side_effect {
-            self.add_side_effect(vars.clone());
-        }
-        self.contains_side_effect |= contains_side_effect;
-        self.ret_vars.append(&mut vars);
-        self.ret_vars.append(&mut then_vars);
-    }
-
-    fn visit_match(&mut self, expr: &'tcx Expr<'tcx>, arms: &'tcx [Arm<'tcx>]) {
-        self.visit_expr(expr);
-        let mut expr_vars = std::mem::take(&mut self.ret_vars);
-        self.ret_vars = arms
-            .iter()
-            .flat_map(|arm| {
-                let contains_side_effect = self.contains_side_effect;
-                self.contains_side_effect = false;
-                // this would visit `expr` multiple times
-                // but couldn't think of a better way
-                self.visit_pat_expr(arm.pat, expr, false);
-                let mut vars = std::mem::take(&mut self.ret_vars);
-                let _ = arm.guard.as_ref().map(|guard| {
-                    self.visit_expr(match guard {
-                        Guard::If(expr) | Guard::IfLet(Let { init: expr, .. }) => expr,
-                    });
-                    vars.append(&mut self.ret_vars);
-                });
-                self.visit_expr(arm.body);
-                if self.contains_side_effect {
-                    self.add_side_effect(vars.clone());
-                    self.add_side_effect(expr_vars.clone());
+    fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
+        if self.entered_body == Some(body.value.hir_id) {
+            self.entered_body = None;
+            self.params.flag_for_linting();
+            for param in &self.params.params {
+                if param.apply_lint.get() {
+                    span_lint_and_then(
+                        cx,
+                        ONLY_USED_IN_RECURSION,
+                        param.ident.span,
+                        "parameter is only used in recursion",
+                        |diag| {
+                            if param.ident.name != kw::SelfLower {
+                                diag.span_suggestion(
+                                    param.ident.span,
+                                    "if this is intentional, prefix it with an underscore",
+                                    format!("_{}", param.ident.name),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                            diag.span_note(
+                                param.uses.iter().map(|x| x.span).collect::<Vec<_>>(),
+                                "parameter used here",
+                            );
+                        },
+                    );
                 }
-                self.contains_side_effect |= contains_side_effect;
-                vars.append(&mut self.ret_vars);
-                vars
-            })
-            .collect();
-        self.ret_vars.append(&mut expr_vars);
-    }
-
-    fn connect_assign(&mut self, lhs: &[(HirId, bool)], rhs: &[(HirId, bool)], connect_self: bool) {
-        // if mutable dereference is on assignment it can have side-effect
-        // (this can lead to parameter mutable dereference and change the original value)
-        // too hard to detect whether this value is from parameter, so this would all
-        // check mutable dereference assignment to side effect
-        lhs.iter().filter(|(_, b)| *b).for_each(|(id, _)| {
-            self.has_side_effect.insert(*id);
-            self.contains_side_effect = true;
-        });
-
-        // there is no connection
-        if lhs.is_empty() || rhs.is_empty() {
-            return;
-        }
-
-        // by connected rhs in cycle, the connections would decrease
-        // from `n * m` to `n + m`
-        // where `n` and `m` are length of `lhs` and `rhs`.
-
-        // unwrap is possible since rhs is not empty
-        let rhs_first = rhs.first().unwrap();
-        for (id, _) in lhs.iter() {
-            if connect_self || *id != rhs_first.0 {
-                self.graph
-                    .entry(*id)
-                    .or_insert_with(FxHashSet::default)
-                    .insert(rhs_first.0);
             }
+            self.params.clear();
         }
-
-        let rhs = rhs.iter();
-        izip!(rhs.clone().cycle().skip(1), rhs).for_each(|(from, to)| {
-            if connect_self || from.0 != to.0 {
-                self.graph.entry(from.0).or_insert_with(FxHashSet::default).insert(to.0);
-            }
-        });
     }
+}
 
-    fn add_side_effect(&mut self, v: Vec<(HirId, bool)>) {
-        for (id, _) in v {
-            self.has_side_effect.insert(id);
-            self.contains_side_effect = true;
-        }
+fn has_matching_substs(kind: FnKind, substs: SubstsRef<'_>) -> bool {
+    match kind {
+        FnKind::Fn => true,
+        FnKind::TraitFn => substs.iter().enumerate().all(|(idx, subst)| match subst.unpack() {
+            GenericArgKind::Lifetime(_) => true,
+            GenericArgKind::Type(ty) => matches!(*ty.kind(), ty::Param(ty) if ty.index as usize == idx),
+            GenericArgKind::Const(c) => matches!(c.kind(), ConstKind::Param(c) if c.index as usize == idx),
+        }),
+        #[allow(trivial_casts)]
+        FnKind::ImplTraitFn(expected_substs) => substs as *const _ as usize == expected_substs,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/open_options.rs b/src/tools/clippy/clippy_lints/src/open_options.rs
deleted file mode 100644 (file)
index 5a0b504..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-use clippy_utils::diagnostics::span_lint;
-use clippy_utils::paths;
-use clippy_utils::ty::match_type;
-use rustc_ast::ast::LitKind;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::{Span, Spanned};
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// use std::fs::OpenOptions;
-    ///
-    /// OpenOptions::new().read(true).truncate(true);
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub NONSENSICAL_OPEN_OPTIONS,
-    correctness,
-    "nonsensical combination of options for opening a file"
-}
-
-declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]);
-
-impl<'tcx> LateLintPass<'tcx> for OpenOptions {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::MethodCall(path, [self_arg, ..], _) = &e.kind {
-            let obj_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
-            if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {
-                let mut options = Vec::new();
-                get_open_options(cx, self_arg, &mut options);
-                check_open_options(cx, &options, e.span);
-            }
-        }
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-enum Argument {
-    True,
-    False,
-    Unknown,
-}
-
-#[derive(Debug)]
-enum OpenOption {
-    Write,
-    Read,
-    Truncate,
-    Create,
-    Append,
-}
-
-fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
-    if let ExprKind::MethodCall(path, arguments, _) = argument.kind {
-        let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).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() >= 2 {
-            let argument_option = match arguments[1].kind {
-                ExprKind::Lit(ref span) => {
-                    if let Spanned {
-                        node: LitKind::Bool(lit),
-                        ..
-                    } = *span
-                    {
-                        if lit { Argument::True } else { Argument::False }
-                    } else {
-                        // The function is called with a literal which is not a boolean literal.
-                        // This is theoretically possible, but not very likely.
-                        return;
-                    }
-                },
-                _ => Argument::Unknown,
-            };
-
-            match path.ident.as_str() {
-                "create" => {
-                    options.push((OpenOption::Create, argument_option));
-                },
-                "append" => {
-                    options.push((OpenOption::Append, argument_option));
-                },
-                "truncate" => {
-                    options.push((OpenOption::Truncate, argument_option));
-                },
-                "read" => {
-                    options.push((OpenOption::Read, argument_option));
-                },
-                "write" => {
-                    options.push((OpenOption::Write, argument_option));
-                },
-                _ => (),
-            }
-
-            get_open_options(cx, &arguments[0], options);
-        }
-    }
-}
-
-fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], span: Span) {
-    let (mut create, mut append, mut truncate, mut read, mut write) = (false, false, false, false, false);
-    let (mut create_arg, mut append_arg, mut truncate_arg, mut read_arg, mut write_arg) =
-        (false, false, false, false, false);
-    // This code is almost duplicated (oh, the irony), but I haven't found a way to
-    // unify it.
-
-    for option in options {
-        match *option {
-            (OpenOption::Create, arg) => {
-                if create {
-                    span_lint(
-                        cx,
-                        NONSENSICAL_OPEN_OPTIONS,
-                        span,
-                        "the method `create` is called more than once",
-                    );
-                } else {
-                    create = true;
-                }
-                create_arg = create_arg || (arg == Argument::True);
-            },
-            (OpenOption::Append, arg) => {
-                if append {
-                    span_lint(
-                        cx,
-                        NONSENSICAL_OPEN_OPTIONS,
-                        span,
-                        "the method `append` is called more than once",
-                    );
-                } else {
-                    append = true;
-                }
-                append_arg = append_arg || (arg == Argument::True);
-            },
-            (OpenOption::Truncate, arg) => {
-                if truncate {
-                    span_lint(
-                        cx,
-                        NONSENSICAL_OPEN_OPTIONS,
-                        span,
-                        "the method `truncate` is called more than once",
-                    );
-                } else {
-                    truncate = true;
-                }
-                truncate_arg = truncate_arg || (arg == Argument::True);
-            },
-            (OpenOption::Read, arg) => {
-                if read {
-                    span_lint(
-                        cx,
-                        NONSENSICAL_OPEN_OPTIONS,
-                        span,
-                        "the method `read` is called more than once",
-                    );
-                } else {
-                    read = true;
-                }
-                read_arg = read_arg || (arg == Argument::True);
-            },
-            (OpenOption::Write, arg) => {
-                if write {
-                    span_lint(
-                        cx,
-                        NONSENSICAL_OPEN_OPTIONS,
-                        span,
-                        "the method `write` is called more than once",
-                    );
-                } else {
-                    write = true;
-                }
-                write_arg = write_arg || (arg == Argument::True);
-            },
-        }
-    }
-
-    if read && truncate && read_arg && truncate_arg && !(write && write_arg) {
-        span_lint(
-            cx,
-            NONSENSICAL_OPEN_OPTIONS,
-            span,
-            "file opened with `truncate` and `read`",
-        );
-    }
-    if append && truncate && append_arg && truncate_arg {
-        span_lint(
-            cx,
-            NONSENSICAL_OPEN_OPTIONS,
-            span,
-            "file opened with `append` and `truncate`",
-        );
-    }
-}
index 44f153cffac511401f43c871690590fd3d29da43..9602d0d1d2ea1a725963b38f8762a4744c2c4328 100644 (file)
@@ -1,21 +1,22 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{
     can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_lang_ctor, peel_blocks,
     peel_hir_expr_while, CaptureKind,
 };
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::LangItem::OptionSome;
-use rustc_hir::{def::Res, BindingAnnotation, Expr, ExprKind, Mutability, PatKind, Path, QPath, UnOp};
+use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
+use rustc_hir::{
+    def::Res, Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Lints usage of `if let Some(v) = ... { y } else { x }` which is more
+    /// 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).
     /// } else {
     ///     5
     /// };
+    /// let _ = match optional {
+    ///     Some(val) => val + 1,
+    ///     None => 5
+    /// };
     /// let _ = if let Some(foo) = optional {
     ///     foo
     /// } else {
     /// # let optional: Option<u32> = Some(0);
     /// # fn do_complicated_function() -> u32 { 5 };
     /// 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);
     /// ```
+    // FIXME: Before moving this lint out of nursery, the lint name needs to be updated. It now also
+    // covers matches and `Result`.
     #[clippy::version = "1.47.0"]
     pub OPTION_IF_LET_ELSE,
     nursery,
 
 declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]);
 
-/// Returns true iff the given expression is the result of calling `Result::ok`
-fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
-    if let ExprKind::MethodCall(path, &[ref receiver], _) = &expr.kind {
-        path.ident.name.as_str() == "ok"
-            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::Result)
-    } else {
-        false
-    }
-}
-
-/// A struct containing information about occurrences of the
-/// `if let Some(..) = .. else` construct that this lint detects.
-struct OptionIfLetElseOccurrence {
+/// A struct containing information about occurrences of construct that this lint detects
+///
+/// Such as:
+///
+/// ```ignore
+/// if let Some(..) = {..} else {..}
+/// ```
+/// or
+/// ```ignore
+/// match x {
+///     Some(..) => {..},
+///     None/_ => {..}
+/// }
+/// ```
+struct OptionOccurence {
     option: String,
     method_sugg: String,
     some_expr: String,
@@ -99,43 +109,38 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo
     )
 }
 
-/// If this expression is the option if let/else construct we're detecting, then
-/// this function returns an `OptionIfLetElseOccurrence` struct with details if
-/// this construct is found, or None if this construct is not found.
-fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionIfLetElseOccurrence> {
+fn try_get_option_occurence<'tcx>(
+    cx: &LateContext<'tcx>,
+    pat: &Pat<'tcx>,
+    expr: &Expr<'_>,
+    if_then: &'tcx Expr<'_>,
+    if_else: &'tcx Expr<'_>,
+) -> Option<OptionOccurence> {
+    let cond_expr = match expr.kind {
+        ExprKind::Unary(UnOp::Deref, inner_expr) | ExprKind::AddrOf(_, _, inner_expr) => inner_expr,
+        _ => expr,
+    };
+    let inner_pat = try_get_inner_pat(cx, pat)?;
     if_chain! {
-        if !expr.span.from_expansion(); // Don't lint macros, because it behaves weirdly
-        if !in_constant(cx, expr.hir_id);
-        if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) })
-            = higher::IfLet::hir(cx, expr);
-        if !is_else_clause(cx.tcx, expr);
-        if !is_result_ok(cx, let_expr); // Don't lint on Result::ok because a different lint does it already
-        if let PatKind::TupleStruct(struct_qpath, [inner_pat], _) = &let_pat.kind;
-        if is_lang_ctor(cx, struct_qpath, OptionSome);
-        if let PatKind::Binding(bind_annotation, _, id, None) = &inner_pat.kind;
+        if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind;
         if let Some(some_captures) = can_move_expr_to_closure(cx, if_then);
         if let Some(none_captures) = can_move_expr_to_closure(cx, if_else);
         if some_captures
             .iter()
             .filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2)))
             .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref());
-
         then {
-            let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
+            let capture_mut = if bind_annotation == BindingAnnotation::Mutable { "mut " } else { "" };
             let some_body = peel_blocks(if_then);
             let none_body = peel_blocks(if_else);
             let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" };
             let capture_name = id.name.to_ident_string();
-            let (as_ref, as_mut) = match &let_expr.kind {
+            let (as_ref, as_mut) = match &expr.kind {
                 ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
                 ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
-                _ => (bind_annotation == &BindingAnnotation::Ref, bind_annotation == &BindingAnnotation::RefMut),
-            };
-            let cond_expr = match let_expr.kind {
-                // Pointer dereferencing happens automatically, so we can omit it in the suggestion
-                ExprKind::Unary(UnOp::Deref, expr) | ExprKind::AddrOf(_, _, expr) => expr,
-                _ => let_expr,
+                _ => (bind_annotation == BindingAnnotation::Ref, bind_annotation == BindingAnnotation::RefMut),
             };
+
             // Check if captures the closure will need conflict with borrows made in the scrutinee.
             // TODO: check all the references made in the scrutinee expression. This will require interacting
             // with the borrow checker. Currently only `<local>[.<field>]*` is checked for.
@@ -154,30 +159,100 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
                     }
                 }
             }
-            Some(OptionIfLetElseOccurrence {
+
+            return Some(OptionOccurence {
                 option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut),
                 method_sugg: method_sugg.to_string(),
                 some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir_with_macro_callsite(cx, some_body, "..")),
                 none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir_with_macro_callsite(cx, none_body, "..")),
-            })
+            });
+        }
+    }
+
+    None
+}
+
+fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&'tcx Pat<'tcx>> {
+    if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind {
+        if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk) {
+            return Some(inner_pat);
+        }
+    }
+    None
+}
+
+/// If this expression is the option if let/else construct we're detecting, then
+/// this function returns an `OptionOccurence` struct with details if
+/// this construct is found, or None if this construct is not found.
+fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionOccurence> {
+    if let Some(higher::IfLet {
+        let_pat,
+        let_expr,
+        if_then,
+        if_else: Some(if_else),
+    }) = higher::IfLet::hir(cx, expr)
+    {
+        if !is_else_clause(cx.tcx, expr) {
+            return try_get_option_occurence(cx, let_pat, let_expr, if_then, if_else);
+        }
+    }
+    None
+}
+
+fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionOccurence> {
+    if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
+        if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) {
+            return try_get_option_occurence(cx, let_pat, ex, if_then, if_else);
+        }
+    }
+    None
+}
+
+fn try_convert_match<'tcx>(
+    cx: &LateContext<'tcx>,
+    arms: &[Arm<'tcx>],
+) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
+    if arms.len() == 2 {
+        return if is_none_or_err_arm(cx, &arms[1]) {
+            Some((arms[0].pat, arms[0].body, arms[1].body))
+        } else if is_none_or_err_arm(cx, &arms[0]) {
+            Some((arms[1].pat, arms[1].body, arms[0].body))
         } else {
             None
-        }
+        };
+    }
+    None
+}
+
+fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
+    match arm.pat.kind {
+        PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
+        PatKind::TupleStruct(ref qpath, [first_pat], _) => {
+            is_lang_ctor(cx, qpath, ResultErr) && matches!(first_pat.kind, PatKind::Wild)
+        },
+        PatKind::Wild => true,
+        _ => false,
     }
 }
 
 impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
-        if let Some(detection) = detect_option_if_let_else(cx, expr) {
+        // Don't lint macros and constants
+        if expr.span.from_expansion() || in_constant(cx, expr.hir_id) {
+            return;
+        }
+
+        let detection = detect_option_if_let_else(cx, expr).or_else(|| detect_option_match(cx, expr));
+        if let Some(det) = detection {
             span_lint_and_sugg(
                 cx,
                 OPTION_IF_LET_ELSE,
                 expr.span,
-                format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(),
+                format!("use Option::{} instead of an if let/else", det.method_sugg).as_str(),
                 "try",
                 format!(
                     "{}.{}({}, {})",
-                    detection.option, detection.method_sugg, detection.none_expr, detection.some_expr,
+                    det.option, det.method_sugg, det.none_expr, det.some_expr
                 ),
                 Applicability::MaybeIncorrect,
             );
index eee7642068d6237bebe5fdcae8b91624fe40518b..000b0ba7a148e75e503dd9f73ca2061ead430189 100644 (file)
@@ -53,7 +53,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 
         // If the expression is a literal `Option::None`
         let is_none_ctor = |expr: &Expr<'_>| {
-            matches!(&peel_hir_expr_refs(expr).0.kind,
+            !expr.span.from_expansion()
+                && matches!(&peel_hir_expr_refs(expr).0.kind,
             ExprKind::Path(p) if is_lang_ctor(cx, p, LangItem::OptionNone))
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
deleted file mode 100644 (file)
index bc6a918..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::sym;
-use std::path::{Component, Path};
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// use std::path::PathBuf;
-    ///
-    /// let mut x = PathBuf::from("/foo");
-    /// x.push("/bar");
-    /// assert_eq!(x, PathBuf::from("/bar"));
-    /// ```
-    /// Could be written:
-    ///
-    /// ```rust
-    /// use std::path::PathBuf;
-    ///
-    /// let mut x = PathBuf::from("/foo");
-    /// x.push("bar");
-    /// assert_eq!(x, PathBuf::from("/foo/bar"));
-    /// ```
-    #[clippy::version = "1.36.0"]
-    pub PATH_BUF_PUSH_OVERWRITE,
-    nursery,
-    "calling `push` with file system root on `PathBuf` can overwrite it"
-}
-
-declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]);
-
-impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let ExprKind::MethodCall(path, [recv, get_index_arg], _) = expr.kind;
-            if path.ident.name == sym!(push);
-            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::PathBuf);
-            if let ExprKind::Lit(ref lit) = get_index_arg.kind;
-            if let LitKind::Str(ref path_lit, _) = lit.node;
-            if let pushed_path = Path::new(path_lit.as_str());
-            if let Some(pushed_path_lit) = pushed_path.to_str();
-            if pushed_path.has_root();
-            if let Some(root) = pushed_path.components().next();
-            if root == Component::RootDir;
-            then {
-                span_lint_and_sugg(
-                    cx,
-                    PATH_BUF_PUSH_OVERWRITE,
-                    lit.span,
-                    "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition",
-                    "try",
-                    format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-    }
-}
index 964a057f00d32e5c1da41c7a4d1b7a3525710f0c..b432ccb1ee32dd675d054de109fd3ec690fe80f8 100644 (file)
@@ -123,7 +123,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
         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::Binding(annot, bind_id, ident, _) = field.kind;
+        if let PatKind::Binding(annot, 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);
         if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id))
index fbf842c339e4906b3fff22a5e3a2d608bc40e047..490f345d2970777634c6554ec54cbb5fd5c040cb 100644 (file)
@@ -1,46 +1,20 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::higher;
 use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local};
-use clippy_utils::{higher, SpanlessEq};
 use if_chain::if_chain;
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, PathSegment, QPath};
+use rustc_hir::{BinOpKind, Expr, ExprKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{Span, Spanned};
-use rustc_span::sym;
 use std::cmp::Ordering;
 
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// # let x = vec![1];
-    /// let _ = x.iter().zip(0..x.len());
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust
-    /// # let x = vec![1];
-    /// let _ = x.iter().enumerate();
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub RANGE_ZIP_WITH_LEN,
-    complexity,
-    "zipping iterator with a range when `enumerate()` would do"
-}
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for exclusive ranges where 1 is added to the
@@ -198,7 +172,6 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 }
 
 impl_lint_pass!(Ranges => [
-    RANGE_ZIP_WITH_LEN,
     RANGE_PLUS_ONE,
     RANGE_MINUS_ONE,
     REVERSED_EMPTY_RANGES,
@@ -207,16 +180,10 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 impl<'tcx> LateLintPass<'tcx> for Ranges {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        match expr.kind {
-            ExprKind::MethodCall(path, args, _) => {
-                check_range_zip_with_len(cx, path, args, expr.span);
-            },
-            ExprKind::Binary(ref op, l, r) => {
-                if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
-                    check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
-                }
-            },
-            _ => {},
+        if let ExprKind::Binary(ref op, l, r) = expr.kind {
+            if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
+                check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
+            }
         }
 
         check_exclusive_range_plus_one(cx, expr);
@@ -380,34 +347,6 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R
     None
 }
 
-fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) {
-    if_chain! {
-        if path.ident.as_str() == "zip";
-        if let [iter, zip_arg] = args;
-        // `.iter()` call
-        if let ExprKind::MethodCall(iter_path, [iter_caller, ..], _) = iter.kind;
-        if iter_path.ident.name == sym::iter;
-        // range expression in `.zip()` call: `0..x.len()`
-        if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
-        if is_integer_const(cx, start, 0);
-        // `.len()` call
-        if let ExprKind::MethodCall(len_path, [len_caller], _) = end.kind;
-        if len_path.ident.name == sym::len;
-        // `.iter()` and `.len()` called on same `Path`
-        if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_caller.kind;
-        if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_caller.kind;
-        if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
-        then {
-            span_lint(cx,
-                RANGE_ZIP_WITH_LEN,
-                span,
-                &format!("it is more idiomatic to use `{}.iter().enumerate()`",
-                    snippet(cx, iter_caller.span, "_"))
-            );
-        }
-    }
-}
-
 // exclusive range plus one: `x..(y+1)`
 fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
index 8db8c4e9b7870117d71022f7baa10809ab1c6bbf..e82aa3a7b9897dd751a40aa5c8a4f59e4de247b6 100644 (file)
@@ -41,7 +41,7 @@
     /// let data = std::rc::Rc::new("some data".to_string());
     /// let v = vec![data; 100];
     /// ```
-    #[clippy::version = "1.62.0"]
+    #[clippy::version = "1.63.0"]
     pub RC_CLONE_IN_VEC_INIT,
     suspicious,
     "initializing reference-counted pointer in `vec![elem; len]`"
index db6c97f3739c74068a74e4b26ca4e9f80aae964c..8693ca9af83003f2492158e481fae972649e5276 100644 (file)
@@ -11,6 +11,8 @@
 use rustc_middle::ty::subst::GenericArg;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
+use std::iter;
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for redundant slicing expressions which use the full range, and
@@ -134,7 +136,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 } else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
                     if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
                         cx.param_env,
-                        cx.tcx.mk_projection(target_id, cx.tcx.mk_substs([GenericArg::from(indexed_ty)].into_iter())),
+                        cx.tcx.mk_projection(target_id, cx.tcx.mk_substs(iter::once(GenericArg::from(indexed_ty)))),
                     ) {
                         if deref_ty == expr_ty {
                             let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
index f8801f769e83d6cc2dddd94abac1f4bbc2f10da8..2d751c274679f9b64eef70d1b8af54d45bd7aad6 100644 (file)
@@ -48,15 +48,15 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 impl RedundantStaticLifetimes {
     // Recursively visit types
-    fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
+    fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
         match ty.kind {
             // Be careful of nested structures (arrays and tuples)
             TyKind::Array(ref ty, _) | TyKind::Slice(ref ty) => {
-                self.visit_type(ty, cx, reason);
+                Self::visit_type(ty, cx, reason);
             },
             TyKind::Tup(ref tup) => {
                 for tup_ty in tup {
-                    self.visit_type(tup_ty, cx, reason);
+                    Self::visit_type(tup_ty, cx, reason);
                 }
             },
             // This is what we are looking for !
@@ -87,7 +87,7 @@ fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
                         _ => {},
                     }
                 }
-                self.visit_type(&borrow_type.ty, cx, reason);
+                Self::visit_type(&borrow_type.ty, cx, reason);
             },
             _ => {},
         }
@@ -102,13 +102,13 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
 
         if !item.span.from_expansion() {
             if let ItemKind::Const(_, ref var_type, _) = item.kind {
-                self.visit_type(var_type, cx, "constants have by default a `'static` lifetime");
+                Self::visit_type(var_type, cx, "constants have by default a `'static` lifetime");
                 // Don't check associated consts because `'static` cannot be elided on those (issue
                 // #2438)
             }
 
             if let ItemKind::Static(ref var_type, _, _) = item.kind {
-                self.visit_type(var_type, cx, "statics have by default a `'static` lifetime");
+                Self::visit_type(var_type, cx, "statics have by default a `'static` lifetime");
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/repeat_once.rs b/src/tools/clippy/clippy_lints/src/repeat_once.rs
deleted file mode 100644 (file)
index 898c70a..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-use clippy_utils::consts::{constant_context, Constant};
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// fn main() {
-    ///     let x = String::from("hello world").repeat(1);
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// fn main() {
-    ///     let x = String::from("hello world").clone();
-    /// }
-    /// ```
-    #[clippy::version = "1.47.0"]
-    pub REPEAT_ONCE,
-    complexity,
-    "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
-}
-
-declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]);
-
-impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let ExprKind::MethodCall(path, [receiver, count], _) = &expr.kind;
-            if path.ident.name == sym!(repeat);
-            if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1));
-            if !receiver.span.from_expansion();
-            then {
-                let ty = cx.typeck_results().expr_ty(receiver).peel_refs();
-                if ty.is_str() {
-                    span_lint_and_sugg(
-                        cx,
-                        REPEAT_ONCE,
-                        expr.span,
-                        "calling `repeat(1)` on str",
-                        "consider using `.to_string()` instead",
-                        format!("{}.to_string()", snippet(cx, receiver.span, r#""...""#)),
-                        Applicability::MachineApplicable,
-                    );
-                } else if ty.builtin_index().is_some() {
-                    span_lint_and_sugg(
-                        cx,
-                        REPEAT_ONCE,
-                        expr.span,
-                        "calling `repeat(1)` on slice",
-                        "consider using `.to_vec()` instead",
-                        format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)),
-                        Applicability::MachineApplicable,
-                    );
-                } else if is_type_diagnostic_item(cx, ty, sym::String) {
-                    span_lint_and_sugg(
-                        cx,
-                        REPEAT_ONCE,
-                        expr.span,
-                        "calling `repeat(1)` on a string literal",
-                        "consider using `.clone()` instead",
-                        format!("{}.clone()", snippet(cx, receiver.span, r#""...""#)),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-        }
-    }
-}
index 1d9a2abf7066c8819b61a42faacde644a72eb94a..1926661c59603a886b5bfe369532d42df86a497e 100644 (file)
@@ -2,7 +2,6 @@
 use clippy_utils::source::{snippet_opt, snippet_with_context};
 use clippy_utils::{fn_def_id, path_to_local_id};
 use if_chain::if_chain;
-use rustc_ast::ast::Attribute;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind};
@@ -11,7 +10,6 @@
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -152,10 +150,6 @@ fn check_fn(
     }
 }
 
-fn attr_is_cfg(attr: &Attribute) -> bool {
-    attr.meta_item_list().is_some() && attr.has_name(sym::cfg)
-}
-
 fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) {
     if let Some(expr) = block.expr {
         check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty);
@@ -178,9 +172,7 @@ fn check_final_expr<'tcx>(
     match expr.kind {
         // simple return is always "bad"
         ExprKind::Ret(ref inner) => {
-            // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
-            let attrs = cx.tcx.hir().attrs(expr.hir_id);
-            if !attrs.iter().any(attr_is_cfg) {
+            if cx.tcx.hir().attrs(expr.hir_id).is_empty() {
                 let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
                 if !borrows {
                     emit_return_lint(
index d07c26d7c8975da63108f5ec5e9af7efd2ab8ebd..9cea4d8806710a84b9f1980361f0c2e407a64321 100644 (file)
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::return_ty;
-use clippy_utils::ty::{contains_adt_constructor, contains_ty};
+use clippy_utils::ty::contains_adt_constructor;
 use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -66,7 +66,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<
             if !contains_adt_constructor(ret_ty, self_adt) {
                 return;
             }
-        } else if !contains_ty(ret_ty, self_ty) {
+        } else if !ret_ty.contains(self_ty) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
deleted file mode 100644 (file)
index 6d54935..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{is_slice_of_primitives, sugg::Sugg};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// let mut vec = vec![2, 1, 3];
-    /// vec.sort();
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// let mut vec = vec![2, 1, 3];
-    /// vec.sort_unstable();
-    /// ```
-    #[clippy::version = "1.47.0"]
-    pub STABLE_SORT_PRIMITIVE,
-    pedantic,
-    "use of sort() when sort_unstable() is equivalent"
-}
-
-declare_lint_pass!(StableSortPrimitive => [STABLE_SORT_PRIMITIVE]);
-
-/// The three "kinds" of sorts
-enum SortingKind {
-    Vanilla,
-    /* The other kinds of lint are currently commented out because they
-     * can map distinct values to equal ones. If the key function is
-     * provably one-to-one, or if the Cmp function conserves equality,
-     * then they could be linted on, but I don't know if we can check
-     * for that. */
-
-    /* ByKey,
-     * ByCmp, */
-}
-impl SortingKind {
-    /// The name of the stable version of this kind of sort
-    fn stable_name(&self) -> &str {
-        match self {
-            SortingKind::Vanilla => "sort",
-            /* SortingKind::ByKey => "sort_by_key",
-             * SortingKind::ByCmp => "sort_by", */
-        }
-    }
-    /// The name of the unstable version of this kind of sort
-    fn unstable_name(&self) -> &str {
-        match self {
-            SortingKind::Vanilla => "sort_unstable",
-            /* SortingKind::ByKey => "sort_unstable_by_key",
-             * SortingKind::ByCmp => "sort_unstable_by", */
-        }
-    }
-    /// Takes the name of a function call and returns the kind of sort
-    /// that corresponds to that function name (or None if it isn't)
-    fn from_stable_name(name: &str) -> Option<SortingKind> {
-        match name {
-            "sort" => Some(SortingKind::Vanilla),
-            // "sort_by" => Some(SortingKind::ByCmp),
-            // "sort_by_key" => Some(SortingKind::ByKey),
-            _ => None,
-        }
-    }
-}
-
-/// A detected instance of this lint
-struct LintDetection {
-    slice_name: String,
-    method: SortingKind,
-    method_args: String,
-    slice_type: String,
-}
-
-fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintDetection> {
-    if_chain! {
-        if let ExprKind::MethodCall(method_name, [slice, args @ ..], _) = &expr.kind;
-        if let Some(method) = SortingKind::from_stable_name(method_name.ident.name.as_str());
-        if let Some(slice_type) = is_slice_of_primitives(cx, slice);
-        then {
-            let args_str = args.iter().map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", ");
-            Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type })
-        } else {
-            None
-        }
-    }
-}
-
-impl LateLintPass<'_> for StableSortPrimitive {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if let Some(detection) = detect_stable_sort_primitive(cx, expr) {
-            span_lint_and_then(
-                cx,
-                STABLE_SORT_PRIMITIVE,
-                expr.span,
-                format!(
-                    "used `{}` on primitive type `{}`",
-                    detection.method.stable_name(),
-                    detection.slice_type,
-                )
-                .as_str(),
-                |diag| {
-                    diag.span_suggestion(
-                        expr.span,
-                        "try",
-                        format!(
-                            "{}.{}({})",
-                            detection.slice_name,
-                            detection.method.unstable_name(),
-                            detection.method_args,
-                        ),
-                        Applicability::MachineApplicable,
-                    );
-                    diag.note(
-                        "an unstable sort typically performs faster without any observable difference for this data type",
-                    );
-                },
-            );
-        }
-    }
-}
index 0a42a31fb8cf9e0a96dac08ede5a215e3e736880..2ffa022b04f7a4b870e32717c5cd45aa189d23cf 100644 (file)
@@ -4,7 +4,7 @@
 use core::hash::{Hash, Hasher};
 use if_chain::if_chain;
 use itertools::Itertools;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -15,6 +15,7 @@
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{BytePos, Span};
+use std::collections::hash_map::Entry;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -103,7 +104,6 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
     fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
         self.check_type_repetition(cx, gen);
         check_trait_bound_duplication(cx, gen);
-        check_bounds_or_where_duplication(cx, gen);
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
@@ -234,35 +234,61 @@ impl Eq for SpanlessTy<'_, '_> {}
 }
 
 fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
-    if gen.span.from_expansion() || gen.params.is_empty() || gen.predicates.is_empty() {
+    if gen.span.from_expansion() {
         return;
     }
 
-    let mut map = FxHashMap::<_, Vec<_>>::default();
-    for predicate in gen.predicates {
+    // Explanation:
+    // fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+    // where T: Clone + Default, { unimplemented!(); }
+    //       ^^^^^^^^^^^^^^^^^^
+    //       |
+    // collects each of these where clauses into a set keyed by generic name and comparable trait
+    // eg. (T, Clone)
+    let where_predicates = gen
+        .predicates
+        .iter()
+        .filter_map(|pred| {
+            if_chain! {
+                if pred.in_where_clause();
+                if let WherePredicate::BoundPredicate(bound_predicate) = pred;
+                if let TyKind::Path(QPath::Resolved(_, path)) =  bound_predicate.bounded_ty.kind;
+                then {
+                    return Some(
+                        rollup_traits(cx, bound_predicate.bounds, "these where clauses contain repeated elements")
+                        .into_iter().map(|(trait_ref, _)| (path.res, trait_ref)))
+                }
+            }
+            None
+        })
+        .flatten()
+        .collect::<FxHashSet<_>>();
+
+    // Explanation:
+    // fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z) ...
+    //            ^^^^^^^^^^^^^^^^^^  ^^^^^^^
+    //            |
+    // compare trait bounds keyed by generic name and comparable trait to collected where
+    // predicates eg. (T, Clone)
+    for predicate in gen.predicates.iter().filter(|pred| !pred.in_where_clause()) {
         if_chain! {
-            if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
+            if let WherePredicate::BoundPredicate(bound_predicate) = predicate;
             if bound_predicate.origin != PredicateOrigin::ImplTrait;
             if !bound_predicate.span.from_expansion();
-            if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
-            if let Some(segment) = segments.first();
+            if let TyKind::Path(QPath::Resolved(_, path)) =  bound_predicate.bounded_ty.kind;
             then {
-                for (res_where, _, span_where) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
-                    let trait_resolutions_direct = map.entry(segment.ident).or_default();
-                    if let Some((_, span_direct)) = trait_resolutions_direct
-                                                .iter()
-                                                .find(|(res_direct, _)| *res_direct == res_where) {
+                let traits = rollup_traits(cx, bound_predicate.bounds, "these bounds contain repeated elements");
+                for (trait_ref, span) in traits {
+                    let key = (path.res, trait_ref);
+                    if where_predicates.contains(&key) {
                         span_lint_and_help(
                             cx,
                             TRAIT_DUPLICATION_IN_BOUNDS,
-                            *span_direct,
+                            span,
                             "this trait bound is already specified in the where clause",
                             None,
                             "consider removing this trait bound",
-                        );
-                    }
-                    else {
-                        trait_resolutions_direct.push((res_where, span_where));
+                            );
                     }
                 }
             }
@@ -270,23 +296,11 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
     }
 }
 
-#[derive(PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
 struct ComparableTraitRef(Res, Vec<Res>);
-
-fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
-    if gen.span.from_expansion() {
-        return;
-    }
-
-    for predicate in gen.predicates {
-        if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate {
-            let msg = if predicate.in_where_clause() {
-                "these where clauses contain repeated elements"
-            } else {
-                "these bounds contain repeated elements"
-            };
-            rollup_traits(cx, bound_predicate.bounds, msg);
-        }
+impl Default for ComparableTraitRef {
+    fn default() -> Self {
+        Self(Res::Err, Vec::new())
     }
 }
 
@@ -331,7 +345,7 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef {
     )
 }
 
-fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) {
+fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -> Vec<(ComparableTraitRef, Span)> {
     let mut map = FxHashMap::default();
     let mut repeated_res = false;
 
@@ -343,23 +357,33 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) {
         }
     };
 
+    let mut i = 0usize;
     for bound in bounds.iter().filter_map(only_comparable_trait_refs) {
         let (comparable_bound, span_direct) = bound;
-        if map.insert(comparable_bound, span_direct).is_some() {
-            repeated_res = true;
+        match map.entry(comparable_bound) {
+            Entry::Occupied(_) => repeated_res = true,
+            Entry::Vacant(e) => {
+                e.insert((span_direct, i));
+                i += 1;
+            },
         }
     }
 
+    // Put bounds in source order
+    let mut comparable_bounds = vec![Default::default(); map.len()];
+    for (k, (v, i)) in map {
+        comparable_bounds[i] = (k, v);
+    }
+
     if_chain! {
         if repeated_res;
         if let [first_trait, .., last_trait] = bounds;
         then {
             let all_trait_span = first_trait.span().to(last_trait.span());
 
-            let mut traits = map.values()
-                .filter_map(|span| snippet_opt(cx, *span))
+            let traits = comparable_bounds.iter()
+                .filter_map(|&(_, span)| snippet_opt(cx, span))
                 .collect::<Vec<_>>();
-            traits.sort_unstable();
             let traits = traits.join(" + ");
 
             span_lint_and_sugg(
@@ -373,4 +397,6 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) {
             );
         }
     }
+
+    comparable_bounds
 }
index 5f3e98144f42ddfb5ccf9ce5021e652e0369a08d..424a6e9264e4b96680b6e4a09cfab81e2a36083f 100644 (file)
@@ -9,6 +9,7 @@
 mod transmute_ref_to_ref;
 mod transmute_undefined_repr;
 mod transmutes_expressible_as_ptr_casts;
+mod transmuting_null;
 mod unsound_collection_transmute;
 mod useless_transmute;
 mod utils;
     "transmute to or from a type with an undefined representation"
 }
 
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
+    /// ```
+    #[clippy::version = "1.35.0"]
+    pub TRANSMUTING_NULL,
+    correctness,
+    "transmutes from a null pointer to a reference, which is undefined behavior"
+}
+
 pub struct Transmute {
     msrv: Option<RustcVersion>,
 }
@@ -404,6 +427,7 @@ pub struct Transmute {
     UNSOUND_COLLECTION_TRANSMUTE,
     TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
     TRANSMUTE_UNDEFINED_REPR,
+    TRANSMUTING_NULL,
 ]);
 impl Transmute {
     #[must_use]
@@ -436,6 +460,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 
                 let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
                     | crosspointer_transmute::check(cx, e, from_ty, to_ty)
+                    | transmuting_null::check(cx, e, arg, to_ty)
                     | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
                     | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
                     | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
index 20b348fc14f7b12f71823d410cd9f5ae2913c250..b6d7d9f5b42ec2a7c5138163a738ced1b4cb8271 100644 (file)
@@ -5,9 +5,9 @@
 use rustc_lint::LateContext;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy};
-use rustc_span::Span;
+use rustc_span::DUMMY_SP;
 
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     e: &'tcx Expr<'_>,
@@ -18,116 +18,89 @@ pub(super) fn check<'tcx>(
     let mut to_ty = cx.tcx.erase_regions(to_ty_orig);
 
     while from_ty != to_ty {
-        match reduce_refs(cx, e.span, from_ty, to_ty) {
-            ReducedTys::FromFatPtr {
-                unsized_ty,
-                to_ty: to_sub_ty,
-            } => match reduce_ty(cx, to_sub_ty) {
-                ReducedTy::TypeErasure => break,
-                ReducedTy::UnorderedFields(ty) if is_size_pair(ty) => break,
-                ReducedTy::Ref(to_sub_ty) => {
-                    from_ty = unsized_ty;
-                    to_ty = to_sub_ty;
-                    continue;
-                },
-                _ => {
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
-                        |diag| {
-                            if from_ty_orig.peel_refs() != unsized_ty {
-                                diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty));
-                            }
-                        },
-                    );
-                    return true;
-                },
+        let reduced_tys = reduce_refs(cx, from_ty, to_ty);
+        match (reduce_ty(cx, reduced_tys.from_ty), reduce_ty(cx, reduced_tys.to_ty)) {
+            // Various forms of type erasure.
+            (ReducedTy::TypeErasure { raw_ptr_only: false }, _)
+            | (_, ReducedTy::TypeErasure { raw_ptr_only: false }) => return false,
+            (ReducedTy::TypeErasure { .. }, _) if reduced_tys.from_raw_ptr => return false,
+            (_, ReducedTy::TypeErasure { .. }) if reduced_tys.to_raw_ptr => return false,
+
+            // `Repr(C)` <-> unordered type.
+            // If the first field of the `Repr(C)` type matches then the transmute is ok
+            (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::UnorderedFields(to_sub_ty))
+            | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty))) => {
+                from_ty = from_sub_ty;
+                to_ty = to_sub_ty;
+                continue;
             },
-            ReducedTys::ToFatPtr {
-                unsized_ty,
-                from_ty: from_sub_ty,
-            } => match reduce_ty(cx, from_sub_ty) {
-                ReducedTy::TypeErasure => break,
-                ReducedTy::UnorderedFields(ty) if is_size_pair(ty) => break,
-                ReducedTy::Ref(from_sub_ty) => {
-                    from_ty = from_sub_ty;
-                    to_ty = unsized_ty;
-                    continue;
-                },
-                _ => {
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!("transmute to `{}` which has an undefined layout", to_ty_orig),
-                        |diag| {
-                            if to_ty_orig.peel_refs() != unsized_ty {
-                                diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty));
-                            }
-                        },
-                    );
-                    return true;
-                },
+            (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => {
+                from_ty = from_sub_ty;
+                to_ty = to_sub_ty;
+                continue;
             },
-            ReducedTys::ToPtr {
-                from_ty: from_sub_ty,
-                to_ty: to_sub_ty,
-            } => match reduce_ty(cx, from_sub_ty) {
-                ReducedTy::UnorderedFields(from_ty) => {
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
-                        |diag| {
-                            if from_ty_orig.peel_refs() != from_ty {
-                                diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
-                            }
-                        },
-                    );
-                    return true;
-                },
-                ReducedTy::Ref(from_sub_ty) => {
-                    from_ty = from_sub_ty;
-                    to_ty = to_sub_ty;
-                    continue;
-                },
-                _ => break,
+            (ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
+                if reduced_tys.from_fat_ptr =>
+            {
+                from_ty = from_sub_ty;
+                to_ty = to_sub_ty;
+                continue;
             },
-            ReducedTys::FromPtr {
-                from_ty: from_sub_ty,
-                to_ty: to_sub_ty,
-            } => match reduce_ty(cx, to_sub_ty) {
-                ReducedTy::UnorderedFields(to_ty) => {
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!("transmute to `{}` which has an undefined layout", to_ty_orig),
-                        |diag| {
-                            if to_ty_orig.peel_refs() != to_ty {
-                                diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
-                            }
-                        },
-                    );
-                    return true;
-                },
-                ReducedTy::Ref(to_sub_ty) => {
-                    from_ty = from_sub_ty;
-                    to_ty = to_sub_ty;
-                    continue;
-                },
-                _ => break,
+
+            // ptr <-> ptr
+            (ReducedTy::Other(from_sub_ty), ReducedTy::Other(to_sub_ty))
+                if matches!(from_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_))
+                    && matches!(to_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_)) =>
+            {
+                from_ty = from_sub_ty;
+                to_ty = to_sub_ty;
+                continue;
             },
-            ReducedTys::Other {
-                from_ty: from_sub_ty,
-                to_ty: to_sub_ty,
-            } => match (reduce_ty(cx, from_sub_ty), reduce_ty(cx, to_sub_ty)) {
-                (ReducedTy::TypeErasure, _) | (_, ReducedTy::TypeErasure) => return false,
-                (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
-                    let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
+
+            // fat ptr <-> (*size, *size)
+            (ReducedTy::Other(_), ReducedTy::UnorderedFields(to_ty))
+                if reduced_tys.from_fat_ptr && is_size_pair(to_ty) =>
+            {
+                return false;
+            },
+            (ReducedTy::UnorderedFields(from_ty), ReducedTy::Other(_))
+                if reduced_tys.to_fat_ptr && is_size_pair(from_ty) =>
+            {
+                return false;
+            },
+
+            // fat ptr -> some struct | some struct -> fat ptr
+            (ReducedTy::Other(_), _) if reduced_tys.from_fat_ptr => {
+                span_lint_and_then(
+                    cx,
+                    TRANSMUTE_UNDEFINED_REPR,
+                    e.span,
+                    &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
+                    |diag| {
+                        if from_ty_orig.peel_refs() != from_ty.peel_refs() {
+                            diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
+                        }
+                    },
+                );
+                return true;
+            },
+            (_, ReducedTy::Other(_)) if reduced_tys.to_fat_ptr => {
+                span_lint_and_then(
+                    cx,
+                    TRANSMUTE_UNDEFINED_REPR,
+                    e.span,
+                    &format!("transmute to `{}` which has an undefined layout", to_ty_orig),
+                    |diag| {
+                        if to_ty_orig.peel_refs() != to_ty.peel_refs() {
+                            diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
+                        }
+                    },
+                );
+                return true;
+            },
+
+            (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
+                let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
                         = (from_ty.kind(), to_ty.kind())
                         && from_def == to_def
                     {
@@ -138,79 +111,72 @@ pub(super) fn check<'tcx>(
                     } else {
                         None
                     };
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!(
-                            "transmute from `{}` to `{}`, both of which have an undefined layout",
-                            from_ty_orig, to_ty_orig
-                        ),
-                        |diag| {
-                            if let Some(same_adt_did) = same_adt_did {
-                                diag.note(&format!(
-                                    "two instances of the same generic type (`{}`) may have different layouts",
-                                    cx.tcx.item_name(same_adt_did)
-                                ));
-                            } else {
-                                if from_ty_orig.peel_refs() != from_ty {
-                                    diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
-                                }
-                                if to_ty_orig.peel_refs() != to_ty {
-                                    diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
-                                }
-                            }
-                        },
-                    );
-                    return true;
-                },
-                (
-                    ReducedTy::UnorderedFields(from_ty),
-                    ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
-                ) => {
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
-                        |diag| {
+                span_lint_and_then(
+                    cx,
+                    TRANSMUTE_UNDEFINED_REPR,
+                    e.span,
+                    &format!(
+                        "transmute from `{}` to `{}`, both of which have an undefined layout",
+                        from_ty_orig, to_ty_orig
+                    ),
+                    |diag| {
+                        if let Some(same_adt_did) = same_adt_did {
+                            diag.note(&format!(
+                                "two instances of the same generic type (`{}`) may have different layouts",
+                                cx.tcx.item_name(same_adt_did)
+                            ));
+                        } else {
                             if from_ty_orig.peel_refs() != from_ty {
                                 diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
                             }
-                        },
-                    );
-                    return true;
-                },
-                (
-                    ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
-                    ReducedTy::UnorderedFields(to_ty),
-                ) => {
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!("transmute into `{}` which has an undefined layout", to_ty_orig),
-                        |diag| {
                             if to_ty_orig.peel_refs() != to_ty {
                                 diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
                             }
-                        },
-                    );
-                    return true;
-                },
-                (ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => {
-                    from_ty = from_sub_ty;
-                    to_ty = to_sub_ty;
-                    continue;
-                },
-                (
-                    ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
-                    ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
-                )
-                | (
-                    ReducedTy::UnorderedFields(_) | ReducedTy::Param,
-                    ReducedTy::UnorderedFields(_) | ReducedTy::Param,
-                ) => break,
+                        }
+                    },
+                );
+                return true;
+            },
+            (
+                ReducedTy::UnorderedFields(from_ty),
+                ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true },
+            ) => {
+                span_lint_and_then(
+                    cx,
+                    TRANSMUTE_UNDEFINED_REPR,
+                    e.span,
+                    &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
+                    |diag| {
+                        if from_ty_orig.peel_refs() != from_ty {
+                            diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
+                        }
+                    },
+                );
+                return true;
+            },
+            (
+                ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true },
+                ReducedTy::UnorderedFields(to_ty),
+            ) => {
+                span_lint_and_then(
+                    cx,
+                    TRANSMUTE_UNDEFINED_REPR,
+                    e.span,
+                    &format!("transmute into `{}` which has an undefined layout", to_ty_orig),
+                    |diag| {
+                        if to_ty_orig.peel_refs() != to_ty {
+                            diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
+                        }
+                    },
+                );
+                return true;
+            },
+            (
+                ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true },
+                ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true },
+            )
+            | (ReducedTy::UnorderedFields(_), ReducedTy::UnorderedFields(_)) => {
+                break;
             },
         }
     }
@@ -218,64 +184,64 @@ pub(super) fn check<'tcx>(
     false
 }
 
-enum ReducedTys<'tcx> {
-    FromFatPtr { unsized_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
-    ToFatPtr { unsized_ty: Ty<'tcx>, from_ty: Ty<'tcx> },
-    ToPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
-    FromPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
-    Other { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
+#[expect(clippy::struct_excessive_bools)]
+struct ReducedTys<'tcx> {
+    from_ty: Ty<'tcx>,
+    to_ty: Ty<'tcx>,
+    from_raw_ptr: bool,
+    to_raw_ptr: bool,
+    from_fat_ptr: bool,
+    to_fat_ptr: bool,
 }
 
 /// Remove references so long as both types are references.
-fn reduce_refs<'tcx>(
-    cx: &LateContext<'tcx>,
-    span: Span,
-    mut from_ty: Ty<'tcx>,
-    mut to_ty: Ty<'tcx>,
-) -> ReducedTys<'tcx> {
-    loop {
-        return match (from_ty.kind(), to_ty.kind()) {
+fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: Ty<'tcx>) -> ReducedTys<'tcx> {
+    let mut from_raw_ptr = false;
+    let mut to_raw_ptr = false;
+    let (from_fat_ptr, to_fat_ptr) = loop {
+        break match (from_ty.kind(), to_ty.kind()) {
             (
                 &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
                 &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })),
             ) => {
+                from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_));
                 from_ty = from_sub_ty;
+                to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_));
                 to_ty = to_sub_ty;
                 continue;
             },
             (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })), _)
-                if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) =>
+                if !unsized_ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env) =>
             {
-                ReducedTys::FromFatPtr { unsized_ty, to_ty }
+                (true, false)
             },
             (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })))
-                if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) =>
+                if !unsized_ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env) =>
             {
-                ReducedTys::ToFatPtr { unsized_ty, from_ty }
+                (false, true)
             },
-            (&(ty::Ref(_, from_ty, _) | ty::RawPtr(TypeAndMut { ty: from_ty, .. })), _) => {
-                ReducedTys::FromPtr { from_ty, to_ty }
-            },
-            (_, &(ty::Ref(_, to_ty, _) | ty::RawPtr(TypeAndMut { ty: to_ty, .. }))) => {
-                ReducedTys::ToPtr { from_ty, to_ty }
-            },
-            _ => ReducedTys::Other { from_ty, to_ty },
+            _ => (false, false),
         };
+    };
+    ReducedTys {
+        from_ty,
+        to_ty,
+        from_raw_ptr,
+        to_raw_ptr,
+        from_fat_ptr,
+        to_fat_ptr,
     }
 }
 
 enum ReducedTy<'tcx> {
     /// The type can be used for type erasure.
-    TypeErasure,
+    TypeErasure { raw_ptr_only: bool },
     /// The type is a struct containing either zero non-zero sized fields, or multiple non-zero
     /// sized fields with a defined order.
-    OrderedFields(Ty<'tcx>),
+    /// The second value is the first non-zero sized type.
+    OrderedFields(Ty<'tcx>, Option<Ty<'tcx>>),
     /// The type is a struct containing multiple non-zero sized fields with no defined order.
     UnorderedFields(Ty<'tcx>),
-    /// The type is a reference to the contained type.
-    Ref(Ty<'tcx>),
-    /// The type is a generic parameter.
-    Param,
     /// Any other type.
     Other(Ty<'tcx>),
 }
@@ -285,16 +251,18 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
     loop {
         ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty);
         return match *ty.kind() {
-            ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => ReducedTy::TypeErasure,
+            ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => {
+                ReducedTy::TypeErasure { raw_ptr_only: false }
+            },
             ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
                 ty = sub_ty;
                 continue;
             },
-            ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure,
+            ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure { raw_ptr_only: false },
             ty::Tuple(args) => {
                 let mut iter = args.iter();
                 let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
-                    return ReducedTy::OrderedFields(ty);
+                    return ReducedTy::OrderedFields(ty, None);
                 };
                 if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
                     ty = sized_ty;
@@ -309,27 +277,25 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
                     .iter()
                     .map(|f| cx.tcx.bound_type_of(f.did).subst(cx.tcx, substs));
                 let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
-                    return ReducedTy::TypeErasure;
+                    return ReducedTy::TypeErasure { raw_ptr_only: false };
                 };
                 if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
                     ty = sized_ty;
                     continue;
                 }
                 if def.repr().inhibit_struct_field_reordering_opt() {
-                    ReducedTy::OrderedFields(ty)
+                    ReducedTy::OrderedFields(ty, Some(sized_ty))
                 } else {
                     ReducedTy::UnorderedFields(ty)
                 }
             },
             ty::Adt(def, _) if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) => {
-                ReducedTy::TypeErasure
+                ReducedTy::TypeErasure { raw_ptr_only: false }
             },
             // TODO: Check if the conversion to or from at least one of a union's fields is valid.
-            ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure,
-            ty::Foreign(_) => ReducedTy::TypeErasure,
-            ty::Ref(_, ty, _) => ReducedTy::Ref(ty),
-            ty::RawPtr(ty) => ReducedTy::Ref(ty.ty),
-            ty::Param(_) => ReducedTy::Param,
+            ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure { raw_ptr_only: false },
+            ty::Foreign(_) | ty::Param(_) => ReducedTy::TypeErasure { raw_ptr_only: false },
+            ty::Int(_) | ty::Uint(_) => ReducedTy::TypeErasure { raw_ptr_only: true },
             _ => ReducedTy::Other(ty),
         };
     }
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
new file mode 100644 (file)
index 0000000..d8e349a
--- /dev/null
@@ -0,0 +1,61 @@
+use clippy_utils::consts::{constant_context, Constant};
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::is_path_diagnostic_item;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::symbol::sym;
+
+use super::TRANSMUTING_NULL;
+
+const LINT_MSG: &str = "transmuting a known null pointer into a reference";
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, to_ty: Ty<'tcx>) -> bool {
+    if !to_ty.is_ref() {
+        return false;
+    }
+
+    // Catching transmute over constants that resolve to `null`.
+    let mut const_eval_context = constant_context(cx, cx.typeck_results());
+    if_chain! {
+        if let ExprKind::Path(ref _qpath) = arg.kind;
+        if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg);
+        if x == 0;
+        then {
+            span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
+            return true;
+        }
+    }
+
+    // Catching:
+    // `std::mem::transmute(0 as *const i32)`
+    if_chain! {
+        if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind;
+        if let ExprKind::Lit(ref lit) = inner_expr.kind;
+        if let LitKind::Int(0, _) = lit.node;
+        then {
+            span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
+            return true;
+        }
+    }
+
+    // Catching:
+    // `std::mem::transmute(std::ptr::null::<i32>())`
+    if_chain! {
+        if let ExprKind::Call(func1, []) = arg.kind;
+        if is_path_diagnostic_item(cx, func1, sym::ptr_null);
+        then {
+            span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
+            return true;
+        }
+    }
+
+    // FIXME:
+    // Also catch transmutations of variables which are known nulls.
+    // To do this, MIR const propagation seems to be the better tool.
+    // Whenever MIR const prop routines are more developed, this will
+    // become available. As of this writing (25/03/19) it is not yet.
+    false
+}
diff --git a/src/tools/clippy/clippy_lints/src/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmuting_null.rs
deleted file mode 100644 (file)
index 7939dfe..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-use clippy_utils::consts::{constant_context, Constant};
-use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_expr_diagnostic_item;
-use if_chain::if_chain;
-use rustc_ast::LitKind;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::sym;
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
-    /// ```
-    #[clippy::version = "1.35.0"]
-    pub TRANSMUTING_NULL,
-    correctness,
-    "transmutes from a null pointer to a reference, which is undefined behavior"
-}
-
-declare_lint_pass!(TransmutingNull => [TRANSMUTING_NULL]);
-
-const LINT_MSG: &str = "transmuting a known null pointer into a reference";
-
-impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        if_chain! {
-            if let ExprKind::Call(func, [arg]) = expr.kind;
-            if is_expr_diagnostic_item(cx, func, sym::transmute);
-
-            then {
-                // Catching transmute over constants that resolve to `null`.
-                let mut const_eval_context = constant_context(cx, cx.typeck_results());
-                if_chain! {
-                    if let ExprKind::Path(ref _qpath) = arg.kind;
-                    if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg);
-                    if x == 0;
-                    then {
-                        span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
-                    }
-                }
-
-                // Catching:
-                // `std::mem::transmute(0 as *const i32)`
-                if_chain! {
-                    if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind;
-                    if let ExprKind::Lit(ref lit) = inner_expr.kind;
-                    if let LitKind::Int(0, _) = lit.node;
-                    then {
-                        span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
-                    }
-                }
-
-                // Catching:
-                // `std::mem::transmute(std::ptr::null::<i32>())`
-                if_chain! {
-                    if let ExprKind::Call(func1, []) = arg.kind;
-                    if is_expr_diagnostic_item(cx, func1, sym::ptr_null);
-                    then {
-                        span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
-                    }
-                }
-
-                // FIXME:
-                // Also catch transmutations of variables which are known nulls.
-                // To do this, MIR const propagation seems to be the better tool.
-                // Whenever MIR const prop routines are more developed, this will
-                // become available. As of this writing (25/03/19) it is not yet.
-            }
-        }
-    }
-}
index cc64d17be05520feefc3a13d3563e149a8d344de..8980283e5c82634ca1ded1a0a0be6db8672b3094 100644 (file)
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_lint_allowed;
+use clippy_utils::macros::span_is_local;
 use clippy_utils::source::snippet;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -98,6 +99,10 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String {
 }
 
 fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
+    if !span_is_local(span) {
+        return;
+    }
+
     let string = snippet(cx, span, "");
     if string.chars().any(|c| ['\u{200B}', '\u{ad}', '\u{2060}'].contains(&c)) {
         span_lint_and_sugg(
@@ -113,6 +118,7 @@ fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
             Applicability::MachineApplicable,
         );
     }
+
     if string.chars().any(|c| c as u32 > 0x7F) {
         span_lint_and_sugg(
             cx,
@@ -128,6 +134,7 @@ fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
             Applicability::MachineApplicable,
         );
     }
+
     if is_lint_allowed(cx, NON_ASCII_LITERAL, id) && string.chars().zip(string.nfc()).any(|(a, b)| a != b) {
         span_lint_and_sugg(
             cx,
index 9f4c5555f11b7c20489ef384432a6e2e0ebc958b..9a41603f2f4ce1068d6dccbc2e61de037b7d3653 100644 (file)
@@ -45,7 +45,7 @@
     ///    let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
     ///    vec.set_len(1000);  // `MaybeUninit` can be uninitialized
     ///    ```
-    /// 3. If you are on nightly, `Vec::spare_capacity_mut()` is available:
+    /// 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>]`
diff --git a/src/tools/clippy/clippy_lints/src/unit_hash.rs b/src/tools/clippy/clippy_lints/src/unit_hash.rs
deleted file mode 100644 (file)
index 88ca0cb..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// # use std::hash::Hash;
-    /// # use std::collections::hash_map::DefaultHasher;
-    /// # enum Foo { Empty, WithValue(u8) }
-    /// # use Foo::*;
-    /// # let mut state = DefaultHasher::new();
-    /// # let my_enum = Foo::Empty;
-    /// match my_enum {
-    ///        Empty => ().hash(&mut state),
-    ///        WithValue(x) => x.hash(&mut state),
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// # use std::hash::Hash;
-    /// # use std::collections::hash_map::DefaultHasher;
-    /// # enum Foo { Empty, WithValue(u8) }
-    /// # use Foo::*;
-    /// # let mut state = DefaultHasher::new();
-    /// # let my_enum = Foo::Empty;
-    /// match my_enum {
-    ///        Empty => 0_u8.hash(&mut state),
-    ///        WithValue(x) => x.hash(&mut state),
-    /// }
-    /// ```
-    #[clippy::version = "1.58.0"]
-    pub UNIT_HASH,
-    correctness,
-    "hashing a unit value, which does nothing"
-}
-declare_lint_pass!(UnitHash => [UNIT_HASH]);
-
-impl<'tcx> LateLintPass<'tcx> for UnitHash {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if_chain! {
-            if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind;
-            if name_ident.ident.name == sym::hash;
-            if let [recv, state_param] = args;
-            if cx.typeck_results().expr_ty(recv).is_unit();
-            then {
-                span_lint_and_then(
-                    cx,
-                    UNIT_HASH,
-                    expr.span,
-                    "this call to `hash` on the unit type will do nothing",
-                    |diag| {
-                        diag.span_suggestion(
-                            expr.span,
-                            "remove the call to `hash` or consider using",
-                            format!(
-                                "0_u8.hash({})",
-                                snippet(cx, state_param.span, ".."),
-                            ),
-                            Applicability::MaybeIncorrect,
-                        );
-                        diag.note("the implementation of `Hash` for `()` is a no-op");
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
deleted file mode 100644 (file)
index ea5aadb..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, subst::GenericArgKind};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-use rustc_span::symbol::Ident;
-use std::iter;
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust
-    /// # struct A;
-    /// # impl A { fn foo(&self) {} }
-    /// # let mut vec: Vec<A> = Vec::new();
-    /// vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// # struct A;
-    /// # impl A { fn foo(&self) {} }
-    /// # let mut vec: Vec<A> = Vec::new();
-    /// vec.sort_by_key(|a| a.foo());
-    /// ```
-    #[clippy::version = "1.46.0"]
-    pub UNNECESSARY_SORT_BY,
-    complexity,
-    "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer"
-}
-
-declare_lint_pass!(UnnecessarySortBy => [UNNECESSARY_SORT_BY]);
-
-enum LintTrigger {
-    Sort(SortDetection),
-    SortByKey(SortByKeyDetection),
-}
-
-struct SortDetection {
-    vec_name: String,
-    unstable: bool,
-}
-
-struct SortByKeyDetection {
-    vec_name: String,
-    closure_arg: String,
-    closure_body: String,
-    reverse: bool,
-    unstable: bool,
-}
-
-/// Detect if the two expressions are mirrored (identical, except one
-/// contains a and the other replaces it with b)
-fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool {
-    match (&a_expr.kind, &b_expr.kind) {
-        // Two boxes with mirrored contents
-        (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => {
-            mirrored_exprs(left_expr, a_ident, right_expr, b_ident)
-        },
-        // Two arrays with mirrored contents
-        (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => {
-            iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
-        },
-        // The two exprs are function calls.
-        // Check to see that the function itself and its arguments are mirrored
-        (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => {
-            mirrored_exprs(left_expr, a_ident, right_expr, b_ident)
-                && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
-        },
-        // The two exprs are method calls.
-        // Check to see that the function is the same and the arguments are mirrored
-        // This is enough because the receiver of the method is listed in the arguments
-        (ExprKind::MethodCall(left_segment, left_args, _), ExprKind::MethodCall(right_segment, right_args, _)) => {
-            left_segment.ident == right_segment.ident
-                && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
-        },
-        // Two tuples with mirrored contents
-        (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => {
-            iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
-        },
-        // Two binary ops, which are the same operation and which have mirrored arguments
-        (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => {
-            left_op.node == right_op.node
-                && mirrored_exprs(left_left, a_ident, right_left, b_ident)
-                && mirrored_exprs(left_right, a_ident, right_right, b_ident)
-        },
-        // Two unary ops, which are the same operation and which have the same argument
-        (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) => {
-            left_op == right_op && mirrored_exprs(left_expr, a_ident, right_expr, b_ident)
-        },
-        // The two exprs are literals of some kind
-        (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node,
-        (ExprKind::Cast(left, _), ExprKind::Cast(right, _)) => mirrored_exprs(left, a_ident, right, b_ident),
-        (ExprKind::DropTemps(left_block), ExprKind::DropTemps(right_block)) => {
-            mirrored_exprs(left_block, a_ident, right_block, b_ident)
-        },
-        (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => {
-            left_ident.name == right_ident.name && mirrored_exprs(left_expr, a_ident, right_expr, right_ident)
-        },
-        // Two paths: either one is a and the other is b, or they're identical to each other
-        (
-            ExprKind::Path(QPath::Resolved(
-                _,
-                Path {
-                    segments: left_segments,
-                    ..
-                },
-            )),
-            ExprKind::Path(QPath::Resolved(
-                _,
-                Path {
-                    segments: right_segments,
-                    ..
-                },
-            )),
-        ) => {
-            (iter::zip(*left_segments, *right_segments).all(|(left, right)| left.ident == right.ident)
-                && left_segments
-                    .iter()
-                    .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident))
-                || (left_segments.len() == 1
-                    && &left_segments[0].ident == a_ident
-                    && right_segments.len() == 1
-                    && &right_segments[0].ident == b_ident)
-        },
-        // Matching expressions, but one or both is borrowed
-        (
-            ExprKind::AddrOf(left_kind, Mutability::Not, left_expr),
-            ExprKind::AddrOf(right_kind, Mutability::Not, right_expr),
-        ) => left_kind == right_kind && mirrored_exprs(left_expr, a_ident, right_expr, b_ident),
-        (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) => mirrored_exprs(a_expr, a_ident, right_expr, b_ident),
-        (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => mirrored_exprs(left_expr, a_ident, b_expr, b_ident),
-        _ => false,
-    }
-}
-
-fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
-    if_chain! {
-        if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind;
-        if let name = name_ident.ident.name.to_ident_string();
-        if name == "sort_by" || name == "sort_unstable_by";
-        if let [vec, Expr { kind: ExprKind::Closure(Closure { body: closure_body_id, .. }), .. }] = args;
-        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec);
-        if let closure_body = cx.tcx.hir().body(*closure_body_id);
-        if let &[
-            Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
-            Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
-        ] = &closure_body.params;
-        if let ExprKind::MethodCall(method_path, [ref left_expr, ref right_expr], _) = &closure_body.value.kind;
-        if method_path.ident.name == sym::cmp;
-        then {
-            let (closure_body, closure_arg, reverse) = if mirrored_exprs(
-                left_expr,
-                left_ident,
-                right_expr,
-                right_ident
-            ) {
-                (Sugg::hir(cx, left_expr, "..").to_string(), left_ident.name.to_string(), false)
-            } else if mirrored_exprs(left_expr, right_ident, right_expr, left_ident) {
-                (Sugg::hir(cx, left_expr, "..").to_string(), right_ident.name.to_string(), true)
-            } else {
-                return None;
-            };
-            let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
-            let unstable = name == "sort_unstable_by";
-
-            if_chain! {
-            if let ExprKind::Path(QPath::Resolved(_, Path {
-                segments: [PathSegment { ident: left_name, .. }], ..
-            })) = &left_expr.kind;
-            if left_name == left_ident;
-            if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
-                implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
-            });
-                then {
-                    return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }));
-                }
-            }
-
-            if !expr_borrows(cx, left_expr) {
-                return Some(LintTrigger::SortByKey(SortByKeyDetection {
-                    vec_name,
-                    closure_arg,
-                    closure_body,
-                    reverse,
-                    unstable,
-                }));
-            }
-        }
-    }
-
-    None
-}
-
-fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let ty = cx.typeck_results().expr_ty(expr);
-    matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
-}
-
-impl LateLintPass<'_> for UnnecessarySortBy {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        match detect_lint(cx, expr) {
-            Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg(
-                cx,
-                UNNECESSARY_SORT_BY,
-                expr.span,
-                "use Vec::sort_by_key here instead",
-                "try",
-                format!(
-                    "{}.sort{}_by_key(|{}| {})",
-                    trigger.vec_name,
-                    if trigger.unstable { "_unstable" } else { "" },
-                    trigger.closure_arg,
-                    if trigger.reverse {
-                        format!("std::cmp::Reverse({})", trigger.closure_body)
-                    } else {
-                        trigger.closure_body.to_string()
-                    },
-                ),
-                if trigger.reverse {
-                    Applicability::MaybeIncorrect
-                } else {
-                    Applicability::MachineApplicable
-                },
-            ),
-            Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg(
-                cx,
-                UNNECESSARY_SORT_BY,
-                expr.span,
-                "use Vec::sort here instead",
-                "try",
-                format!(
-                    "{}.sort{}()",
-                    trigger.vec_name,
-                    if trigger.unstable { "_unstable" } else { "" },
-                ),
-                Applicability::MachineApplicable,
-            ),
-            None => {},
-        }
-    }
-}
index f4f5a4336a39ec7ad4ae0800207e429f986f1f4d..a5afbb8ff9da49272efd9887b20732ed221c0049 100644 (file)
@@ -130,7 +130,7 @@ fn check_fn(
                         (
                             ret_expr.span,
                             if inner_type.is_unit() {
-                                "".to_string()
+                                String::new()
                             } else {
                                 snippet(cx, arg.span.source_callsite(), "..").to_string()
                             }
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
new file mode 100644 (file)
index 0000000..ac73173
--- /dev/null
@@ -0,0 +1,225 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::{match_type, peel_mid_ty_refs_is_mutable};
+use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, paths, peel_ref_operators};
+use rustc_ast::Mutability;
+use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// let collection = vec![1, 2, 3];
+    /// let iter = collection.iter().peekable();
+    ///
+    /// for item in iter {
+    ///     // ...
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// let collection = vec![1, 2, 3];
+    /// let iter = collection.iter();
+    ///
+    /// for item in iter {
+    ///     // ...
+    /// }
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub UNUSED_PEEKABLE,
+    suspicious,
+    "creating a peekable iterator without using any of its methods"
+}
+
+declare_lint_pass!(UnusedPeekable => [UNUSED_PEEKABLE]);
+
+impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
+        // Don't lint `Peekable`s returned from a block
+        if let Some(expr) = block.expr
+            && let Some(ty) = cx.typeck_results().expr_ty_opt(peel_ref_operators(cx, expr))
+            && match_type(cx, ty, &paths::PEEKABLE)
+        {
+            return;
+        }
+
+        for (idx, stmt) in block.stmts.iter().enumerate() {
+            if !stmt.span.from_expansion()
+                && let StmtKind::Local(local) = stmt.kind
+                && let PatKind::Binding(_, binding, ident, _) = local.pat.kind
+                && let Some(init) = local.init
+                && !init.span.from_expansion()
+                && let Some(ty) = cx.typeck_results().expr_ty_opt(init)
+                && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
+                && match_type(cx, ty, &paths::PEEKABLE)
+            {
+                let mut vis = PeekableVisitor::new(cx, binding);
+
+                if idx + 1 == block.stmts.len() && block.expr.is_none() {
+                    return;
+                }
+
+                for stmt in &block.stmts[idx..] {
+                    vis.visit_stmt(stmt);
+                }
+
+                if let Some(expr) = block.expr {
+                    vis.visit_expr(expr);
+                }
+
+                if !vis.found_peek_call {
+                    span_lint_and_help(
+                        cx,
+                        UNUSED_PEEKABLE,
+                        ident.span,
+                        "`peek` never called on `Peekable` iterator",
+                        None,
+                        "consider removing the call to `peekable`"
+                   );
+                }
+            }
+        }
+    }
+}
+
+struct PeekableVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    expected_hir_id: HirId,
+    found_peek_call: bool,
+}
+
+impl<'a, 'tcx> PeekableVisitor<'a, 'tcx> {
+    fn new(cx: &'a LateContext<'tcx>, expected_hir_id: HirId) -> Self {
+        Self {
+            cx,
+            expected_hir_id,
+            found_peek_call: false,
+        }
+    }
+}
+
+impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
+    fn visit_expr(&mut self, ex: &'_ Expr<'_>) {
+        if self.found_peek_call {
+            return;
+        }
+
+        if path_to_local_id(ex, self.expected_hir_id) {
+            for (_, node) in self.cx.tcx.hir().parent_iter(ex.hir_id) {
+                match node {
+                    Node::Expr(expr) => {
+                        match expr.kind {
+                            // some_function(peekable)
+                            //
+                            // If the Peekable is passed to a function, stop
+                            ExprKind::Call(_, args) => {
+                                if let Some(func_did) = fn_def_id(self.cx, expr)
+                                    && let Ok(into_iter_did) = self
+                                        .cx
+                                        .tcx
+                                        .lang_items()
+                                        .require(LangItem::IntoIterIntoIter)
+                                    && func_did == into_iter_did
+                                {
+                                    // Probably a for loop desugar, stop searching
+                                    return;
+                                }
+
+                                if args.iter().any(|arg| {
+                                    matches!(arg.kind, ExprKind::Path(_)) && arg_is_mut_peekable(self.cx, arg)
+                                }) {
+                                    self.found_peek_call = true;
+                                    return;
+                                }
+                            },
+                            // Catch anything taking a Peekable mutably
+                            ExprKind::MethodCall(
+                                PathSegment {
+                                    ident: method_name_ident,
+                                    ..
+                                },
+                                [self_arg, remaining_args @ ..],
+                                _,
+                            ) => {
+                                let method_name = method_name_ident.name.as_str();
+
+                                // `Peekable` methods
+                                if matches!(method_name, "peek" | "peek_mut" | "next_if" | "next_if_eq")
+                                    && arg_is_mut_peekable(self.cx, self_arg)
+                                {
+                                    self.found_peek_call = true;
+                                    return;
+                                }
+
+                                // foo.some_method() excluding Iterator methods
+                                if remaining_args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg))
+                                    && !is_trait_method(self.cx, expr, sym::Iterator)
+                                {
+                                    self.found_peek_call = true;
+                                    return;
+                                }
+
+                                // foo.by_ref(), keep checking for `peek`
+                                if method_name == "by_ref" {
+                                    continue;
+                                }
+
+                                return;
+                            },
+                            ExprKind::AddrOf(_, Mutability::Mut, _) | ExprKind::Unary(..) | ExprKind::DropTemps(_) => {
+                            },
+                            ExprKind::AddrOf(_, Mutability::Not, _) => return,
+                            _ => {
+                                self.found_peek_call = true;
+                                return;
+                            },
+                        }
+                    },
+                    Node::Local(Local { init: Some(init), .. }) => {
+                        if arg_is_mut_peekable(self.cx, init) {
+                            self.found_peek_call = true;
+                            return;
+                        }
+
+                        break;
+                    },
+                    Node::Stmt(stmt) => match stmt.kind {
+                        StmtKind::Expr(_) | StmtKind::Semi(_) => {},
+                        _ => {
+                            self.found_peek_call = true;
+                            return;
+                        },
+                    },
+                    Node::Block(_) | Node::ExprField(_) => {},
+                    _ => {
+                        break;
+                    },
+                }
+            }
+        }
+
+        walk_expr(self, ex);
+    }
+}
+
+fn arg_is_mut_peekable(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
+    if let Some(ty) = cx.typeck_results().expr_ty_opt(arg)
+        && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
+        && match_type(cx, ty, &paths::PEEKABLE)
+    {
+        true
+    } else {
+        false
+    }
+}
index e1ec357838dbd88846e97ef43c602d33500ebe85..b8a5d4ea8c9fbe177429781c403313046f752194 100644 (file)
@@ -22,7 +22,7 @@
     /// ```rust
     /// let x = 1f32;
     /// ```
-    #[clippy::version = "1.62.0"]
+    #[clippy::version = "1.63.0"]
     pub UNUSED_ROUNDING,
     nursery,
     "Uselessly rounding a whole number floating-point literal"
index 3faae9ac0d2b2af6232568015f6874955174c811..84e65d5fa0b719044d3d43705141e5656aa9f63e 100644 (file)
@@ -350,7 +350,7 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
     /// Lint: DISALLOWED_SCRIPT_IDENTS.
     ///
     /// The list of unicode scripts allowed to be used in the scope.
-    (allowed_scripts: Vec<String> = ["Latin"].iter().map(ToString::to_string).collect()),
+    (allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
     /// Lint: NON_SEND_FIELDS_IN_SEND_TY.
     ///
     /// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
@@ -379,6 +379,10 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
     ///
     /// Whether `dbg!` should be allowed in test functions
     (allow_dbg_in_tests: bool = false),
+    /// Lint: RESULT_LARGE_ERR
+    ///
+    /// The maximum size of the `Err`-variant in a `Result` returned from a function
+    (large_error_threshold: u64 = 128),
 }
 
 /// Search for the configuration file.
index 5dcacd604be45f6b0a4c4844e05ece2e13287198..eb34085a2abf3a5e5631bf182173a33cb14abb9c 100644 (file)
@@ -593,8 +593,8 @@ fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Opt
     attrs.iter().find_map(|attr| {
         if_chain! {
             // Identify attribute
-            if let ast::AttrKind::Normal(ref attr_kind, _) = &attr.kind;
-            if let [tool_name, attr_name] = &attr_kind.path.segments[..];
+            if let ast::AttrKind::Normal(ref attr_kind) = &attr.kind;
+            if let [tool_name, attr_name] = &attr_kind.item.path.segments[..];
             if tool_name.ident.name == sym::clippy;
             if attr_name.ident.name == sym::version;
             if let Some(version) = attr.value_str();
index 92cf42c7ad43f0459fe10051fd2ea4baac6109eb..b1148bccc2a283d025cb530f18197437bfbe9079 100644 (file)
@@ -797,7 +797,7 @@ fn get_lint_group_and_level_or_lint(
     let result = cx.lint_store.check_lint_name(
         lint_name,
         Some(sym::clippy),
-        &[Ident::with_dummy_span(sym::clippy)].into_iter().collect(),
+        &std::iter::once(Ident::with_dummy_span(sym::clippy)).collect(),
     );
     if let CheckLintNameResult::Tool(Ok(lint_lst)) = result {
         if let Some(group) = get_lint_group(cx, lint_lst[0]) {
diff --git a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
deleted file mode 100644 (file)
index 0fee3e8..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{match_def_path, paths};
-use if_chain::if_chain;
-use rustc_ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Spanned;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Finds occurrences of `Vec::resize(0, an_int)`
-    ///
-    /// ### Why is this bad?
-    /// This is probably an argument inversion mistake.
-    ///
-    /// ### Example
-    /// ```rust
-    /// vec!(1, 2, 3, 4, 5).resize(0, 5)
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust
-    /// vec!(1, 2, 3, 4, 5).clear()
-    /// ```
-    #[clippy::version = "1.46.0"]
-    pub VEC_RESIZE_TO_ZERO,
-    correctness,
-    "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake"
-}
-
-declare_lint_pass!(VecResizeToZero => [VEC_RESIZE_TO_ZERO]);
-
-impl<'tcx> LateLintPass<'tcx> for VecResizeToZero {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let hir::ExprKind::MethodCall(path_segment, args, _) = expr.kind;
-            if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
-            if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3;
-            if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind;
-            if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = args[2].kind;
-            then {
-                let method_call_span = expr.span.with_lo(path_segment.ident.span.lo());
-                span_lint_and_then(
-                    cx,
-                    VEC_RESIZE_TO_ZERO,
-                    expr.span,
-                    "emptying a vector with `resize`",
-                    |db| {
-                        db.help("the arguments may be inverted...");
-                        db.span_suggestion(
-                            method_call_span,
-                            "...or you can empty the vector with",
-                            "clear()".to_string(),
-                            Applicability::MaybeIncorrect,
-                        );
-                    },
-                );
-            }
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
deleted file mode 100644 (file)
index afd0077..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::paths;
-use clippy_utils::ty::match_type;
-use if_chain::if_chain;
-use rustc_hir::{Expr, ExprKind, QPath};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// ### 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
-    /// ```rust,no_run
-    /// # use std::io::Read;
-    /// # use std::fs::File;
-    /// 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
-    /// ```rust,no_run
-    /// # use std::fs;
-    /// let mut bytes = fs::read("foo.txt").unwrap();
-    /// ```
-    #[clippy::version = "1.44.0"]
-    pub VERBOSE_FILE_READS,
-    restriction,
-    "use of `File::read_to_end` or `File::read_to_string`"
-}
-
-declare_lint_pass!(VerboseFileReads => [VERBOSE_FILE_READS]);
-
-impl<'tcx> LateLintPass<'tcx> for VerboseFileReads {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if is_file_read_to_end(cx, expr) {
-            span_lint_and_help(
-                cx,
-                VERBOSE_FILE_READS,
-                expr.span,
-                "use of `File::read_to_end`",
-                None,
-                "consider using `fs::read` instead",
-            );
-        } else if is_file_read_to_string(cx, expr) {
-            span_lint_and_help(
-                cx,
-                VERBOSE_FILE_READS,
-                expr.span,
-                "use of `File::read_to_string`",
-                None,
-                "consider using `fs::read_to_string` instead",
-            );
-        }
-    }
-}
-
-fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
-    if_chain! {
-        if let ExprKind::MethodCall(method_name, [recv, ..], _) = expr.kind;
-        if method_name.ident.as_str() == "read_to_end";
-        if let ExprKind::Path(QPath::Resolved(None, _)) = &recv.kind;
-        let ty = cx.typeck_results().expr_ty(recv);
-        if match_type(cx, ty, &paths::FILE);
-        then {
-            return true
-        }
-    }
-    false
-}
-
-fn is_file_read_to_string<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
-    if_chain! {
-        if let ExprKind::MethodCall(method_name, exprs, _) = expr.kind;
-        if method_name.ident.as_str() == "read_to_string";
-        if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
-        let ty = cx.typeck_results().expr_ty(&exprs[0]);
-        if match_type(cx, ty, &paths::FILE);
-        then {
-            return true
-        }
-    }
-    false
-}
index fa2383066f3f622af5353b45d5431fe33d7df445..347165d9704a100717d0e61bffe3cee3ab571269 100644 (file)
@@ -3,8 +3,9 @@
 use std::ops::{Deref, Range};
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet_opt, snippet_with_applicability};
+use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
 use rustc_ast::ast::{Expr, ExprKind, Impl, Item, ItemKind, MacCall, Path, StrLit, StrStyle};
+use rustc_ast::ptr::P;
 use rustc_ast::token::{self, LitKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_errors::{Applicability, DiagnosticBuilder};
     "writing a literal with a format string"
 }
 
+declare_clippy_lint! {
+    /// ### 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
+    /// ```rust
+    /// println!("{}", x = 10);
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// println!("{x}", x = 10);
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub POSITIONAL_NAMED_FORMAT_PARAMETERS,
+    suspicious,
+    "named parameter in a format string is used positionally"
+}
+
 #[derive(Default)]
 pub struct Write {
     in_debug_impl: bool,
@@ -270,7 +293,8 @@ pub struct Write {
     PRINT_LITERAL,
     WRITE_WITH_NEWLINE,
     WRITELN_EMPTY_STRING,
-    WRITE_LITERAL
+    WRITE_LITERAL,
+    POSITIONAL_NAMED_FORMAT_PARAMETERS,
 ]);
 
 impl EarlyLintPass for Write {
@@ -408,6 +432,7 @@ fn newline_span(fmtstr: &StrLit) -> (Span, bool) {
 #[derive(Default)]
 struct SimpleFormatArgs {
     unnamed: Vec<Vec<Span>>,
+    complex_unnamed: Vec<Vec<Span>>,
     named: Vec<(Symbol, Vec<Span>)>,
 }
 impl SimpleFormatArgs {
@@ -419,6 +444,10 @@ fn get_unnamed(&self) -> impl Iterator<Item = &[Span]> {
         })
     }
 
+    fn get_complex_unnamed(&self) -> impl Iterator<Item = &[Span]> {
+        self.complex_unnamed.iter().map(Vec::as_slice)
+    }
+
     fn get_named(&self, n: &Path) -> &[Span] {
         self.named.iter().find(|x| *n == x.0).map_or(&[], |x| x.1.as_slice())
     }
@@ -479,6 +508,61 @@ fn push(&mut self, arg: rustc_parse_format::Argument<'_>, span: Span) {
             },
         };
     }
+
+    fn push_to_complex(&mut self, span: Span, position: usize) {
+        if self.complex_unnamed.len() <= position {
+            self.complex_unnamed.resize_with(position, Vec::new);
+            self.complex_unnamed.push(vec![span]);
+        } else {
+            let args: &mut Vec<Span> = &mut self.complex_unnamed[position];
+            args.push(span);
+        }
+    }
+
+    fn push_complex(
+        &mut self,
+        cx: &EarlyContext<'_>,
+        arg: rustc_parse_format::Argument<'_>,
+        str_lit_span: Span,
+        fmt_span: Span,
+    ) {
+        use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam, CountIsStar};
+
+        let snippet = snippet_opt(cx, fmt_span);
+
+        let end = snippet
+            .as_ref()
+            .and_then(|s| s.find(':'))
+            .or_else(|| fmt_span.hi().0.checked_sub(fmt_span.lo().0 + 1).map(|u| u as usize));
+
+        if let (ArgumentIs(n) | ArgumentImplicitlyIs(n), Some(end)) = (arg.position, end) {
+            let span = fmt_span.from_inner(InnerSpan::new(1, end));
+            self.push_to_complex(span, n);
+        };
+
+        if let (CountIsParam(n) | CountIsStar(n), Some(span)) = (arg.format.precision, arg.format.precision_span) {
+            // We need to do this hack as precision spans should be converted from .* to .foo$
+            let hack = if snippet.as_ref().and_then(|s| s.find('*')).is_some() {
+                0
+            } else {
+                1
+            };
+
+            let span = str_lit_span.from_inner(InnerSpan {
+                start: span.start + 1,
+                end: span.end - hack,
+            });
+            self.push_to_complex(span, n);
+        };
+
+        if let (CountIsParam(n), Some(span)) = (arg.format.width, arg.format.width_span) {
+            let span = str_lit_span.from_inner(InnerSpan {
+                start: span.start,
+                end: span.end - 1,
+            });
+            self.push_to_complex(span, n);
+        };
+    }
 }
 
 impl Write {
@@ -511,8 +595,8 @@ fn parse_fmt_string(&self, cx: &EarlyContext<'_>, str_lit: &StrLit) -> Option<Si
                 // FIXME: modify rustc's fmt string parser to give us the current span
                 span_lint(cx, USE_DEBUG, span, "use of `Debug`-based formatting");
             }
-
             args.push(arg, span);
+            args.push_complex(cx, arg, str_lit.span, span);
         }
 
         parser.errors.is_empty().then_some(args)
@@ -566,6 +650,7 @@ fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool)
 
         let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL };
         let mut unnamed_args = args.get_unnamed();
+        let mut complex_unnamed_args = args.get_complex_unnamed();
         loop {
             if !parser.eat(&token::Comma) {
                 return (Some(fmtstr), expr);
@@ -577,11 +662,20 @@ fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool)
             } else {
                 return (Some(fmtstr), None);
             };
+            let complex_unnamed_arg = complex_unnamed_args.next();
+
             let (fmt_spans, lit) = match &token_expr.kind {
                 ExprKind::Lit(lit) => (unnamed_args.next().unwrap_or(&[]), lit),
-                ExprKind::Assign(lhs, rhs, _) => match (&lhs.kind, &rhs.kind) {
-                    (ExprKind::Path(_, p), ExprKind::Lit(lit)) => (args.get_named(p), lit),
-                    _ => continue,
+                ExprKind::Assign(lhs, rhs, _) => {
+                    if let Some(span) = complex_unnamed_arg {
+                        for x in span {
+                            Self::report_positional_named_param(cx, *x, lhs, rhs);
+                        }
+                    }
+                    match (&lhs.kind, &rhs.kind) {
+                        (ExprKind::Path(_, p), ExprKind::Lit(lit)) => (args.get_named(p), lit),
+                        _ => continue,
+                    }
                 },
                 _ => {
                     unnamed_args.next();
@@ -637,6 +731,29 @@ fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool)
         }
     }
 
+    fn report_positional_named_param(cx: &EarlyContext<'_>, span: Span, lhs: &P<Expr>, _rhs: &P<Expr>) {
+        if let ExprKind::Path(_, _p) = &lhs.kind {
+            let mut applicability = Applicability::MachineApplicable;
+            let name = snippet_with_applicability(cx, lhs.span, "name", &mut applicability);
+            // We need to do this hack as precision spans should be converted from .* to .foo$
+            let hack = snippet(cx, span, "").contains('*');
+
+            span_lint_and_sugg(
+                cx,
+                POSITIONAL_NAMED_FORMAT_PARAMETERS,
+                span,
+                &format!("named parameter {} is used as a positional parameter", name),
+                "replace it with",
+                if hack {
+                    format!("{}$", name)
+                } else {
+                    format!("{}", name)
+                },
+                applicability,
+            );
+        };
+    }
+
     fn lint_println_empty_string(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
         if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
             if fmt_str.symbol == kw::Empty {
index a688050f63a6ad659603b248aa78ca785edcf093..c36bca06507d67b8544dd51850235166b9cf0015 100644 (file)
@@ -7,6 +7,7 @@ publish = false
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
 if_chain = "1.0"
+itertools = "0.10.1"
 rustc-semver = "1.1"
 
 [features]
index f716f009ff3f5c23c238b7e28f2a3cf435fe012e..997e773b5da4eecc3cf2ea61ae2dc0a1f131c552 100644 (file)
@@ -2,6 +2,7 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(let_else)]
+#![feature(let_chains)]
 #![feature(lint_reasons)]
 #![feature(once_cell)]
 #![feature(rustc_private)]
@@ -27,6 +28,7 @@
 extern crate rustc_lexer;
 extern crate rustc_lint;
 extern crate rustc_middle;
+extern crate rustc_parse_format;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
@@ -86,6 +88,7 @@
     Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
     TraitRef, TyKind, UnOp,
 };
+use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::ty as rustc_ty;
 use rustc_session::Session;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
+use rustc_span::source_map::SourceMap;
 use rustc_span::sym;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -371,15 +375,19 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
 
 /// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
 ///
-/// Please use `is_expr_diagnostic_item` if the target is a diagnostic item.
+/// Please use `is_path_diagnostic_item` if the target is a diagnostic item.
 pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
     path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments))
 }
 
-/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given
-/// diagnostic item.
-pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
-    path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
+/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
+/// it matches the given diagnostic item.
+pub fn is_path_diagnostic_item<'tcx>(
+    cx: &LateContext<'_>,
+    maybe_path: &impl MaybePath<'tcx>,
+    diag_item: Symbol,
+) -> bool {
+    path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
 }
 
 /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
@@ -2273,6 +2281,18 @@ pub fn walk_to_expr_usage<'tcx, T>(
     None
 }
 
+/// Checks whether a given span has any comment token
+/// This checks for all types of comment: line "//", block "/**", doc "///" "//!"
+pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
+    let Ok(snippet) = sm.span_to_snippet(span) else { return false };
+    return tokenize(&snippet).any(|token| {
+        matches!(
+            token.kind,
+            TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
+        )
+    });
+}
+
 macro_rules! op_utils {
     ($($name:ident $assign:ident)*) => {
         /// Binary operation traits like `LangItem::Add`
index a268e339bb130df99138102b739e6def1d44c640..43e53f3feebd31429644fca6943951a93720019c 100644 (file)
@@ -1,16 +1,21 @@
 #![allow(clippy::similar_names)] // `expr` and `expn`
 
+use crate::is_path_diagnostic_item;
+use crate::source::snippet_opt;
 use crate::visitors::expr_visitor_no_bodies;
 
 use arrayvec::ArrayVec;
-use if_chain::if_chain;
+use itertools::{izip, Either, Itertools};
 use rustc_ast::ast::LitKind;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath};
+use rustc_lexer::unescape::unescape_literal;
+use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
 use rustc_lint::LateContext;
+use rustc_parse_format::{self as rpf, Alignment};
 use rustc_span::def_id::DefId;
 use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
-use rustc_span::{sym, ExpnData, ExpnId, ExpnKind, Span, Symbol};
+use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol};
 use std::ops::ControlFlow;
 
 const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[
@@ -332,121 +337,495 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) ->
     }
 }
 
-/// A parsed `format_args!` expansion
+/// The format string doesn't exist in the HIR, so we reassemble it from source code
 #[derive(Debug)]
-pub struct FormatArgsExpn<'tcx> {
-    /// Span of the first argument, the format string
-    pub format_string_span: Span,
-    /// The format string split by formatted args like `{..}`
-    pub format_string_parts: Vec<Symbol>,
-    /// Values passed after the format string
-    pub value_args: Vec<&'tcx Expr<'tcx>>,
-    /// Each element is a `value_args` index and a formatting trait (e.g. `sym::Debug`)
-    pub formatters: Vec<(usize, Symbol)>,
-    /// List of `fmt::v1::Argument { .. }` expressions. If this is empty,
-    /// then `formatters` represents the format args (`{..}`).
-    /// If this is non-empty, it represents the format args, and the `position`
-    /// parameters within the struct expressions are indexes of `formatters`.
-    pub specs: Vec<&'tcx Expr<'tcx>>,
+pub struct FormatString {
+    /// Span of the whole format string literal, including `[r#]"`.
+    pub span: Span,
+    /// Snippet of the whole format string literal, including `[r#]"`.
+    pub snippet: String,
+    /// If the string is raw `r"..."`/`r#""#`, how many `#`s does it have on each side.
+    pub style: Option<usize>,
+    /// The unescaped value of the format string, e.g. `"val – {}"` for the literal
+    /// `"val \u{2013} {}"`.
+    pub unescaped: String,
+    /// The format string split by format args like `{..}`.
+    pub parts: Vec<Symbol>,
 }
 
-impl<'tcx> FormatArgsExpn<'tcx> {
-    /// Parses an expanded `format_args!` or `format_args_nl!` invocation
-    pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<Self> {
-        macro_backtrace(expr.span).find(|macro_call| {
-            matches!(
-                cx.tcx.item_name(macro_call.def_id),
-                sym::const_format_args | sym::format_args | sym::format_args_nl
-            )
-        })?;
-        let mut format_string_span: Option<Span> = None;
-        let mut format_string_parts: Vec<Symbol> = Vec::new();
-        let mut value_args: Vec<&Expr<'_>> = Vec::new();
-        let mut formatters: Vec<(usize, Symbol)> = Vec::new();
-        let mut specs: Vec<&Expr<'_>> = Vec::new();
-        expr_visitor_no_bodies(|e| {
-            // if we're still inside of the macro definition...
-            if e.span.ctxt() == expr.span.ctxt() {
-                // ArgumentV1::new_<format_trait>(<value>)
-                if_chain! {
-                    if let ExprKind::Call(callee, [val]) = e.kind;
-                    if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind;
-                    if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
-                    if path.segments.last().unwrap().ident.name == sym::ArgumentV1;
-                    if seg.ident.name.as_str().starts_with("new_");
-                    then {
-                        let val_idx = if_chain! {
-                            if val.span.ctxt() == expr.span.ctxt();
-                            if let ExprKind::Field(_, field) = val.kind;
-                            if let Ok(idx) = field.name.as_str().parse();
-                            then {
-                                // tuple index
-                                idx
-                            } else {
-                                // assume the value expression is passed directly
-                                formatters.len()
-                            }
-                        };
-                        let fmt_trait = match seg.ident.name.as_str() {
-                            "new_display" => "Display",
-                            "new_debug" => "Debug",
-                            "new_lower_exp" => "LowerExp",
-                            "new_upper_exp" => "UpperExp",
-                            "new_octal" => "Octal",
-                            "new_pointer" => "Pointer",
-                            "new_binary" => "Binary",
-                            "new_lower_hex" => "LowerHex",
-                            "new_upper_hex" => "UpperHex",
-                            _ => unreachable!(),
-                        };
-                        formatters.push((val_idx, Symbol::intern(fmt_trait)));
-                    }
-                }
-                if let ExprKind::Struct(QPath::Resolved(_, path), ..) = e.kind {
-                    if path.segments.last().unwrap().ident.name == sym::Argument {
-                        specs.push(e);
-                    }
+impl FormatString {
+    fn new(cx: &LateContext<'_>, pieces: &Expr<'_>) -> Option<Self> {
+        // format_args!(r"a {} b \", 1);
+        //
+        // expands to
+        //
+        // ::core::fmt::Arguments::new_v1(&["a ", " b \\"],
+        //      &[::core::fmt::ArgumentV1::new_display(&1)]);
+        //
+        // where `pieces` is the expression `&["a ", " b \\"]`. It has the span of `r"a {} b \"`
+        let span = pieces.span;
+        let snippet = snippet_opt(cx, span)?;
+
+        let (inner, style) = match tokenize(&snippet).next()?.kind {
+            TokenKind::Literal { kind, .. } => {
+                let style = match kind {
+                    LiteralKind::Str { .. } => None,
+                    LiteralKind::RawStr { n_hashes: Some(n), .. } => Some(n.into()),
+                    _ => return None,
+                };
+
+                let start = style.map_or(1, |n| 2 + n);
+                let end = snippet.len() - style.map_or(1, |n| 1 + n);
+
+                (&snippet[start..end], style)
+            },
+            _ => return None,
+        };
+
+        let mode = if style.is_some() {
+            unescape::Mode::RawStr
+        } else {
+            unescape::Mode::Str
+        };
+
+        let mut unescaped = String::with_capacity(inner.len());
+        unescape_literal(inner, mode, &mut |_, ch| {
+            unescaped.push(ch.unwrap());
+        });
+
+        let mut parts = Vec::new();
+        expr_visitor_no_bodies(|expr| {
+            if let ExprKind::Lit(lit) = &expr.kind {
+                if let LitKind::Str(symbol, _) = lit.node {
+                    parts.push(symbol);
                 }
-                // walk through the macro expansion
-                return true;
             }
-            // assume that the first expr with a differing context represents
-            // (and has the span of) the format string
-            if format_string_span.is_none() {
-                format_string_span = Some(e.span);
-                let span = e.span;
-                // walk the expr and collect string literals which are format string parts
-                expr_visitor_no_bodies(|e| {
-                    if e.span.ctxt() != span.ctxt() {
-                        // defensive check, probably doesn't happen
-                        return false;
-                    }
-                    if let ExprKind::Lit(lit) = &e.kind {
-                        if let LitKind::Str(symbol, _s) = lit.node {
-                            format_string_parts.push(symbol);
-                        }
-                    }
-                    true
-                })
-                .visit_expr(e);
+
+            true
+        })
+        .visit_expr(pieces);
+
+        Some(Self {
+            span,
+            snippet,
+            style,
+            unescaped,
+            parts,
+        })
+    }
+}
+
+struct FormatArgsValues<'tcx> {
+    /// See `FormatArgsExpn::value_args`
+    value_args: Vec<&'tcx Expr<'tcx>>,
+    /// Maps an `rt::v1::Argument::position` or an `rt::v1::Count::Param` to its index in
+    /// `value_args`
+    pos_to_value_index: Vec<usize>,
+    /// Used to check if a value is declared inline & to resolve `InnerSpan`s.
+    format_string_span: SpanData,
+}
+
+impl<'tcx> FormatArgsValues<'tcx> {
+    fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self {
+        let mut pos_to_value_index = Vec::new();
+        let mut value_args = Vec::new();
+        expr_visitor_no_bodies(|expr| {
+            if expr.span.ctxt() == args.span.ctxt() {
+                // ArgumentV1::new_<format_trait>(<val>)
+                // ArgumentV1::from_usize(<val>)
+                if let ExprKind::Call(callee, [val]) = expr.kind
+                    && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind
+                    && let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind
+                    && path.segments.last().unwrap().ident.name == sym::ArgumentV1
+                {
+                    let val_idx = if val.span.ctxt() == expr.span.ctxt()
+                        && let ExprKind::Field(_, field) = val.kind
+                        && let Ok(idx) = field.name.as_str().parse()
+                    {
+                        // tuple index
+                        idx
+                    } else {
+                        // assume the value expression is passed directly
+                        pos_to_value_index.len()
+                    };
+
+                    pos_to_value_index.push(val_idx);
+                }
+
+                true
             } else {
-                // assume that any further exprs with a differing context are value args
-                value_args.push(e);
+                // assume that any expr with a differing span is a value
+                value_args.push(expr);
+
+                false
             }
-            // don't walk anything not from the macro expansion (e.a. inputs)
-            false
         })
-        .visit_expr(expr);
-        Some(FormatArgsExpn {
-            format_string_span: format_string_span?,
-            format_string_parts,
+        .visit_expr(args);
+
+        Self {
             value_args,
-            formatters,
-            specs,
+            pos_to_value_index,
+            format_string_span,
+        }
+    }
+}
+
+/// The positions of a format argument's value, precision and width
+///
+/// A position is an index into the second argument of `Arguments::new_v1[_formatted]`
+#[derive(Debug, Default, Copy, Clone)]
+struct ParamPosition {
+    /// The position stored in `rt::v1::Argument::position`.
+    value: usize,
+    /// The position stored in `rt::v1::FormatSpec::width` if it is a `Count::Param`.
+    width: Option<usize>,
+    /// The position stored in `rt::v1::FormatSpec::precision` if it is a `Count::Param`.
+    precision: Option<usize>,
+}
+
+/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)`
+fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option<impl Iterator<Item = ParamPosition> + 'tcx> {
+    fn parse_count(expr: &Expr<'_>) -> Option<usize> {
+        // ::core::fmt::rt::v1::Count::Param(1usize),
+        if let ExprKind::Call(ctor, [val]) = expr.kind
+            && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind
+            && path.segments.last()?.ident.name == sym::Param
+            && let ExprKind::Lit(lit) = &val.kind
+            && let LitKind::Int(pos, _) = lit.node
+        {
+            Some(pos as usize)
+        } else {
+            None
+        }
+    }
+
+    if let ExprKind::AddrOf(.., array) = fmt_arg.kind
+        && let ExprKind::Array(specs) = array.kind
+    {
+        Some(specs.iter().map(|spec| {
+            let mut position = ParamPosition::default();
+
+            // ::core::fmt::rt::v1::Argument {
+            //     position: 0usize,
+            //     format: ::core::fmt::rt::v1::FormatSpec {
+            //         ..
+            //         precision: ::core::fmt::rt::v1::Count::Implied,
+            //         width: ::core::fmt::rt::v1::Count::Implied,
+            //     },
+            // }
+
+            // TODO: this can be made much nicer next sync with `Visitor::visit_expr_field`
+            if let ExprKind::Struct(_, fields, _) = spec.kind {
+                for field in fields {
+                    match (field.ident.name, &field.expr.kind) {
+                        (sym::position, ExprKind::Lit(lit)) => {
+                            if let LitKind::Int(pos, _) = lit.node {
+                                position.value = pos as usize;
+                            }
+                        },
+                        (sym::format, &ExprKind::Struct(_, spec_fields, _)) => {
+                            for spec_field in spec_fields {
+                                match spec_field.ident.name {
+                                    sym::precision => {
+                                        position.precision = parse_count(spec_field.expr);
+                                    },
+                                    sym::width => {
+                                        position.width = parse_count(spec_field.expr);
+                                    },
+                                    _ => {},
+                                }
+                            }
+                        },
+                        _ => {},
+                    }
+                }
+            }
+
+            position
+        }))
+    } else {
+        None
+    }
+}
+
+/// `Span::from_inner`, but for `rustc_parse_format`'s `InnerSpan`
+fn span_from_inner(base: SpanData, inner: rpf::InnerSpan) -> Span {
+    Span::new(
+        base.lo + BytePos::from_usize(inner.start),
+        base.lo + BytePos::from_usize(inner.end),
+        base.ctxt,
+        base.parent,
+    )
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum FormatParamKind {
+    /// An implicit parameter , such as `{}` or `{:?}`.
+    Implicit,
+    /// A parameter with an explicit number, or an asterisk precision. e.g. `{1}`, `{0:?}`,
+    /// `{:.0$}` or `{:.*}`.
+    Numbered,
+    /// A named parameter with a named `value_arg`, such as the `x` in `format!("{x}", x = 1)`.
+    Named(Symbol),
+    /// An implicit named parameter, such as the `y` in `format!("{y}")`.
+    NamedInline(Symbol),
+}
+
+/// A `FormatParam` is any place in a `FormatArgument` that refers to a supplied value, e.g.
+///
+/// ```
+/// let precision = 2;
+/// format!("{:.precision$}", 0.1234);
+/// ```
+///
+/// has two `FormatParam`s, a [`FormatParamKind::Implicit`] `.kind` with a `.value` of `0.1234`
+/// and a [`FormatParamKind::NamedInline("precision")`] `.kind` with a `.value` of `2`
+#[derive(Debug, Copy, Clone)]
+pub struct FormatParam<'tcx> {
+    /// The expression this parameter refers to.
+    pub value: &'tcx Expr<'tcx>,
+    /// How this parameter refers to its `value`.
+    pub kind: FormatParamKind,
+    /// Span of the parameter, may be zero width. Includes the whitespace of implicit parameters.
+    ///
+    /// ```text
+    /// format!("{}, {  }, {0}, {name}", ...);
+    ///          ^    ~~    ~    ~~~~
+    /// ```
+    pub span: Span,
+}
+
+impl<'tcx> FormatParam<'tcx> {
+    fn new(
+        mut kind: FormatParamKind,
+        position: usize,
+        inner: rpf::InnerSpan,
+        values: &FormatArgsValues<'tcx>,
+    ) -> Option<Self> {
+        let value_index = *values.pos_to_value_index.get(position)?;
+        let value = *values.value_args.get(value_index)?;
+        let span = span_from_inner(values.format_string_span, inner);
+
+        // if a param is declared inline, e.g. `format!("{x}")`, the generated expr's span points
+        // into the format string
+        if let FormatParamKind::Named(name) = kind && values.format_string_span.contains(value.span.data()) {
+            kind = FormatParamKind::NamedInline(name);
+        }
+
+        Some(Self { value, kind, span })
+    }
+}
+
+/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and
+/// [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
+#[derive(Debug, Copy, Clone)]
+pub enum Count<'tcx> {
+    /// Specified with a literal number, stores the value.
+    Is(usize, Span),
+    /// Specified using `$` and `*` syntaxes. The `*` format is still considered to be
+    /// `FormatParamKind::Numbered`.
+    Param(FormatParam<'tcx>),
+    /// Not specified.
+    Implied,
+}
+
+impl<'tcx> Count<'tcx> {
+    fn new(
+        count: rpf::Count<'_>,
+        position: Option<usize>,
+        inner: Option<rpf::InnerSpan>,
+        values: &FormatArgsValues<'tcx>,
+    ) -> Option<Self> {
+        Some(match count {
+            rpf::Count::CountIs(val) => Self::Is(val, span_from_inner(values.format_string_span, inner?)),
+            rpf::Count::CountIsName(name, span) => Self::Param(FormatParam::new(
+                FormatParamKind::Named(Symbol::intern(name)),
+                position?,
+                span,
+                values,
+            )?),
+            rpf::Count::CountIsParam(_) | rpf::Count::CountIsStar(_) => {
+                Self::Param(FormatParam::new(FormatParamKind::Numbered, position?, inner?, values)?)
+            },
+            rpf::Count::CountImplied => Self::Implied,
+        })
+    }
+
+    pub fn is_implied(self) -> bool {
+        matches!(self, Count::Implied)
+    }
+
+    pub fn param(self) -> Option<FormatParam<'tcx>> {
+        match self {
+            Count::Param(param) => Some(param),
+            _ => None,
+        }
+    }
+}
+
+/// Specification for the formatting of an argument in the format string. See
+/// <https://doc.rust-lang.org/std/fmt/index.html#formatting-parameters> for the precise meanings.
+#[derive(Debug)]
+pub struct FormatSpec<'tcx> {
+    /// Optionally specified character to fill alignment with.
+    pub fill: Option<char>,
+    /// Optionally specified alignment.
+    pub align: Alignment,
+    /// Packed version of various flags provided, see [`rustc_parse_format::Flag`].
+    pub flags: u32,
+    /// Represents either the maximum width or the integer precision.
+    pub precision: Count<'tcx>,
+    /// The minimum width, will be padded according to `width`/`align`
+    pub width: Count<'tcx>,
+    /// The formatting trait used by the argument, e.g. `sym::Display` for `{}`, `sym::Debug` for
+    /// `{:?}`.
+    pub r#trait: Symbol,
+    pub trait_span: Option<Span>,
+}
+
+impl<'tcx> FormatSpec<'tcx> {
+    fn new(spec: rpf::FormatSpec<'_>, positions: ParamPosition, values: &FormatArgsValues<'tcx>) -> Option<Self> {
+        Some(Self {
+            fill: spec.fill,
+            align: spec.align,
+            flags: spec.flags,
+            precision: Count::new(spec.precision, positions.precision, spec.precision_span, values)?,
+            width: Count::new(spec.width, positions.width, spec.width_span, values)?,
+            r#trait: match spec.ty {
+                "" => sym::Display,
+                "?" => sym::Debug,
+                "o" => sym!(Octal),
+                "x" => sym!(LowerHex),
+                "X" => sym!(UpperHex),
+                "p" => sym::Pointer,
+                "b" => sym!(Binary),
+                "e" => sym!(LowerExp),
+                "E" => sym!(UpperExp),
+                _ => return None,
+            },
+            trait_span: spec
+                .ty_span
+                .map(|span| span_from_inner(values.format_string_span, span)),
         })
     }
 
-    /// Finds a nested call to `format_args!` within a `format!`-like macro call
+    /// Returns true if this format spec would change the contents of a string when formatted
+    pub fn has_string_formatting(&self) -> bool {
+        self.r#trait != sym::Display || !self.width.is_implied() || !self.precision.is_implied()
+    }
+}
+
+/// A format argument, such as `{}`, `{foo:?}`.
+#[derive(Debug)]
+pub struct FormatArg<'tcx> {
+    /// The parameter the argument refers to.
+    pub param: FormatParam<'tcx>,
+    /// How to format `param`.
+    pub format: FormatSpec<'tcx>,
+    /// span of the whole argument, `{..}`.
+    pub span: Span,
+}
+
+/// A parsed `format_args!` expansion.
+#[derive(Debug)]
+pub struct FormatArgsExpn<'tcx> {
+    /// The format string literal.
+    pub format_string: FormatString,
+    // The format arguments, such as `{:?}`.
+    pub args: Vec<FormatArg<'tcx>>,
+    /// Has an added newline due to `println!()`/`writeln!()`/etc. The last format string part will
+    /// include this added newline.
+    pub newline: bool,
+    /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for
+    /// `format!("{x} {} {y}", 1, z + 2)`.
+    value_args: Vec<&'tcx Expr<'tcx>>,
+}
+
+impl<'tcx> FormatArgsExpn<'tcx> {
+    pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<Self> {
+        let macro_name = macro_backtrace(expr.span)
+            .map(|macro_call| cx.tcx.item_name(macro_call.def_id))
+            .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?;
+        let newline = macro_name == sym::format_args_nl;
+
+        // ::core::fmt::Arguments::new_v1(pieces, args)
+        // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg)
+        if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind
+            && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind
+            && is_path_diagnostic_item(cx, ty, sym::Arguments)
+            && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted")
+        {
+            let format_string = FormatString::new(cx, pieces)?;
+
+            let mut parser = rpf::Parser::new(
+                &format_string.unescaped,
+                format_string.style,
+                Some(format_string.snippet.clone()),
+                // `format_string.unescaped` does not contain the appended newline
+                false,
+                rpf::ParseMode::Format,
+            );
+
+            let parsed_args = parser
+                .by_ref()
+                .filter_map(|piece| match piece {
+                    rpf::Piece::NextArgument(a) => Some(a),
+                    rpf::Piece::String(_) => None,
+                })
+                .collect_vec();
+            if !parser.errors.is_empty() {
+                return None;
+            }
+
+            let positions = if let Some(fmt_arg) = rest.first() {
+                // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse
+                // them.
+
+                Either::Left(parse_rt_fmt(fmt_arg)?)
+            } else {
+                // If no format specs are given, the positions are in the given order and there are
+                // no `precision`/`width`s to consider.
+
+                Either::Right((0..).map(|n| ParamPosition {
+                    value: n,
+                    width: None,
+                    precision: None,
+                }))
+            };
+
+            let values = FormatArgsValues::new(args, format_string.span.data());
+
+            let args = izip!(positions, parsed_args, parser.arg_places)
+                .map(|(position, parsed_arg, arg_span)| {
+                    Some(FormatArg {
+                        param: FormatParam::new(
+                            match parsed_arg.position {
+                                rpf::Position::ArgumentImplicitlyIs(_) => FormatParamKind::Implicit,
+                                rpf::Position::ArgumentIs(_) => FormatParamKind::Numbered,
+                                // NamedInline is handled by `FormatParam::new()`
+                                rpf::Position::ArgumentNamed(name) => FormatParamKind::Named(Symbol::intern(name)),
+                            },
+                            position.value,
+                            parsed_arg.position_span,
+                            &values,
+                        )?,
+                        format: FormatSpec::new(parsed_arg.format, position, &values)?,
+                        span: span_from_inner(values.format_string_span, arg_span),
+                    })
+                })
+                .collect::<Option<Vec<_>>>()?;
+
+            Some(Self {
+                format_string,
+                args,
+                value_args: values.value_args,
+                newline,
+            })
+        } else {
+            None
+        }
+    }
+
     pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option<Self> {
         let mut format_args = None;
         expr_visitor_no_bodies(|e| {
@@ -466,88 +845,23 @@ pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: Expn
         format_args
     }
 
-    /// Returns a vector of `FormatArgsArg`.
-    pub fn args(&self) -> Option<Vec<FormatArgsArg<'tcx>>> {
-        if self.specs.is_empty() {
-            let args = std::iter::zip(&self.value_args, &self.formatters)
-                .map(|(value, &(_, format_trait))| FormatArgsArg {
-                    value,
-                    format_trait,
-                    spec: None,
-                })
-                .collect();
-            return Some(args);
-        }
-        self.specs
-            .iter()
-            .map(|spec| {
-                if_chain! {
-                    // struct `core::fmt::rt::v1::Argument`
-                    if let ExprKind::Struct(_, fields, _) = spec.kind;
-                    if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position);
-                    if let ExprKind::Lit(lit) = &position_field.expr.kind;
-                    if let LitKind::Int(position, _) = lit.node;
-                    if let Ok(i) = usize::try_from(position);
-                    if let Some(&(j, format_trait)) = self.formatters.get(i);
-                    then {
-                        Some(FormatArgsArg {
-                            value: self.value_args[j],
-                            format_trait,
-                            spec: Some(spec),
-                        })
-                    } else {
-                        None
-                    }
-                }
-            })
-            .collect()
-    }
-
     /// Source callsite span of all inputs
     pub fn inputs_span(&self) -> Span {
         match *self.value_args {
-            [] => self.format_string_span,
+            [] => self.format_string.span,
             [.., last] => self
-                .format_string_span
-                .to(hygiene::walk_chain(last.span, self.format_string_span.ctxt())),
+                .format_string
+                .span
+                .to(hygiene::walk_chain(last.span, self.format_string.span.ctxt())),
         }
     }
-}
 
-/// Type representing a `FormatArgsExpn`'s format arguments
-pub struct FormatArgsArg<'tcx> {
-    /// An element of `value_args` according to `position`
-    pub value: &'tcx Expr<'tcx>,
-    /// An element of `args` according to `position`
-    pub format_trait: Symbol,
-    /// An element of `specs`
-    pub spec: Option<&'tcx Expr<'tcx>>,
-}
-
-impl<'tcx> FormatArgsArg<'tcx> {
-    /// Returns true if any formatting parameters are used that would have an effect on strings,
-    /// like `{:+2}` instead of just `{}`.
-    pub fn has_string_formatting(&self) -> bool {
-        self.spec.map_or(false, |spec| {
-            // `!` because these conditions check that `self` is unformatted.
-            !if_chain! {
-                // struct `core::fmt::rt::v1::Argument`
-                if let ExprKind::Struct(_, fields, _) = spec.kind;
-                if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
-                // struct `core::fmt::rt::v1::FormatSpec`
-                if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind;
-                if subfields.iter().all(|field| match field.ident.name {
-                    sym::precision | sym::width => match field.expr.kind {
-                        ExprKind::Path(QPath::Resolved(_, path)) => {
-                            path.segments.last().unwrap().ident.name == sym::Implied
-                        }
-                        _ => false,
-                    }
-                    _ => true,
-                });
-                then { true } else { false }
-            }
-        })
+    /// Iterator of all format params, both values and those referenced by `width`/`precision`s.
+    pub fn params(&'tcx self) -> impl Iterator<Item = FormatParam<'tcx>> {
+        self.args
+            .iter()
+            .flat_map(|arg| [Some(arg.param), arg.format.precision.param(), arg.format.width.param()])
+            .flatten()
     }
 }
 
index 9e238c6f1ac0ef84a8883d8d6c84d695ccd28cfd..62020e21c81552a98e28c431396cdb18cde6c85d 100644 (file)
@@ -13,7 +13,7 @@ macro_rules! msrv_aliases {
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
     1,62,0 { BOOL_THEN_SOME }
-    1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN }
+    1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
     1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
     1,51,0 { BORROW_AS_PTR, UNSIGNED_ABS }
     1,50,0 { BOOL_THEN }
@@ -32,8 +32,8 @@ macro_rules! msrv_aliases {
     1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
     1,28,0 { FROM_BOOL }
     1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
+    1,24,0 { IS_ASCII_DIGIT }
     1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN }
     1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
     1,16,0 { STR_REPEAT }
-    1,24,0 { IS_ASCII_DIGIT }
 }
index 8d697a301c444c354efd1ee383a5be24eae64099..fb0d34e02eece6b1d67c0ff67f498c36ee137d74 100644 (file)
@@ -71,7 +71,6 @@
 pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"];
 pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"];
 pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
 #[cfg(feature = "internal")]
 pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
@@ -96,6 +95,7 @@
 pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"];
 pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
 pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
+pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"];
 pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
 #[cfg_attr(not(unix), allow(clippy::invalid_paths))]
 pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"];
index e7d670766a050203793c22970b12c09bc26c2806..5a7f9568441c90acb857177748168c1f763772ca 100644 (file)
@@ -43,14 +43,6 @@ pub fn can_partially_move_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool
     }
 }
 
-/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty`
-pub fn contains_ty<'tcx>(ty: Ty<'tcx>, other_ty: Ty<'tcx>) -> bool {
-    ty.walk().any(|inner| match inner.unpack() {
-        GenericArgKind::Type(inner_ty) => other_ty == inner_ty,
-        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
-    })
-}
-
 /// Walks into `ty` and returns `true` if any inner type is an instance of the given adt
 /// constructor.
 pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool {
@@ -410,7 +402,7 @@ fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
     peel(ty, 0)
 }
 
-/// Peels off all references on the type.Returns the underlying type, the number of references
+/// Peels off all references on the type. Returns the underlying type, the number of references
 /// removed, and whether the pointer is ultimately mutable or not.
 pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
     fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) {
@@ -839,3 +831,53 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc
         })
         .unwrap_or(false)
 }
+
+/// Comes up with an "at least" guesstimate for the type's size, not taking into
+/// account the layout of type parameters.
+pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
+    use rustc_middle::ty::layout::LayoutOf;
+    if !is_normalizable(cx, cx.param_env, ty) {
+        return 0;
+    }
+    match (cx.layout_of(ty).map(|layout| layout.size.bytes()), ty.kind()) {
+        (Ok(size), _) => size,
+        (Err(_), ty::Tuple(list)) => list.as_substs().types().map(|t| approx_ty_size(cx, t)).sum(),
+        (Err(_), ty::Array(t, n)) => {
+            n.try_eval_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t)
+        },
+        (Err(_), ty::Adt(def, subst)) if def.is_struct() => def
+            .variants()
+            .iter()
+            .map(|v| {
+                v.fields
+                    .iter()
+                    .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst)))
+                    .sum::<u64>()
+            })
+            .sum(),
+        (Err(_), ty::Adt(def, subst)) if def.is_enum() => def
+            .variants()
+            .iter()
+            .map(|v| {
+                v.fields
+                    .iter()
+                    .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst)))
+                    .sum::<u64>()
+            })
+            .max()
+            .unwrap_or_default(),
+        (Err(_), ty::Adt(def, subst)) if def.is_union() => def
+            .variants()
+            .iter()
+            .map(|v| {
+                v.fields
+                    .iter()
+                    .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst)))
+                    .max()
+                    .unwrap_or_default()
+            })
+            .max()
+            .unwrap_or_default(),
+        (Err(_), _) => 0,
+    }
+}
index 7e14df4feea66316953a53425dcde75eee8bf066..85b60fefd60fc4ab84a271c50ebc510bd7449221 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-08-11"
+channel = "nightly-2022-08-27"
 components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
index 5f289918a7c1306e8d908c7456e0c922dd36ef37..429dddc42ea9157f6830be6792489b3ab3d08f95 100644 (file)
@@ -84,7 +84,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 #[must_use]
 pub fn get_commit_hash() -> Option<String> {
     std::process::Command::new("git")
-        .args(&["rev-parse", "--short", "HEAD"])
+        .args(["rev-parse", "--short", "HEAD"])
         .output()
         .ok()
         .and_then(|r| String::from_utf8(r.stdout).ok())
@@ -93,7 +93,7 @@ pub fn get_commit_hash() -> Option<String> {
 #[must_use]
 pub fn get_commit_date() -> Option<String> {
     std::process::Command::new("git")
-        .args(&["log", "-1", "--date=short", "--pretty=format:%cd"])
+        .args(["log", "-1", "--date=short", "--pretty=format:%cd"])
         .output()
         .ok()
         .and_then(|r| String::from_utf8(r.stdout).ok())
index 0defd45b68b064745537b02321f5bb2b56c688aa..e106583de4a2eb0a099d145cafe71b60453c2ef2 100644 (file)
@@ -13,7 +13,7 @@ fn fmt() {
     let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     let output = Command::new("cargo")
         .current_dir(root_dir)
-        .args(&["dev", "fmt", "--check"])
+        .args(["dev", "fmt", "--check"])
         .output()
         .unwrap();
 
index 92ac1a2be56142e896c4ea0a9226055bbda56ea3..ba6186e599e9637f0481df911ab18085ee3a441f 100644 (file)
@@ -393,8 +393,8 @@ fn compile_test() {
     "search_is_some.rs",
     "single_component_path_imports_nested_first.rs",
     "string_add.rs",
+    "suspicious_to_owned.rs",
     "toplevel_ref_arg_non_rustfix.rs",
-    "trait_duplication_in_bounds.rs",
     "unit_arg.rs",
     "unnecessary_clone.rs",
     "unnecessary_lazy_eval_unfixable.rs",
@@ -404,16 +404,23 @@ fn compile_test() {
 ];
 
 fn check_rustfix_coverage() {
-    let missing_coverage_path = Path::new("target/debug/test/ui/rustfix_missing_coverage.txt");
+    let missing_coverage_path = Path::new("debug/test/ui/rustfix_missing_coverage.txt");
+    let missing_coverage_path = if let Ok(target_dir) = std::env::var("CARGO_TARGET_DIR") {
+        PathBuf::from(target_dir).join(missing_coverage_path)
+    } else {
+        missing_coverage_path.to_path_buf()
+    };
 
     if let Ok(missing_coverage_contents) = std::fs::read_to_string(missing_coverage_path) {
         assert!(RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS.iter().is_sorted_by_key(Path::new));
 
-        for rs_path in missing_coverage_contents.lines() {
-            if Path::new(rs_path).starts_with("tests/ui/crashes") {
+        for rs_file in missing_coverage_contents.lines() {
+            let rs_path = Path::new(rs_file);
+            if rs_path.starts_with("tests/ui/crashes") {
                 continue;
             }
-            let filename = Path::new(rs_path).strip_prefix("tests/ui/").unwrap();
+            assert!(rs_path.starts_with("tests/ui/"), "{:?}", rs_file);
+            let filename = rs_path.strip_prefix("tests/ui/").unwrap();
             assert!(
                 RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS
                     .binary_search_by_key(&filename, Path::new)
@@ -421,7 +428,7 @@ fn check_rustfix_coverage() {
                 "`{}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \
                 Please either add `// run-rustfix` at the top of the file or add the file to \
                 `RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS` in `tests/compile-test.rs`.",
-                rs_path,
+                rs_file,
             );
         }
     }
index 5697e8680cd6f86779a303edfd5b63d940e8da14..961525bbd9101dfbc6759f69ba3f05d7aa94e170 100644 (file)
@@ -87,11 +87,11 @@ fn run_clippy_for_package(project: &str, args: &[&str]) {
 
     if cfg!(feature = "internal") {
         // internal lints only exist if we build with the internal feature
-        command.args(&["-D", "clippy::internal"]);
+        command.args(["-D", "clippy::internal"]);
     } else {
         // running a clippy built without internal lints on the clippy source
         // that contains e.g. `allow(clippy::invalid_paths)`
-        command.args(&["-A", "unknown_lints"]);
+        command.args(["-A", "unknown_lints"]);
     }
 
     let output = command.output().unwrap();
index c64425fa01a42a36b8351e934ae81523d75b7129..23a9bef3ccceaee4b9df52ecb40afb848e8f1873 100644 (file)
@@ -19,7 +19,7 @@ fn integration_test() {
     repo_dir.push(crate_name);
 
     let st = Command::new("git")
-        .args(&[
+        .args([
             OsStr::new("clone"),
             OsStr::new("--depth=1"),
             OsStr::new(&repo_url),
@@ -37,7 +37,7 @@ fn integration_test() {
         .current_dir(repo_dir)
         .env("RUST_BACKTRACE", "full")
         .env("CARGO_TARGET_DIR", target_dir)
-        .args(&[
+        .args([
             "clippy",
             "--all-targets",
             "--all-features",
index c3aae1a9aa2d01992ee0c00b6c847bc869b033d0..2e0f4e76075b38a1eaec8e6380001dcd5109886a 100644 (file)
@@ -19,7 +19,7 @@ fn new(path: PathBuf) -> Self {
         // we don't want the first letter after "error: ", "help: " ... to be capitalized
         // also no punctuation (except for "?" ?) at the end of a line
         static REGEX_SET: LazyLock<RegexSet> = LazyLock::new(|| {
-            RegexSet::new(&[
+            RegexSet::new([
                 r"error: [A-Z]",
                 r"help: [A-Z]",
                 r"warning: [A-Z]",
@@ -37,7 +37,7 @@ fn new(path: PathBuf) -> Self {
         // sometimes the first character is capitalized and it is legal (like in "C-like enum variants") or
         // we want to ask a question ending in "?"
         static EXCEPTIONS_SET: LazyLock<RegexSet> = LazyLock::new(|| {
-            RegexSet::new(&[
+            RegexSet::new([
                 r"\.\.\.$",
                 r".*C-like enum variant discriminant is not portable to 32-bit targets",
                 r".*Intel x86 assembly syntax used",
index 9f8e778b3b9d1d36b526de62226c03462ab1dff4..a52a0b5289fe4839f22bc68f9ec1bbfb206fc6e2 100644 (file)
@@ -19,6 +19,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            enforced-import-renames
            enum-variant-name-threshold
            enum-variant-size-threshold
+           large-error-threshold
            literal-representation-threshold
            max-fn-params-bools
            max-include-file-size
index 0d65071af15ed1c4694daec5b20dac9baa96e56a..6f0485b5279b1112c173c8a5d07cfcbb872bd0d3 100644 (file)
@@ -14,31 +14,31 @@ fn is_rust_file(filename: &str) -> bool {
 
 fn main() {
     // std::string::String and &str should trigger the lint failure with .ext12
-    let _ = String::from("").ends_with(".ext12");
+    let _ = String::new().ends_with(".ext12");
     let _ = "str".ends_with(".ext12");
 
     // The test struct should not trigger the lint failure with .ext12
     TestStruct {}.ends_with(".ext12");
 
     // std::string::String and &str should trigger the lint failure with .EXT12
-    let _ = String::from("").ends_with(".EXT12");
+    let _ = String::new().ends_with(".EXT12");
     let _ = "str".ends_with(".EXT12");
 
     // The test struct should not trigger the lint failure with .EXT12
     TestStruct {}.ends_with(".EXT12");
 
     // Should not trigger the lint failure with .eXT12
-    let _ = String::from("").ends_with(".eXT12");
+    let _ = String::new().ends_with(".eXT12");
     let _ = "str".ends_with(".eXT12");
     TestStruct {}.ends_with(".eXT12");
 
     // Should not trigger the lint failure with .EXT123 (too long)
-    let _ = String::from("").ends_with(".EXT123");
+    let _ = String::new().ends_with(".EXT123");
     let _ = "str".ends_with(".EXT123");
     TestStruct {}.ends_with(".EXT123");
 
     // Shouldn't fail if it doesn't start with a dot
-    let _ = String::from("").ends_with("a.ext");
+    let _ = String::new().ends_with("a.ext");
     let _ = "str".ends_with("a.extA");
     TestStruct {}.ends_with("a.ext");
 }
index 05b98169f2d17b0dd1be7812b07acd5236fb566b..5d9a043edb9a5357dbce51e67c236a5f838901a2 100644 (file)
@@ -8,10 +8,10 @@ LL |     filename.ends_with(".rs")
    = help: consider using a case-insensitive comparison instead
 
 error: case-sensitive file extension comparison
-  --> $DIR/case_sensitive_file_extension_comparisons.rs:17:30
+  --> $DIR/case_sensitive_file_extension_comparisons.rs:17:27
    |
-LL |     let _ = String::from("").ends_with(".ext12");
-   |                              ^^^^^^^^^^^^^^^^^^^
+LL |     let _ = String::new().ends_with(".ext12");
+   |                           ^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using a case-insensitive comparison instead
 
@@ -24,10 +24,10 @@ LL |     let _ = "str".ends_with(".ext12");
    = help: consider using a case-insensitive comparison instead
 
 error: case-sensitive file extension comparison
-  --> $DIR/case_sensitive_file_extension_comparisons.rs:24:30
+  --> $DIR/case_sensitive_file_extension_comparisons.rs:24:27
    |
-LL |     let _ = String::from("").ends_with(".EXT12");
-   |                              ^^^^^^^^^^^^^^^^^^^
+LL |     let _ = String::new().ends_with(".EXT12");
+   |                           ^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using a case-insensitive comparison instead
 
diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed
new file mode 100644 (file)
index 0000000..b70c191
--- /dev/null
@@ -0,0 +1,24 @@
+// run-rustfix
+#![warn(clippy::cast_slice_from_raw_parts)]
+
+#[allow(unused_imports, unused_unsafe)]
+fn main() {
+    let mut vec = vec![0u8; 1];
+    let ptr: *const u8 = vec.as_ptr();
+    let mptr = vec.as_mut_ptr();
+    let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) };
+    let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) };
+    let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+    {
+        use core::slice;
+        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+        use slice as one;
+        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+    }
+    {
+        use std::slice;
+        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+        use slice as one;
+        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs
new file mode 100644 (file)
index 0000000..c1b3167
--- /dev/null
@@ -0,0 +1,24 @@
+// run-rustfix
+#![warn(clippy::cast_slice_from_raw_parts)]
+
+#[allow(unused_imports, unused_unsafe)]
+fn main() {
+    let mut vec = vec![0u8; 1];
+    let ptr: *const u8 = vec.as_ptr();
+    let mptr = vec.as_mut_ptr();
+    let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] };
+    let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] };
+    let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8];
+    {
+        use core::slice;
+        let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+        use slice as one;
+        let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+    }
+    {
+        use std::slice;
+        let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+        use slice as one;
+        let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr
new file mode 100644 (file)
index 0000000..f07801c
--- /dev/null
@@ -0,0 +1,46 @@
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:9:35
+   |
+LL |     let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+   |
+   = note: `-D clippy::cast-slice-from-raw-parts` implied by `-D warnings`
+
+error: casting the result of `from_raw_parts_mut` to *mut [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:10:35
+   |
+LL |     let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:11:26
+   |
+LL |     let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8];
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:14:30
+   |
+LL |         let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:16:30
+   |
+LL |         let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:20:30
+   |
+LL |         let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:22:30
+   |
+LL |         let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.fixed b/src/tools/clippy/tests/ui/collapsible_str_replace.fixed
new file mode 100644 (file)
index 0000000..49fc9a9
--- /dev/null
@@ -0,0 +1,73 @@
+// run-rustfix
+
+#![warn(clippy::collapsible_str_replace)]
+
+fn get_filter() -> char {
+    'u'
+}
+
+fn main() {
+    let d = 'd';
+    let p = 'p';
+    let s = 's';
+    let u = 'u';
+    let l = "l";
+
+    let mut iter = ["l", "z"].iter();
+
+    // LINT CASES
+    let _ = "hesuo worpd".replace(['s', 'u'], "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u'], l);
+
+    let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l");
+
+    let _ = "hesuo worpd"
+        .replace(['s', 'u', 'p', 'd'], "l");
+
+    let _ = "hesuo world".replace([s, 'u'], "l");
+
+    let _ = "hesuo worpd".replace([s, 'u', 'p'], "l");
+
+    let _ = "hesuo worpd".replace([s, u, 'p'], "l");
+
+    let _ = "hesuo worpd".replace([s, u, p], "l");
+
+    let _ = "hesuo worlp".replace(['s', 'u'], "l").replace('p', "d");
+
+    let _ = "hesuo worpd".replace('s', "x").replace(['u', 'p'], "l");
+
+    // Note: Future iterations could lint `replace(|c| matches!(c, "su" | 'd' | 'p'), "l")`
+    let _ = "hesudo worpd".replace("su", "l").replace(['d', 'p'], "l");
+
+    let _ = "hesudo worpd".replace([d, 'p'], "l").replace("su", "l");
+
+    let _ = "hesuo world".replace([get_filter(), 's'], "l");
+
+    // NO LINT CASES
+    let _ = "hesuo world".replace('s', "l").replace('u', "p");
+
+    let _ = "hesuo worpd".replace('s', "l").replace('p', l);
+
+    let _ = "hesudo worpd".replace('d', "l").replace("su", "l").replace('p', "l");
+
+    // Note: Future iterations of `collapsible_str_replace` might lint this and combine to `[s, u, p]`
+    let _ = "hesuo worpd".replace([s, u], "l").replace([u, p], "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u'], "l").replace(['u', 'p'], "l");
+
+    let _ = "hesuo worpd".replace('s', "l").replace(['u', 'p'], "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l").replace('r', "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u', 'p'], l).replace('r', l);
+
+    let _ = "hesuo worpd".replace(['s', u, 'p'], "l").replace('r', "l");
+
+    let _ = "hesuo worpd".replace([s, u], "l").replace(p, "l");
+
+    // Regression test
+    let _ = "hesuo worpd"
+        .replace('u', iter.next().unwrap())
+        .replace('s', iter.next().unwrap());
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.rs b/src/tools/clippy/tests/ui/collapsible_str_replace.rs
new file mode 100644 (file)
index 0000000..e3e25c4
--- /dev/null
@@ -0,0 +1,76 @@
+// run-rustfix
+
+#![warn(clippy::collapsible_str_replace)]
+
+fn get_filter() -> char {
+    'u'
+}
+
+fn main() {
+    let d = 'd';
+    let p = 'p';
+    let s = 's';
+    let u = 'u';
+    let l = "l";
+
+    let mut iter = ["l", "z"].iter();
+
+    // LINT CASES
+    let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
+
+    let _ = "hesuo worpd".replace('s', l).replace('u', l);
+
+    let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l");
+
+    let _ = "hesuo worpd"
+        .replace('s', "l")
+        .replace('u', "l")
+        .replace('p', "l")
+        .replace('d', "l");
+
+    let _ = "hesuo world".replace(s, "l").replace('u', "l");
+
+    let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l");
+
+    let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l");
+
+    let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l");
+
+    let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d");
+
+    let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l");
+
+    // Note: Future iterations could lint `replace(|c| matches!(c, "su" | 'd' | 'p'), "l")`
+    let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l");
+
+    let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l");
+
+    let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l");
+
+    // NO LINT CASES
+    let _ = "hesuo world".replace('s', "l").replace('u', "p");
+
+    let _ = "hesuo worpd".replace('s', "l").replace('p', l);
+
+    let _ = "hesudo worpd".replace('d', "l").replace("su", "l").replace('p', "l");
+
+    // Note: Future iterations of `collapsible_str_replace` might lint this and combine to `[s, u, p]`
+    let _ = "hesuo worpd".replace([s, u], "l").replace([u, p], "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u'], "l").replace(['u', 'p'], "l");
+
+    let _ = "hesuo worpd".replace('s', "l").replace(['u', 'p'], "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l").replace('r', "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u', 'p'], l).replace('r', l);
+
+    let _ = "hesuo worpd".replace(['s', u, 'p'], "l").replace('r', "l");
+
+    let _ = "hesuo worpd".replace([s, u], "l").replace(p, "l");
+
+    // Regression test
+    let _ = "hesuo worpd"
+        .replace('u', iter.next().unwrap())
+        .replace('s', iter.next().unwrap());
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.stderr b/src/tools/clippy/tests/ui/collapsible_str_replace.stderr
new file mode 100644 (file)
index 0000000..8e3daf3
--- /dev/null
@@ -0,0 +1,86 @@
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:19:27
+   |
+LL |     let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
+   |
+   = note: `-D clippy::collapsible-str-replace` implied by `-D warnings`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:21:27
+   |
+LL |     let _ = "hesuo worpd".replace('s', l).replace('u', l);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], l)`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:23:27
+   |
+LL |     let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u', 'p'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:26:10
+   |
+LL |           .replace('s', "l")
+   |  __________^
+LL | |         .replace('u', "l")
+LL | |         .replace('p', "l")
+LL | |         .replace('d', "l");
+   | |__________________________^ help: replace with: `replace(['s', 'u', 'p', 'd'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:31:27
+   |
+LL |     let _ = "hesuo world".replace(s, "l").replace('u', "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:33:27
+   |
+LL |     let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u', 'p'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:35:27
+   |
+LL |     let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, 'p'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:37:27
+   |
+LL |     let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, p], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:39:27
+   |
+LL |     let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:41:45
+   |
+LL |     let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l");
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['u', 'p'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:44:47
+   |
+LL |     let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l");
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['d', 'p'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:46:28
+   |
+LL |     let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l");
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([d, 'p'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:48:27
+   |
+LL |     let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([get_filter(), 's'], "l")`
+
+error: aborting due to 13 previous errors
+
index 1073acf6f0cd66b51c33588bfa7296e1a9364a57..d742595e14d4c17dfd987a6dbaab4aca98916da5 100644 (file)
@@ -6,8 +6,9 @@ fn expect_option() {
 }
 
 fn expect_result() {
-    let res: Result<u8, ()> = Ok(0);
+    let res: Result<u8, u8> = Ok(0);
     let _ = res.expect("");
+    let _ = res.expect_err("");
 }
 
 fn main() {
index ab28aac45563b1cd7bfd3192ad5b192f86638451..904c090464523c17dce9196547b56f306115afdb 100644 (file)
@@ -15,5 +15,13 @@ LL |     let _ = res.expect("");
    |
    = help: if this value is an `Err`, it will panic
 
-error: aborting due to 2 previous errors
+error: used `expect_err()` on `a Result` value
+  --> $DIR/expect.rs:11:13
+   |
+LL |     let _ = res.expect_err("");
+   |             ^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this value is an `Ok`, it will panic
+
+error: aborting due to 3 previous errors
 
index ae7805fdf018eea7228cecc02adcb4781173768e..c86a502d15f0967fcf2e448d62f35f0886bdeff9 100644 (file)
@@ -5,6 +5,7 @@ fn main() {
     let x = 2f32;
     let _ = x.exp_m1();
     let _ = x.exp_m1() + 2.0;
+    let _ = (x as f32).exp_m1() + 2.0;
     // Cases where the lint shouldn't be applied
     let _ = x.exp() - 2.0;
     let _ = x.exp() - 1.0 * 2.0;
index 27e0b9bcbc937a829e9e1d9ce7d7fb286c0c63d6..e59589f912a21accd00d9d9306a70b5df937197a 100644 (file)
@@ -5,6 +5,7 @@ fn main() {
     let x = 2f32;
     let _ = x.exp() - 1.0;
     let _ = x.exp() - 1.0 + 2.0;
+    let _ = (x as f32).exp() - 1.0 + 2.0;
     // Cases where the lint shouldn't be applied
     let _ = x.exp() - 2.0;
     let _ = x.exp() - 1.0 * 2.0;
index 5cd999ad47cdd0d768138c901b1a9df01d891d8b..f84eede19872a2923b409a5d32c3fddb5f03e8b7 100644 (file)
@@ -13,16 +13,22 @@ LL |     let _ = x.exp() - 1.0 + 2.0;
    |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
 
 error: (e.pow(x) - 1) can be computed more accurately
-  --> $DIR/floating_point_exp.rs:13:13
+  --> $DIR/floating_point_exp.rs:8:13
+   |
+LL |     let _ = (x as f32).exp() - 1.0 + 2.0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).exp_m1()`
+
+error: (e.pow(x) - 1) can be computed more accurately
+  --> $DIR/floating_point_exp.rs:14:13
    |
 LL |     let _ = x.exp() - 1.0;
    |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
 
 error: (e.pow(x) - 1) can be computed more accurately
-  --> $DIR/floating_point_exp.rs:14:13
+  --> $DIR/floating_point_exp.rs:15:13
    |
 LL |     let _ = x.exp() - 1.0 + 2.0;
    |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
index 5b487bb8fcf790cae0bb771ae964327b04036cc5..4def9300bb7d2f70dae72beb47af6be5586fd03c 100644 (file)
@@ -12,6 +12,7 @@ fn check_log_base() {
     let _ = x.ln();
     let _ = x.log2();
     let _ = x.ln();
+    let _ = (x as f32).log2();
 
     let x = 1f64;
     let _ = x.log2();
index 01181484e7dee290c0973d60a38a93bd71062905..1e04caa7d2a865070f83c44e465dfe672ea1514a 100644 (file)
@@ -12,6 +12,7 @@ fn check_log_base() {
     let _ = x.log(std::f32::consts::E);
     let _ = x.log(TWO);
     let _ = x.log(E);
+    let _ = (x as f32).log(2f32);
 
     let x = 1f64;
     let _ = x.log(2f64);
index 96e5a15444170f4fd2d9453ac15774af596f86d7..89800a13a6ecc75ed966bc41d57b090427b0fc50 100644 (file)
@@ -31,25 +31,31 @@ LL |     let _ = x.log(E);
    |             ^^^^^^^^ help: consider using: `x.ln()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> $DIR/floating_point_log.rs:17:13
+  --> $DIR/floating_point_log.rs:15:13
+   |
+LL |     let _ = (x as f32).log(2f32);
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log2()`
+
+error: logarithm for bases 2, 10 and e can be computed more accurately
+  --> $DIR/floating_point_log.rs:18:13
    |
 LL |     let _ = x.log(2f64);
    |             ^^^^^^^^^^^ help: consider using: `x.log2()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> $DIR/floating_point_log.rs:18:13
+  --> $DIR/floating_point_log.rs:19:13
    |
 LL |     let _ = x.log(10f64);
    |             ^^^^^^^^^^^^ help: consider using: `x.log10()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> $DIR/floating_point_log.rs:19:13
+  --> $DIR/floating_point_log.rs:20:13
    |
 LL |     let _ = x.log(std::f64::consts::E);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:24:13
+  --> $DIR/floating_point_log.rs:25:13
    |
 LL |     let _ = (1f32 + 2.).ln();
    |             ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
@@ -57,118 +63,118 @@ LL |     let _ = (1f32 + 2.).ln();
    = note: `-D clippy::imprecise-flops` implied by `-D warnings`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:25:13
+  --> $DIR/floating_point_log.rs:26:13
    |
 LL |     let _ = (1f32 + 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:26:13
+  --> $DIR/floating_point_log.rs:27:13
    |
 LL |     let _ = (1.0 + x).ln();
    |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:27:13
+  --> $DIR/floating_point_log.rs:28:13
    |
 LL |     let _ = (1.0 + x / 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:28:13
+  --> $DIR/floating_point_log.rs:29:13
    |
 LL |     let _ = (1.0 + x.powi(3)).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:29:13
+  --> $DIR/floating_point_log.rs:30:13
    |
 LL |     let _ = (1.0 + x.powi(3) / 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(3) / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:30:13
+  --> $DIR/floating_point_log.rs:31:13
    |
 LL |     let _ = (1.0 + (std::f32::consts::E - 1.0)).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(std::f32::consts::E - 1.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:31:13
+  --> $DIR/floating_point_log.rs:32:13
    |
 LL |     let _ = (x + 1.0).ln();
    |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:32:13
+  --> $DIR/floating_point_log.rs:33:13
    |
 LL |     let _ = (x.powi(3) + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:33:13
+  --> $DIR/floating_point_log.rs:34:13
    |
 LL |     let _ = (x + 2.0 + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:34:13
+  --> $DIR/floating_point_log.rs:35:13
    |
 LL |     let _ = (x / 2.0 + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:42:13
+  --> $DIR/floating_point_log.rs:43:13
    |
 LL |     let _ = (1f64 + 2.).ln();
    |             ^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:43:13
+  --> $DIR/floating_point_log.rs:44:13
    |
 LL |     let _ = (1f64 + 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:44:13
+  --> $DIR/floating_point_log.rs:45:13
    |
 LL |     let _ = (1.0 + x).ln();
    |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:45:13
+  --> $DIR/floating_point_log.rs:46:13
    |
 LL |     let _ = (1.0 + x / 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:46:13
+  --> $DIR/floating_point_log.rs:47:13
    |
 LL |     let _ = (1.0 + x.powi(3)).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:47:13
+  --> $DIR/floating_point_log.rs:48:13
    |
 LL |     let _ = (x + 1.0).ln();
    |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:48:13
+  --> $DIR/floating_point_log.rs:49:13
    |
 LL |     let _ = (x.powi(3) + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:49:13
+  --> $DIR/floating_point_log.rs:50:13
    |
 LL |     let _ = (x + 2.0 + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:50:13
+  --> $DIR/floating_point_log.rs:51:13
    |
 LL |     let _ = (x / 2.0 + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
 
-error: aborting due to 28 previous errors
+error: aborting due to 29 previous errors
 
index 13962a272d4552b6ccce46a9ff908890e0add9cf..936462f94066f681284506f22daacd4a6706dc84 100644 (file)
@@ -5,6 +5,7 @@ fn main() {
     let x = 3f32;
     let y = 5f32;
     let _ = x.log(y);
+    let _ = (x as f32).log(y);
     let _ = x.log(y);
     let _ = x.log(y);
     let _ = x.log(y);
index 26bc20d5370b1f0a6f678d1b7d54b6fe447487d8..0b56fa8fa41fa3112f63adfeac48176a2909c79e 100644 (file)
@@ -5,6 +5,7 @@ fn main() {
     let x = 3f32;
     let y = 5f32;
     let _ = x.ln() / y.ln();
+    let _ = (x as f32).ln() / y.ln();
     let _ = x.log2() / y.log2();
     let _ = x.log10() / y.log10();
     let _ = x.log(5f32) / y.log(5f32);
index 78354c2f62d432eaf0e9c7a9cd6670bfc3bbc4cf..384e3554cbbe1335f3707ebc03eb52b1015bbdee 100644 (file)
@@ -9,20 +9,26 @@ LL |     let _ = x.ln() / y.ln();
 error: log base can be expressed more clearly
   --> $DIR/floating_point_logbase.rs:8:13
    |
+LL |     let _ = (x as f32).ln() / y.ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log(y)`
+
+error: log base can be expressed more clearly
+  --> $DIR/floating_point_logbase.rs:9:13
+   |
 LL |     let _ = x.log2() / y.log2();
    |             ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
 
 error: log base can be expressed more clearly
-  --> $DIR/floating_point_logbase.rs:9:13
+  --> $DIR/floating_point_logbase.rs:10:13
    |
 LL |     let _ = x.log10() / y.log10();
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
 
 error: log base can be expressed more clearly
-  --> $DIR/floating_point_logbase.rs:10:13
+  --> $DIR/floating_point_logbase.rs:11:13
    |
 LL |     let _ = x.log(5f32) / y.log(5f32);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
index b0641a100cdc810b4a3c7d3d045928970dfe1272..7efe10a10f9e9809db283ef8bf73378a16bbe31a 100644 (file)
@@ -11,10 +11,13 @@ fn main() {
     let _ = (-3.1f32).exp();
     let _ = x.sqrt();
     let _ = x.cbrt();
+    let _ = (x as f32).cbrt();
     let _ = x.powi(3);
     let _ = x.powi(-2);
     let _ = x.powi(16_777_215);
     let _ = x.powi(-16_777_215);
+    let _ = (x as f32).powi(-16_777_215);
+    let _ = (x as f32).powi(3);
     // Cases where the lint shouldn't be applied
     let _ = x.powf(2.1);
     let _ = x.powf(-2.1);
index a0a2c973900f4b7ba943f29a7bb90dcecaf6a8ce..445080417f2ed8c2a0e5b7f1f1a799286077c2f8 100644 (file)
@@ -11,10 +11,13 @@ fn main() {
     let _ = std::f32::consts::E.powf(-3.1);
     let _ = x.powf(1.0 / 2.0);
     let _ = x.powf(1.0 / 3.0);
+    let _ = (x as f32).powf(1.0 / 3.0);
     let _ = x.powf(3.0);
     let _ = x.powf(-2.0);
     let _ = x.powf(16_777_215.0);
     let _ = x.powf(-16_777_215.0);
+    let _ = (x as f32).powf(-16_777_215.0);
+    let _ = (x as f32).powf(3.0);
     // Cases where the lint shouldn't be applied
     let _ = x.powf(2.1);
     let _ = x.powf(-2.1);
index 2422eb911e90a7041dedbecccf2fa2677a12710d..6ee696e6ada5ffda8d5580258d2ec7074bcfee3a 100644 (file)
@@ -50,101 +50,119 @@ LL |     let _ = x.powf(1.0 / 3.0);
    |
    = note: `-D clippy::imprecise-flops` implied by `-D warnings`
 
-error: exponentiation with integer powers can be computed more efficiently
+error: cube-root of a number can be computed more accurately
   --> $DIR/floating_point_powf.rs:14:13
    |
+LL |     let _ = (x as f32).powf(1.0 / 3.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).cbrt()`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:15: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:15:13
+  --> $DIR/floating_point_powf.rs:16: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:16:13
+  --> $DIR/floating_point_powf.rs:17:13
    |
 LL |     let _ = x.powf(16_777_215.0);
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(16_777_215)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:17:13
+  --> $DIR/floating_point_powf.rs:18:13
    |
 LL |     let _ = x.powf(-16_777_215.0);
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-16_777_215)`
 
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:19:13
+   |
+LL |     let _ = (x as f32).powf(-16_777_215.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(-16_777_215)`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:20:13
+   |
+LL |     let _ = (x as f32).powf(3.0);
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(3)`
+
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:25:13
+  --> $DIR/floating_point_powf.rs:28: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:26:13
+  --> $DIR/floating_point_powf.rs:29: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:27:13
+  --> $DIR/floating_point_powf.rs:30: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:28:13
+  --> $DIR/floating_point_powf.rs:31: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:29:13
+  --> $DIR/floating_point_powf.rs:32: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:30:13
+  --> $DIR/floating_point_powf.rs:33: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:31:13
+  --> $DIR/floating_point_powf.rs:34: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:32:13
+  --> $DIR/floating_point_powf.rs:35: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:33:13
+  --> $DIR/floating_point_powf.rs:36: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:34:13
+  --> $DIR/floating_point_powf.rs:37: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:35:13
+  --> $DIR/floating_point_powf.rs:38: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:36:13
+  --> $DIR/floating_point_powf.rs:39:13
    |
 LL |     let _ = x.powf(2_147_483_647.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)`
 
-error: aborting due to 24 previous errors
+error: aborting due to 27 previous errors
 
index 85f7c531e398ae28af7c4056f87c9e1bf4ebd89e..5758db7c6c82d90506cc76a561f5d3ac18dfe021 100644 (file)
@@ -8,6 +8,7 @@ fn main() {
     let y = 4f32;
     let _ = x.mul_add(x, y);
     let _ = y.mul_add(y, x);
+    let _ = (y as f32).mul_add(y as f32, x);
     let _ = x.mul_add(x, y).sqrt();
     let _ = y.mul_add(y, x).sqrt();
     // Cases where the lint shouldn't be applied
index ece61d1bec42d4bb78b2d9bdc0f419369c11805c..5926bf1b0004265c96a82b53a9e8abaefcdedcc2 100644 (file)
@@ -8,6 +8,7 @@ fn main() {
     let y = 4f32;
     let _ = x.powi(2) + y;
     let _ = x + y.powi(2);
+    let _ = x + (y as f32).powi(2);
     let _ = (x.powi(2) + y).sqrt();
     let _ = (x + y.powi(2)).sqrt();
     // Cases where the lint shouldn't be applied
index 37d840988bb23b3b422895d73c09fd6670109bcd..a3c74544212b22e1f082e7d4938b14c60775f062 100644 (file)
@@ -15,14 +15,20 @@ LL |     let _ = x + y.powi(2);
 error: multiply and add expressions can be calculated more efficiently and accurately
   --> $DIR/floating_point_powi.rs:11:13
    |
+LL |     let _ = x + (y as f32).powi(2);
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y as f32).mul_add(y as f32, x)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:12:13
+   |
 LL |     let _ = (x.powi(2) + y).sqrt();
    |             ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
 
 error: multiply and add expressions can be calculated more efficiently and accurately
-  --> $DIR/floating_point_powi.rs:12:13
+  --> $DIR/floating_point_powi.rs:13:13
    |
 LL |     let _ = (x + y.powi(2)).sqrt();
    |             ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
index ce91fe176c6fccec4fee57bc3339f7091e0e8827..27674b8a455b099a30d9f7be60cceb729628e077 100644 (file)
@@ -8,6 +8,11 @@ pub const fn const_context() {
     let _ = x * 180f32 / std::f32::consts::PI;
 }
 
+pub fn issue9391(degrees: i64) {
+    let _ = (degrees as f64).to_radians();
+    let _ = (degrees as f64).to_degrees();
+}
+
 fn main() {
     let x = 3f32;
     let _ = x.to_degrees();
index 8f3234986148b70d302dd0f5ac04852feec89c16..f1ea73df39845d988b5437125ee05a82057eb8bc 100644 (file)
@@ -8,6 +8,11 @@ pub const fn const_context() {
     let _ = x * 180f32 / std::f32::consts::PI;
 }
 
+pub fn issue9391(degrees: i64) {
+    let _ = degrees as f64 * std::f64::consts::PI / 180.0;
+    let _ = degrees as f64 * 180.0 / std::f64::consts::PI;
+}
+
 fn main() {
     let x = 3f32;
     let _ = x * 180f32 / std::f32::consts::PI;
index f12d3d23f3ab93fa38f53d5fc595857872e1d3a2..979442f2c24a371d57d38aa7546e790ef7b5c638 100644 (file)
@@ -1,40 +1,52 @@
+error: conversion to radians can be done more accurately
+  --> $DIR/floating_point_rad.rs:12:13
+   |
+LL |     let _ = degrees as f64 * std::f64::consts::PI / 180.0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_radians()`
+   |
+   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
+
 error: conversion to degrees can be done more accurately
   --> $DIR/floating_point_rad.rs:13:13
    |
+LL |     let _ = degrees as f64 * 180.0 / std::f64::consts::PI;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_degrees()`
+
+error: conversion to degrees can be done more accurately
+  --> $DIR/floating_point_rad.rs:18:13
+   |
 LL |     let _ = x * 180f32 / std::f32::consts::PI;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()`
-   |
-   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
 
 error: conversion to degrees can be done more accurately
-  --> $DIR/floating_point_rad.rs:14:13
+  --> $DIR/floating_point_rad.rs:19:13
    |
 LL |     let _ = 90. * 180f64 / std::f64::consts::PI;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_degrees()`
 
 error: conversion to degrees can be done more accurately
-  --> $DIR/floating_point_rad.rs:15:13
+  --> $DIR/floating_point_rad.rs:20:13
    |
 LL |     let _ = 90.5 * 180f64 / std::f64::consts::PI;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_degrees()`
 
 error: conversion to radians can be done more accurately
-  --> $DIR/floating_point_rad.rs:16:13
+  --> $DIR/floating_point_rad.rs:21:13
    |
 LL |     let _ = x * std::f32::consts::PI / 180f32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()`
 
 error: conversion to radians can be done more accurately
-  --> $DIR/floating_point_rad.rs:17:13
+  --> $DIR/floating_point_rad.rs:22:13
    |
 LL |     let _ = 90. * std::f32::consts::PI / 180f32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_radians()`
 
 error: conversion to radians can be done more accurately
-  --> $DIR/floating_point_rad.rs:18:13
+  --> $DIR/floating_point_rad.rs:23:13
    |
 LL |     let _ = 90.5 * std::f32::consts::PI / 180f32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_radians()`
 
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
 
index 6b754f3bd7103bb3f6ff068ab637acc368f85c7c..b56d6aec508d38bda3189d67fd5610f971166d4e 100644 (file)
@@ -33,7 +33,7 @@ fn main() {
     format!("foo {}", "bar");
     format!("{} bar", "foo");
 
-    let arg: String = "".to_owned();
+    let arg = String::new();
     arg.to_string();
     format!("{:?}", arg); // Don't warn about debug.
     format!("{:8}", arg);
index ca9826b356ec8aea1642450c6f3789244323f071..4c1a3a840ed96721f5cd87d7496c3e1edec99f94 100644 (file)
@@ -35,7 +35,7 @@ fn main() {
     format!("foo {}", "bar");
     format!("{} bar", "foo");
 
-    let arg: String = "".to_owned();
+    let arg = String::new();
     format!("{}", arg);
     format!("{:?}", arg); // Don't warn about debug.
     format!("{:8}", arg);
index 69b5e1c722e0320df446f0fb6a01d74d20fead7f..e1c2d4d70be4f65effd89e0d84edfa3b77fcf3bd 100644 (file)
@@ -1,8 +1,6 @@
 // run-rustfix
 
-#![allow(unreachable_code)]
-#![allow(unused_macros)]
-#![allow(unused_variables)]
+#![allow(unused)]
 #![allow(clippy::assertions_on_constants)]
 #![allow(clippy::eq_op)]
 #![allow(clippy::print_literal)]
@@ -115,3 +113,50 @@ fn main() {
     // https://github.com/rust-lang/rust-clippy/issues/7903
     println!("{foo}{foo:?}", foo = "foo".to_string());
 }
+
+fn issue8643(vendor_id: usize, product_id: usize, name: &str) {
+    println!(
+        "{:<9}  {:<10}  {}",
+        format!("0x{:x}", vendor_id),
+        format!("0x{:x}", product_id),
+        name
+    );
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/8855
+mod issue_8855 {
+    #![allow(dead_code)]
+
+    struct A {}
+
+    impl std::fmt::Display for A {
+        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+            write!(f, "test")
+        }
+    }
+
+    fn main() {
+        let a = A {};
+        let b = A {};
+
+        let x = format!("{} {}", a, b);
+        dbg!(x);
+
+        let x = format!("{:>6} {:>6}", a, b.to_string());
+        dbg!(x);
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/9256
+mod issue_9256 {
+    #![allow(dead_code)]
+
+    fn print_substring(original: &str) {
+        assert!(original.len() > 10);
+        println!("{}", &original[..10]);
+    }
+
+    fn main() {
+        print_substring("Hello, world!");
+    }
+}
index 3a434c5bf002a3350a08a0da2988747de925bcc9..b9a4d66c28ad9f4f85390dc427dca8d08e66bcdc 100644 (file)
@@ -1,8 +1,6 @@
 // run-rustfix
 
-#![allow(unreachable_code)]
-#![allow(unused_macros)]
-#![allow(unused_variables)]
+#![allow(unused)]
 #![allow(clippy::assertions_on_constants)]
 #![allow(clippy::eq_op)]
 #![allow(clippy::print_literal)]
@@ -115,3 +113,50 @@ fn main() {
     // https://github.com/rust-lang/rust-clippy/issues/7903
     println!("{foo}{foo:?}", foo = "foo".to_string());
 }
+
+fn issue8643(vendor_id: usize, product_id: usize, name: &str) {
+    println!(
+        "{:<9}  {:<10}  {}",
+        format!("0x{:x}", vendor_id),
+        format!("0x{:x}", product_id),
+        name
+    );
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/8855
+mod issue_8855 {
+    #![allow(dead_code)]
+
+    struct A {}
+
+    impl std::fmt::Display for A {
+        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+            write!(f, "test")
+        }
+    }
+
+    fn main() {
+        let a = A {};
+        let b = A {};
+
+        let x = format!("{} {}", a, b.to_string());
+        dbg!(x);
+
+        let x = format!("{:>6} {:>6}", a, b.to_string());
+        dbg!(x);
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/9256
+mod issue_9256 {
+    #![allow(dead_code)]
+
+    fn print_substring(original: &str) {
+        assert!(original.len() > 10);
+        println!("{}", original[..10].to_string());
+    }
+
+    fn main() {
+        print_substring("Hello, world!");
+    }
+}
index c0cbca507958d1306cfbf008fb3b1d16e2f3959d..aa6e3659b43b519d19f14fa7ecd395a7d7763bda 100644 (file)
@@ -1,5 +1,5 @@
 error: `to_string` applied to a type that implements `Display` in `format!` args
-  --> $DIR/format_args.rs:76:72
+  --> $DIR/format_args.rs:74:72
    |
 LL |     let _ = format!("error: something failed at {}", Location::caller().to_string());
    |                                                                        ^^^^^^^^^^^^ help: remove this
@@ -7,124 +7,136 @@ LL |     let _ = format!("error: something failed at {}", Location::caller().to_
    = note: `-D clippy::to-string-in-format-args` implied by `-D warnings`
 
 error: `to_string` applied to a type that implements `Display` in `write!` args
-  --> $DIR/format_args.rs:80:27
+  --> $DIR/format_args.rs:78:27
    |
 LL |         Location::caller().to_string()
    |                           ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `writeln!` args
-  --> $DIR/format_args.rs:85:27
+  --> $DIR/format_args.rs:83:27
    |
 LL |         Location::caller().to_string()
    |                           ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `print!` args
-  --> $DIR/format_args.rs:87:63
+  --> $DIR/format_args.rs:85:63
    |
 LL |     print!("error: something failed at {}", Location::caller().to_string());
    |                                                               ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:88:65
+  --> $DIR/format_args.rs:86:65
    |
 LL |     println!("error: something failed at {}", Location::caller().to_string());
    |                                                                 ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `eprint!` args
-  --> $DIR/format_args.rs:89:64
+  --> $DIR/format_args.rs:87:64
    |
 LL |     eprint!("error: something failed at {}", Location::caller().to_string());
    |                                                                ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `eprintln!` args
-  --> $DIR/format_args.rs:90:66
+  --> $DIR/format_args.rs:88:66
    |
 LL |     eprintln!("error: something failed at {}", Location::caller().to_string());
    |                                                                  ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `format_args!` args
-  --> $DIR/format_args.rs:91:77
+  --> $DIR/format_args.rs:89:77
    |
 LL |     let _ = format_args!("error: something failed at {}", Location::caller().to_string());
    |                                                                             ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `assert!` args
-  --> $DIR/format_args.rs:92:70
+  --> $DIR/format_args.rs:90:70
    |
 LL |     assert!(true, "error: something failed at {}", Location::caller().to_string());
    |                                                                      ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `assert_eq!` args
-  --> $DIR/format_args.rs:93:73
+  --> $DIR/format_args.rs:91:73
    |
 LL |     assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
    |                                                                         ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `assert_ne!` args
-  --> $DIR/format_args.rs:94:73
+  --> $DIR/format_args.rs:92:73
    |
 LL |     assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
    |                                                                         ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `panic!` args
-  --> $DIR/format_args.rs:95:63
+  --> $DIR/format_args.rs:93:63
    |
 LL |     panic!("error: something failed at {}", Location::caller().to_string());
    |                                                               ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:96:20
+  --> $DIR/format_args.rs:94:20
    |
 LL |     println!("{}", X(1).to_string());
    |                    ^^^^^^^^^^^^^^^^ help: use this: `*X(1)`
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:97:20
+  --> $DIR/format_args.rs:95:20
    |
 LL |     println!("{}", Y(&X(1)).to_string());
    |                    ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))`
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:98:24
+  --> $DIR/format_args.rs:96:24
    |
 LL |     println!("{}", Z(1).to_string());
    |                        ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:99:20
+  --> $DIR/format_args.rs:97:20
    |
 LL |     println!("{}", x.to_string());
    |                    ^^^^^^^^^^^^^ help: use this: `**x`
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:100:20
+  --> $DIR/format_args.rs:98:20
    |
 LL |     println!("{}", x_ref.to_string());
    |                    ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref`
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:102:39
+  --> $DIR/format_args.rs:100:39
    |
 LL |     println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar");
    |                                       ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:103:52
+  --> $DIR/format_args.rs:101:52
    |
 LL |     println!("{foo}{bar}", foo = "foo", bar = "bar".to_string());
    |                                                    ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:104:39
+  --> $DIR/format_args.rs:102:39
    |
 LL |     println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo");
    |                                       ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:105:52
+  --> $DIR/format_args.rs:103:52
    |
 LL |     println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
    |                                                    ^^^^^^^^^^^^ help: remove this
 
-error: aborting due to 21 previous errors
+error: `to_string` applied to a type that implements `Display` in `format!` args
+  --> $DIR/format_args.rs:142:38
+   |
+LL |         let x = format!("{} {}", a, b.to_string());
+   |                                      ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+  --> $DIR/format_args.rs:156:24
+   |
+LL |         println!("{}", original[..10].to_string());
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use this: `&original[..10]`
+
+error: aborting due to 23 previous errors
 
index 5f9cebe212abd89844733156582e3c64771c0524..fa564e23cd275cb270a64ae9510504e91c81657d 100644 (file)
@@ -68,7 +68,7 @@ fn main() {
     &x;
     x;
 
-    let mut a = A("".into());
+    let mut a = A(String::new());
     let b = a << 0; // no error: non-integer
 
     1 * Meter; // no error: non-integer
index ca799c9cfac0f8a4c7e82c24d2e605d770fec561..3d06d2a73b628d7b760d3a8c3684c8d15c4ebde7 100644 (file)
@@ -68,7 +68,7 @@ fn main() {
     &x >> 0;
     x >> &0;
 
-    let mut a = A("".into());
+    let mut a = A(String::new());
     let b = a << 0; // no error: non-integer
 
     1 * Meter; // no error: non-integer
index 6cbfafbb38b9913e7ec71de26f6206fce73ae1cf..321feb0224ed11a97d111f645b8c77b7af073b89 100644 (file)
@@ -39,4 +39,12 @@ fn if_let_different_mutex() {
     };
 }
 
+fn mutex_ref(mutex: &Mutex<i32>) {
+    if let Ok(i) = mutex.lock() {
+        do_stuff(i);
+    } else {
+        let _x = mutex.lock();
+    };
+}
+
 fn main() {}
index e9c4d9163328f3066e9c67f244a8ce233c35555a..8a4d5dbac592b33d12a0d3b0061413a719e17248 100644 (file)
@@ -1,10 +1,14 @@
 error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
   --> $DIR/if_let_mutex.rs:10:5
    |
-LL | /     if let Err(locked) = m.lock() {
+LL |       if let Err(locked) = m.lock() {
+   |       ^                    - this Mutex will remain locked for the entire `if let`-block...
+   |  _____|
+   | |
 LL | |         do_stuff(locked);
 LL | |     } else {
 LL | |         let lock = m.lock().unwrap();
+   | |                    - ... and is tried to lock again here, which will always deadlock.
 LL | |         do_stuff(lock);
 LL | |     };
    | |_____^
@@ -15,15 +19,35 @@ LL | |     };
 error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
   --> $DIR/if_let_mutex.rs:22:5
    |
-LL | /     if let Some(locked) = m.lock().unwrap().deref() {
+LL |       if let Some(locked) = m.lock().unwrap().deref() {
+   |       ^                     - this Mutex will remain locked for the entire `if let`-block...
+   |  _____|
+   | |
 LL | |         do_stuff(locked);
 LL | |     } else {
 LL | |         let lock = m.lock().unwrap();
+   | |                    - ... and is tried to lock again here, which will always deadlock.
 LL | |         do_stuff(lock);
 LL | |     };
    | |_____^
    |
    = help: move the lock call outside of the `if let ...` expression
 
-error: aborting due to 2 previous errors
+error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
+  --> $DIR/if_let_mutex.rs:43:5
+   |
+LL |       if let Ok(i) = mutex.lock() {
+   |       ^              ----- this Mutex will remain locked for the entire `if let`-block...
+   |  _____|
+   | |
+LL | |         do_stuff(i);
+LL | |     } else {
+LL | |         let _x = mutex.lock();
+   | |                  ----- ... and is tried to lock again here, which will always deadlock.
+LL | |     };
+   | |_____^
+   |
+   = help: move the lock call outside of the `if let ...` expression
+
+error: aborting due to 3 previous errors
 
index 8cb22d569f4cc90bca59bf68e2971bb5e8415458..c22ace30d2dc21defe9cefa3108599f228860f27 100644 (file)
@@ -27,21 +27,21 @@ LL | |     };
    |
    = help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })`
 
-error: this could be simplified with `bool::then`
+error: this could be simplified with `bool::then_some`
   --> $DIR/if_then_some_else_none.rs:23:28
    |
 LL |     let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider using `bool::then` like: `(o < 32).then(|| o)`
+   = help: consider using `bool::then_some` like: `(o < 32).then_some(o)`
 
-error: this could be simplified with `bool::then`
+error: this could be simplified with `bool::then_some`
   --> $DIR/if_then_some_else_none.rs:27:13
    |
 LL |     let _ = if !x { Some(0) } else { None };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider using `bool::then` like: `(!x).then(|| 0)`
+   = help: consider using `bool::then_some` like: `(!x).then_some(0)`
 
 error: this could be simplified with `bool::then`
   --> $DIR/if_then_some_else_none.rs:82:13
index 45a430edcb58998562e96b35e86d8c2a41db1e8b..7ebf6ee993cbd7a02b6db0b178a3de67f828ba8c 100644 (file)
@@ -3,7 +3,7 @@
 // We also check the out_of_bounds_indexing lint here, because it lints similar things and
 // we want to avoid false positives.
 #![warn(clippy::out_of_bounds_indexing)]
-#![allow(const_err, clippy::no_effect, clippy::unnecessary_operation)]
+#![allow(const_err, unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
 
 const ARR: [i32; 2] = [1, 2];
 const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr.
diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed b/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed
new file mode 100644 (file)
index 0000000..bd9b07a
--- /dev/null
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::iter_on_empty_collections)]
+#![allow(clippy::iter_next_slice, clippy::redundant_clone)]
+
+fn array() {
+    assert_eq!(std::iter::empty().next(), Option::<i32>::None);
+    assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None);
+    assert_eq!(std::iter::empty().next(), Option::<&i32>::None);
+    assert_eq!(std::iter::empty().next(), Option::<i32>::None);
+    assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None);
+    assert_eq!(std::iter::empty().next(), Option::<&i32>::None);
+
+    // Don't trigger on non-iter methods
+    let _: Option<String> = None.clone();
+    let _: [String; 0] = [].clone();
+
+    // Don't trigger on match or if branches
+    let _ = match 123 {
+        123 => [].iter(),
+        _ => ["test"].iter(),
+    };
+
+    let _ = if false { ["test"].iter() } else { [].iter() };
+}
+
+macro_rules! in_macros {
+    () => {
+        assert_eq!([].into_iter().next(), Option::<i32>::None);
+        assert_eq!([].iter_mut().next(), Option::<&mut i32>::None);
+        assert_eq!([].iter().next(), Option::<&i32>::None);
+        assert_eq!(None.into_iter().next(), Option::<i32>::None);
+        assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None);
+        assert_eq!(None.iter().next(), Option::<&i32>::None);
+    };
+}
+
+// Don't trigger on a `None` that isn't std's option
+mod custom_option {
+    #[allow(unused)]
+    enum CustomOption {
+        Some(i32),
+        None,
+    }
+
+    impl CustomOption {
+        fn iter(&self) {}
+        fn iter_mut(&mut self) {}
+        fn into_iter(self) {}
+    }
+    use CustomOption::*;
+
+    pub fn custom_option() {
+        None.iter();
+        None.iter_mut();
+        None.into_iter();
+    }
+}
+
+fn main() {
+    array();
+    custom_option::custom_option();
+    in_macros!();
+}
diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.rs b/src/tools/clippy/tests/ui/iter_on_empty_collections.rs
new file mode 100644 (file)
index 0000000..e15ba94
--- /dev/null
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::iter_on_empty_collections)]
+#![allow(clippy::iter_next_slice, clippy::redundant_clone)]
+
+fn array() {
+    assert_eq!([].into_iter().next(), Option::<i32>::None);
+    assert_eq!([].iter_mut().next(), Option::<&mut i32>::None);
+    assert_eq!([].iter().next(), Option::<&i32>::None);
+    assert_eq!(None.into_iter().next(), Option::<i32>::None);
+    assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None);
+    assert_eq!(None.iter().next(), Option::<&i32>::None);
+
+    // Don't trigger on non-iter methods
+    let _: Option<String> = None.clone();
+    let _: [String; 0] = [].clone();
+
+    // Don't trigger on match or if branches
+    let _ = match 123 {
+        123 => [].iter(),
+        _ => ["test"].iter(),
+    };
+
+    let _ = if false { ["test"].iter() } else { [].iter() };
+}
+
+macro_rules! in_macros {
+    () => {
+        assert_eq!([].into_iter().next(), Option::<i32>::None);
+        assert_eq!([].iter_mut().next(), Option::<&mut i32>::None);
+        assert_eq!([].iter().next(), Option::<&i32>::None);
+        assert_eq!(None.into_iter().next(), Option::<i32>::None);
+        assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None);
+        assert_eq!(None.iter().next(), Option::<&i32>::None);
+    };
+}
+
+// Don't trigger on a `None` that isn't std's option
+mod custom_option {
+    #[allow(unused)]
+    enum CustomOption {
+        Some(i32),
+        None,
+    }
+
+    impl CustomOption {
+        fn iter(&self) {}
+        fn iter_mut(&mut self) {}
+        fn into_iter(self) {}
+    }
+    use CustomOption::*;
+
+    pub fn custom_option() {
+        None.iter();
+        None.iter_mut();
+        None.into_iter();
+    }
+}
+
+fn main() {
+    array();
+    custom_option::custom_option();
+    in_macros!();
+}
diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr b/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr
new file mode 100644 (file)
index 0000000..cbd6117
--- /dev/null
@@ -0,0 +1,40 @@
+error: `into_iter` call on an empty collection
+  --> $DIR/iter_on_empty_collections.rs:6:16
+   |
+LL |     assert_eq!([].into_iter().next(), Option::<i32>::None);
+   |                ^^^^^^^^^^^^^^ help: try: `std::iter::empty()`
+   |
+   = note: `-D clippy::iter-on-empty-collections` implied by `-D warnings`
+
+error: `iter_mut` call on an empty collection
+  --> $DIR/iter_on_empty_collections.rs:7:16
+   |
+LL |     assert_eq!([].iter_mut().next(), Option::<&mut i32>::None);
+   |                ^^^^^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: `iter` call on an empty collection
+  --> $DIR/iter_on_empty_collections.rs:8:16
+   |
+LL |     assert_eq!([].iter().next(), Option::<&i32>::None);
+   |                ^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: `into_iter` call on an empty collection
+  --> $DIR/iter_on_empty_collections.rs:9:16
+   |
+LL |     assert_eq!(None.into_iter().next(), Option::<i32>::None);
+   |                ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: `iter_mut` call on an empty collection
+  --> $DIR/iter_on_empty_collections.rs:10:16
+   |
+LL |     assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None);
+   |                ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: `iter` call on an empty collection
+  --> $DIR/iter_on_empty_collections.rs:11:16
+   |
+LL |     assert_eq!(None.iter().next(), Option::<&i32>::None);
+   |                ^^^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.fixed b/src/tools/clippy/tests/ui/iter_on_single_items.fixed
new file mode 100644 (file)
index 0000000..1fa4b03
--- /dev/null
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::iter_on_single_items)]
+#![allow(clippy::iter_next_slice, clippy::redundant_clone)]
+
+fn array() {
+    assert_eq!(std::iter::once(123).next(), Some(123));
+    assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123));
+    assert_eq!(std::iter::once(&123).next(), Some(&123));
+    assert_eq!(std::iter::once(123).next(), Some(123));
+    assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123));
+    assert_eq!(std::iter::once(&123).next(), Some(&123));
+
+    // Don't trigger on non-iter methods
+    let _: Option<String> = Some("test".to_string()).clone();
+    let _: [String; 1] = ["test".to_string()].clone();
+
+    // Don't trigger on match or if branches
+    let _ = match 123 {
+        123 => [].iter(),
+        _ => ["test"].iter(),
+    };
+
+    let _ = if false { ["test"].iter() } else { [].iter() };
+}
+
+macro_rules! in_macros {
+    () => {
+        assert_eq!([123].into_iter().next(), Some(123));
+        assert_eq!([123].iter_mut().next(), Some(&mut 123));
+        assert_eq!([123].iter().next(), Some(&123));
+        assert_eq!(Some(123).into_iter().next(), Some(123));
+        assert_eq!(Some(123).iter_mut().next(), Some(&mut 123));
+        assert_eq!(Some(123).iter().next(), Some(&123));
+    };
+}
+
+// Don't trigger on a `Some` that isn't std's option
+mod custom_option {
+    #[allow(unused)]
+    enum CustomOption {
+        Some(i32),
+        None,
+    }
+
+    impl CustomOption {
+        fn iter(&self) {}
+        fn iter_mut(&mut self) {}
+        fn into_iter(self) {}
+    }
+    use CustomOption::*;
+
+    pub fn custom_option() {
+        Some(3).iter();
+        Some(3).iter_mut();
+        Some(3).into_iter();
+    }
+}
+
+fn main() {
+    array();
+    custom_option::custom_option();
+    in_macros!();
+}
diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.rs b/src/tools/clippy/tests/ui/iter_on_single_items.rs
new file mode 100644 (file)
index 0000000..ea96d80
--- /dev/null
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::iter_on_single_items)]
+#![allow(clippy::iter_next_slice, clippy::redundant_clone)]
+
+fn array() {
+    assert_eq!([123].into_iter().next(), Some(123));
+    assert_eq!([123].iter_mut().next(), Some(&mut 123));
+    assert_eq!([123].iter().next(), Some(&123));
+    assert_eq!(Some(123).into_iter().next(), Some(123));
+    assert_eq!(Some(123).iter_mut().next(), Some(&mut 123));
+    assert_eq!(Some(123).iter().next(), Some(&123));
+
+    // Don't trigger on non-iter methods
+    let _: Option<String> = Some("test".to_string()).clone();
+    let _: [String; 1] = ["test".to_string()].clone();
+
+    // Don't trigger on match or if branches
+    let _ = match 123 {
+        123 => [].iter(),
+        _ => ["test"].iter(),
+    };
+
+    let _ = if false { ["test"].iter() } else { [].iter() };
+}
+
+macro_rules! in_macros {
+    () => {
+        assert_eq!([123].into_iter().next(), Some(123));
+        assert_eq!([123].iter_mut().next(), Some(&mut 123));
+        assert_eq!([123].iter().next(), Some(&123));
+        assert_eq!(Some(123).into_iter().next(), Some(123));
+        assert_eq!(Some(123).iter_mut().next(), Some(&mut 123));
+        assert_eq!(Some(123).iter().next(), Some(&123));
+    };
+}
+
+// Don't trigger on a `Some` that isn't std's option
+mod custom_option {
+    #[allow(unused)]
+    enum CustomOption {
+        Some(i32),
+        None,
+    }
+
+    impl CustomOption {
+        fn iter(&self) {}
+        fn iter_mut(&mut self) {}
+        fn into_iter(self) {}
+    }
+    use CustomOption::*;
+
+    pub fn custom_option() {
+        Some(3).iter();
+        Some(3).iter_mut();
+        Some(3).into_iter();
+    }
+}
+
+fn main() {
+    array();
+    custom_option::custom_option();
+    in_macros!();
+}
diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.stderr b/src/tools/clippy/tests/ui/iter_on_single_items.stderr
new file mode 100644 (file)
index 0000000..d6c5471
--- /dev/null
@@ -0,0 +1,40 @@
+error: `into_iter` call on a collection with only one item
+  --> $DIR/iter_on_single_items.rs:6:16
+   |
+LL |     assert_eq!([123].into_iter().next(), Some(123));
+   |                ^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)`
+   |
+   = note: `-D clippy::iter-on-single-items` implied by `-D warnings`
+
+error: `iter_mut` call on a collection with only one item
+  --> $DIR/iter_on_single_items.rs:7:16
+   |
+LL |     assert_eq!([123].iter_mut().next(), Some(&mut 123));
+   |                ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)`
+
+error: `iter` call on a collection with only one item
+  --> $DIR/iter_on_single_items.rs:8:16
+   |
+LL |     assert_eq!([123].iter().next(), Some(&123));
+   |                ^^^^^^^^^^^^ help: try: `std::iter::once(&123)`
+
+error: `into_iter` call on a collection with only one item
+  --> $DIR/iter_on_single_items.rs:9:16
+   |
+LL |     assert_eq!(Some(123).into_iter().next(), Some(123));
+   |                ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)`
+
+error: `iter_mut` call on a collection with only one item
+  --> $DIR/iter_on_single_items.rs:10:16
+   |
+LL |     assert_eq!(Some(123).iter_mut().next(), Some(&mut 123));
+   |                ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)`
+
+error: `iter` call on a collection with only one item
+  --> $DIR/iter_on_single_items.rs:11:16
+   |
+LL |     assert_eq!(Some(123).iter().next(), Some(&123));
+   |                ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&123)`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_string_new.fixed b/src/tools/clippy/tests/ui/manual_string_new.fixed
new file mode 100644 (file)
index 0000000..a376411
--- /dev/null
@@ -0,0 +1,63 @@
+// run-rustfix
+
+#![warn(clippy::manual_string_new)]
+
+macro_rules! create_strings_from_macro {
+    // When inside a macro, nothing should warn to prevent false positives.
+    ($some_str:expr) => {
+        let _: String = $some_str.into();
+        let _ = $some_str.to_string();
+    };
+}
+
+fn main() {
+    // Method calls
+    let _ = String::new();
+    let _ = "no warning".to_string();
+
+    let _ = String::new();
+    let _ = "no warning".to_owned();
+
+    let _: String = String::new();
+    let _: String = "no warning".into();
+
+    let _: SomeOtherStruct = "no warning".into();
+    let _: SomeOtherStruct = "".into(); // No warning too. We are not converting into String.
+
+    // Calls
+    let _ = String::new();
+    let _ = String::new();
+    let _ = String::from("no warning");
+    let _ = SomeOtherStruct::from("no warning");
+    let _ = SomeOtherStruct::from(""); // Again: no warning.
+
+    let _ = String::new();
+    let _ = String::try_from("no warning").unwrap();
+    let _ = String::try_from("no warning").expect("this should not warn");
+    let _ = SomeOtherStruct::try_from("no warning").unwrap();
+    let _ = SomeOtherStruct::try_from("").unwrap(); // Again: no warning.
+
+    let _: String = String::new();
+    let _: String = From::from("no warning");
+    let _: SomeOtherStruct = From::from("no warning");
+    let _: SomeOtherStruct = From::from(""); // Again: no warning.
+
+    let _: String = String::new();
+    let _: String = TryFrom::try_from("no warning").unwrap();
+    let _: String = TryFrom::try_from("no warning").expect("this should not warn");
+    let _: String = String::new();
+    let _: SomeOtherStruct = TryFrom::try_from("no_warning").unwrap();
+    let _: SomeOtherStruct = TryFrom::try_from("").unwrap(); // Again: no warning.
+
+    // Macros (never warn)
+    create_strings_from_macro!("");
+    create_strings_from_macro!("Hey");
+}
+
+struct SomeOtherStruct {}
+
+impl From<&str> for SomeOtherStruct {
+    fn from(_value: &str) -> Self {
+        Self {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_string_new.rs b/src/tools/clippy/tests/ui/manual_string_new.rs
new file mode 100644 (file)
index 0000000..6bfc52f
--- /dev/null
@@ -0,0 +1,63 @@
+// run-rustfix
+
+#![warn(clippy::manual_string_new)]
+
+macro_rules! create_strings_from_macro {
+    // When inside a macro, nothing should warn to prevent false positives.
+    ($some_str:expr) => {
+        let _: String = $some_str.into();
+        let _ = $some_str.to_string();
+    };
+}
+
+fn main() {
+    // Method calls
+    let _ = "".to_string();
+    let _ = "no warning".to_string();
+
+    let _ = "".to_owned();
+    let _ = "no warning".to_owned();
+
+    let _: String = "".into();
+    let _: String = "no warning".into();
+
+    let _: SomeOtherStruct = "no warning".into();
+    let _: SomeOtherStruct = "".into(); // No warning too. We are not converting into String.
+
+    // Calls
+    let _ = String::from("");
+    let _ = <String>::from("");
+    let _ = String::from("no warning");
+    let _ = SomeOtherStruct::from("no warning");
+    let _ = SomeOtherStruct::from(""); // Again: no warning.
+
+    let _ = String::try_from("").unwrap();
+    let _ = String::try_from("no warning").unwrap();
+    let _ = String::try_from("no warning").expect("this should not warn");
+    let _ = SomeOtherStruct::try_from("no warning").unwrap();
+    let _ = SomeOtherStruct::try_from("").unwrap(); // Again: no warning.
+
+    let _: String = From::from("");
+    let _: String = From::from("no warning");
+    let _: SomeOtherStruct = From::from("no warning");
+    let _: SomeOtherStruct = From::from(""); // Again: no warning.
+
+    let _: String = TryFrom::try_from("").unwrap();
+    let _: String = TryFrom::try_from("no warning").unwrap();
+    let _: String = TryFrom::try_from("no warning").expect("this should not warn");
+    let _: String = TryFrom::try_from("").expect("this should warn");
+    let _: SomeOtherStruct = TryFrom::try_from("no_warning").unwrap();
+    let _: SomeOtherStruct = TryFrom::try_from("").unwrap(); // Again: no warning.
+
+    // Macros (never warn)
+    create_strings_from_macro!("");
+    create_strings_from_macro!("Hey");
+}
+
+struct SomeOtherStruct {}
+
+impl From<&str> for SomeOtherStruct {
+    fn from(_value: &str) -> Self {
+        Self {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_string_new.stderr b/src/tools/clippy/tests/ui/manual_string_new.stderr
new file mode 100644 (file)
index 0000000..e5ecfc6
--- /dev/null
@@ -0,0 +1,58 @@
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:15:13
+   |
+LL |     let _ = "".to_string();
+   |             ^^^^^^^^^^^^^^ help: consider using: `String::new()`
+   |
+   = note: `-D clippy::manual-string-new` implied by `-D warnings`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:18:13
+   |
+LL |     let _ = "".to_owned();
+   |             ^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:21:21
+   |
+LL |     let _: String = "".into();
+   |                     ^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:28:13
+   |
+LL |     let _ = String::from("");
+   |             ^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:29:13
+   |
+LL |     let _ = <String>::from("");
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:34:13
+   |
+LL |     let _ = String::try_from("").unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:40:21
+   |
+LL |     let _: String = From::from("");
+   |                     ^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:45:21
+   |
+LL |     let _: String = TryFrom::try_from("").unwrap();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:48:21
+   |
+LL |     let _: String = TryFrom::try_from("").expect("this should warn");
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: aborting due to 9 previous errors
+
index 1ccbfda64b73a5240ae68929f83c37d07cd66c05..95ca571d07bfbf88fcce5d626814d6f210156ee2 100644 (file)
@@ -167,4 +167,29 @@ fn main() {
             _ => false,
         };
     }
+
+    let x = ' ';
+    // ignore if match block contains comment
+    let _line_comments = match x {
+        // numbers are bad!
+        '1' | '2' | '3' => true,
+        // spaces are very important to be true.
+        ' ' => true,
+        // as are dots
+        '.' => true,
+        _ => false,
+    };
+
+    let _block_comments = match x {
+        /* numbers are bad!
+         */
+        '1' | '2' | '3' => true,
+        /* spaces are very important to be true.
+         */
+        ' ' => true,
+        /* as are dots
+         */
+        '.' => true,
+        _ => false,
+    };
 }
index a49991f594174473c51cc41609d3f808b1d80768..3b9c8cadadcc417ebbe731a3735dd98580837e46 100644 (file)
@@ -208,4 +208,29 @@ enum E {
             _ => false,
         };
     }
+
+    let x = ' ';
+    // ignore if match block contains comment
+    let _line_comments = match x {
+        // numbers are bad!
+        '1' | '2' | '3' => true,
+        // spaces are very important to be true.
+        ' ' => true,
+        // as are dots
+        '.' => true,
+        _ => false,
+    };
+
+    let _block_comments = match x {
+        /* numbers are bad!
+         */
+        '1' | '2' | '3' => true,
+        /* spaces are very important to be true.
+         */
+        ' ' => true,
+        /* as are dots
+         */
+        '.' => true,
+        _ => false,
+    };
 }
diff --git a/src/tools/clippy/tests/ui/multi_assignments.rs b/src/tools/clippy/tests/ui/multi_assignments.rs
new file mode 100644 (file)
index 0000000..b186bf8
--- /dev/null
@@ -0,0 +1,9 @@
+#![warn(clippy::multi_assignments)]
+fn main() {
+    let (mut a, mut b, mut c, mut d) = ((), (), (), ());
+    a = b = c;
+    a = b = c = d;
+    a = b = { c };
+    a = { b = c };
+    a = (b = c);
+}
diff --git a/src/tools/clippy/tests/ui/multi_assignments.stderr b/src/tools/clippy/tests/ui/multi_assignments.stderr
new file mode 100644 (file)
index 0000000..d6c42bb
--- /dev/null
@@ -0,0 +1,40 @@
+error: assignments don't nest intuitively
+  --> $DIR/multi_assignments.rs:4:5
+   |
+LL |     a = b = c;
+   |     ^^^^^^^^^
+   |
+   = note: `-D clippy::multi-assignments` implied by `-D warnings`
+
+error: assignments don't nest intuitively
+  --> $DIR/multi_assignments.rs:5:5
+   |
+LL |     a = b = c = d;
+   |     ^^^^^^^^^^^^^
+
+error: assignments don't nest intuitively
+  --> $DIR/multi_assignments.rs:5:9
+   |
+LL |     a = b = c = d;
+   |         ^^^^^^^^^
+
+error: assignments don't nest intuitively
+  --> $DIR/multi_assignments.rs:6:5
+   |
+LL |     a = b = { c };
+   |     ^^^^^^^^^^^^^
+
+error: assignments don't nest intuitively
+  --> $DIR/multi_assignments.rs:7:5
+   |
+LL |     a = { b = c };
+   |     ^^^^^^^^^^^^^
+
+error: assignments don't nest intuitively
+  --> $DIR/multi_assignments.rs:8:5
+   |
+LL |     a = (b = c);
+   |     ^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
index bfd2725ecaaa874b9409502e5b72514663ad7cb8..8cf93bd248173ee93cef0b0ec5e87815e11f370b 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![feature(lint_reasons)]
+#![feature(custom_inner_attributes, lint_reasons)]
 
 #[warn(clippy::all, clippy::needless_borrow)]
 #[allow(unused_variables, clippy::unnecessary_mut_passed)]
@@ -127,6 +127,20 @@ fn main() {
             0
         }
     }
+
+    let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap();
+    let _ = std::path::Path::new(".").join(".");
+    deref_target_is_x(X);
+    multiple_constraints([[""]]);
+    multiple_constraints_normalizes_to_same(X, X);
+    let _ = Some("").unwrap_or("");
+
+    only_sized(&""); // Don't lint. `Sized` is only bound
+    let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound
+    let _ = Box::new(&""); // Don't lint. Type parameter appears in return type
+    ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter
+    refs_only(&()); // Don't lint. `&T` implements trait, but `T` doesn't
+    multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments
 }
 
 #[allow(clippy::needless_borrowed_reference)]
@@ -183,3 +197,104 @@ mod issue9160 {
         }
     }
 }
+
+#[derive(Clone, Copy)]
+struct X;
+
+impl std::ops::Deref for X {
+    type Target = X;
+    fn deref(&self) -> &Self::Target {
+        self
+    }
+}
+
+fn deref_target_is_x<T>(_: T)
+where
+    T: std::ops::Deref<Target = X>,
+{
+}
+
+fn multiple_constraints<T, U, V, X, Y>(_: T)
+where
+    T: IntoIterator<Item = U> + IntoIterator<Item = X>,
+    U: IntoIterator<Item = V>,
+    V: AsRef<str>,
+    X: IntoIterator<Item = Y>,
+    Y: AsRef<std::ffi::OsStr>,
+{
+}
+
+fn multiple_constraints_normalizes_to_same<T, U, V>(_: T, _: V)
+where
+    T: std::ops::Deref<Target = U>,
+    U: std::ops::Deref<Target = V>,
+{
+}
+
+fn only_sized<T>(_: T) {}
+
+fn ref_as_ref_path<T: 'static>(_: &'static T)
+where
+    &'static T: AsRef<std::path::Path>,
+{
+}
+
+trait RefsOnly {
+    type Referent;
+}
+
+impl<T> RefsOnly for &T {
+    type Referent = T;
+}
+
+fn refs_only<T, U>(_: T)
+where
+    T: RefsOnly<Referent = U>,
+{
+}
+
+fn multiple_constraints_normalizes_to_different<T, U, V>(_: T, _: U)
+where
+    T: IntoIterator<Item = U>,
+    U: IntoIterator<Item = V>,
+    V: AsRef<str>,
+{
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
+#[allow(dead_code)]
+mod copyable_iterator {
+    #[derive(Clone, Copy)]
+    struct Iter;
+    impl Iterator for Iter {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            None
+        }
+    }
+    fn takes_iter(_: impl Iterator) {}
+    fn dont_warn(mut x: Iter) {
+        takes_iter(&mut x);
+    }
+    fn warn(mut x: &mut Iter) {
+        takes_iter(&mut x)
+    }
+}
+
+mod under_msrv {
+    #![allow(dead_code)]
+    #![clippy::msrv = "1.52.0"]
+
+    fn foo() {
+        let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+    }
+}
+
+mod meets_msrv {
+    #![allow(dead_code)]
+    #![clippy::msrv = "1.53.0"]
+
+    fn foo() {
+        let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap();
+    }
+}
index c457d8c5471886f5491aba8bfc3c08f4a85d2621..fd9b2a11df96f1cba7dcd147dd7d6ca96774435d 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![feature(lint_reasons)]
+#![feature(custom_inner_attributes, lint_reasons)]
 
 #[warn(clippy::all, clippy::needless_borrow)]
 #[allow(unused_variables, clippy::unnecessary_mut_passed)]
@@ -127,6 +127,20 @@ fn from(s: &S) -> Self {
             0
         }
     }
+
+    let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+    let _ = std::path::Path::new(".").join(&&".");
+    deref_target_is_x(&X);
+    multiple_constraints(&[[""]]);
+    multiple_constraints_normalizes_to_same(&X, X);
+    let _ = Some("").unwrap_or(&"");
+
+    only_sized(&""); // Don't lint. `Sized` is only bound
+    let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound
+    let _ = Box::new(&""); // Don't lint. Type parameter appears in return type
+    ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter
+    refs_only(&()); // Don't lint. `&T` implements trait, but `T` doesn't
+    multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments
 }
 
 #[allow(clippy::needless_borrowed_reference)]
@@ -183,3 +197,104 @@ fn calls_mut_field(&mut self) -> T {
         }
     }
 }
+
+#[derive(Clone, Copy)]
+struct X;
+
+impl std::ops::Deref for X {
+    type Target = X;
+    fn deref(&self) -> &Self::Target {
+        self
+    }
+}
+
+fn deref_target_is_x<T>(_: T)
+where
+    T: std::ops::Deref<Target = X>,
+{
+}
+
+fn multiple_constraints<T, U, V, X, Y>(_: T)
+where
+    T: IntoIterator<Item = U> + IntoIterator<Item = X>,
+    U: IntoIterator<Item = V>,
+    V: AsRef<str>,
+    X: IntoIterator<Item = Y>,
+    Y: AsRef<std::ffi::OsStr>,
+{
+}
+
+fn multiple_constraints_normalizes_to_same<T, U, V>(_: T, _: V)
+where
+    T: std::ops::Deref<Target = U>,
+    U: std::ops::Deref<Target = V>,
+{
+}
+
+fn only_sized<T>(_: T) {}
+
+fn ref_as_ref_path<T: 'static>(_: &'static T)
+where
+    &'static T: AsRef<std::path::Path>,
+{
+}
+
+trait RefsOnly {
+    type Referent;
+}
+
+impl<T> RefsOnly for &T {
+    type Referent = T;
+}
+
+fn refs_only<T, U>(_: T)
+where
+    T: RefsOnly<Referent = U>,
+{
+}
+
+fn multiple_constraints_normalizes_to_different<T, U, V>(_: T, _: U)
+where
+    T: IntoIterator<Item = U>,
+    U: IntoIterator<Item = V>,
+    V: AsRef<str>,
+{
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
+#[allow(dead_code)]
+mod copyable_iterator {
+    #[derive(Clone, Copy)]
+    struct Iter;
+    impl Iterator for Iter {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            None
+        }
+    }
+    fn takes_iter(_: impl Iterator) {}
+    fn dont_warn(mut x: Iter) {
+        takes_iter(&mut x);
+    }
+    fn warn(mut x: &mut Iter) {
+        takes_iter(&mut x)
+    }
+}
+
+mod under_msrv {
+    #![allow(dead_code)]
+    #![clippy::msrv = "1.52.0"]
+
+    fn foo() {
+        let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+    }
+}
+
+mod meets_msrv {
+    #![allow(dead_code)]
+    #![clippy::msrv = "1.53.0"]
+
+    fn foo() {
+        let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+    }
+}
index 66588689d81851a8f81862bac08e1bf08ce95d58..5af68706d4ba579311308199b560dbfcad016ad2 100644 (file)
@@ -120,17 +120,59 @@ error: this expression creates a reference which is immediately dereferenced by
 LL |     (&&5).foo();
    |     ^^^^^ help: change this to: `(&5)`
 
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:131:51
+   |
+LL |     let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+   |                                                   ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]`
+
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:132:44
+   |
+LL |     let _ = std::path::Path::new(".").join(&&".");
+   |                                            ^^^^^ help: change this to: `"."`
+
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:133:23
+   |
+LL |     deref_target_is_x(&X);
+   |                       ^^ help: change this to: `X`
+
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:134:26
+   |
+LL |     multiple_constraints(&[[""]]);
+   |                          ^^^^^^^ help: change this to: `[[""]]`
+
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:135:45
+   |
+LL |     multiple_constraints_normalizes_to_same(&X, X);
+   |                                             ^^ help: change this to: `X`
+
+error: this expression creates a reference which is immediately dereferenced by the compiler
+  --> $DIR/needless_borrow.rs:136:32
+   |
+LL |     let _ = Some("").unwrap_or(&"");
+   |                                ^^^ help: change this to: `""`
+
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:173:13
+  --> $DIR/needless_borrow.rs:187:13
    |
 LL |             (&self.f)()
    |             ^^^^^^^^^ help: change this to: `(self.f)`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:182:13
+  --> $DIR/needless_borrow.rs:196:13
    |
 LL |             (&mut self.f)()
    |             ^^^^^^^^^^^^^ help: change this to: `(self.f)`
 
-error: aborting due to 22 previous errors
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:298:55
+   |
+LL |         let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+   |                                                       ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]`
+
+error: aborting due to 29 previous errors
 
index 1f11d1f8d563c2bcb213f6924ac169512950d762..12a9ace1ee688679a5745698e314990480eda9f7 100644 (file)
@@ -112,3 +112,192 @@ fn allow_test() {
     let v = [1].iter().collect::<Vec<_>>();
     v.into_iter().collect::<HashSet<_>>();
 }
+
+mod issue_8553 {
+    fn test_for() {
+        let vec = vec![1, 2];
+        let w: Vec<usize> = vec.iter().map(|i| i * i).collect();
+
+        for i in 0..2 {
+            // Do not lint, because this method call is in the loop
+            w.contains(&i);
+        }
+
+        for i in 0..2 {
+            let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+            let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+            // Do lint
+            y.contains(&i);
+            for j in 0..2 {
+                // Do not lint, because this method call is in the loop
+                z.contains(&j);
+            }
+        }
+
+        // Do not lint, because this variable is used.
+        w.contains(&0);
+    }
+
+    fn test_while() {
+        let vec = vec![1, 2];
+        let x: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let mut n = 0;
+        while n > 1 {
+            // Do not lint, because this method call is in the loop
+            x.contains(&n);
+            n += 1;
+        }
+
+        while n > 2 {
+            let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+            let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+            // Do lint
+            y.contains(&n);
+            n += 1;
+            while n > 4 {
+                // Do not lint, because this method call is in the loop
+                z.contains(&n);
+                n += 1;
+            }
+        }
+    }
+
+    fn test_loop() {
+        let vec = vec![1, 2];
+        let x: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let mut n = 0;
+        loop {
+            if n < 1 {
+                // Do not lint, because this method call is in the loop
+                x.contains(&n);
+                n += 1;
+            } else {
+                break;
+            }
+        }
+
+        loop {
+            if n < 2 {
+                let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+                let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+                // Do lint
+                y.contains(&n);
+                n += 1;
+                loop {
+                    if n < 4 {
+                        // Do not lint, because this method call is in the loop
+                        z.contains(&n);
+                        n += 1;
+                    } else {
+                        break;
+                    }
+                }
+            } else {
+                break;
+            }
+        }
+    }
+
+    fn test_while_let() {
+        let vec = vec![1, 2];
+        let x: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let optional = Some(0);
+        let mut n = 0;
+        while let Some(value) = optional {
+            if n < 1 {
+                // Do not lint, because this method call is in the loop
+                x.contains(&n);
+                n += 1;
+            } else {
+                break;
+            }
+        }
+
+        while let Some(value) = optional {
+            let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+            let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+            if n < 2 {
+                // Do lint
+                y.contains(&n);
+                n += 1;
+            } else {
+                break;
+            }
+
+            while let Some(value) = optional {
+                if n < 4 {
+                    // Do not lint, because this method call is in the loop
+                    z.contains(&n);
+                    n += 1;
+                } else {
+                    break;
+                }
+            }
+        }
+    }
+
+    fn test_if_cond() {
+        let vec = vec![1, 2];
+        let v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let w = v.iter().collect::<Vec<_>>();
+        // Do lint
+        for _ in 0..w.len() {
+            todo!();
+        }
+    }
+
+    fn test_if_cond_false_case() {
+        let vec = vec![1, 2];
+        let v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let w = v.iter().collect::<Vec<_>>();
+        // Do not lint, because w is used.
+        for _ in 0..w.len() {
+            todo!();
+        }
+
+        w.len();
+    }
+
+    fn test_while_cond() {
+        let mut vec = vec![1, 2];
+        let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let mut w = v.iter().collect::<Vec<_>>();
+        // Do lint
+        while 1 == w.len() {
+            todo!();
+        }
+    }
+
+    fn test_while_cond_false_case() {
+        let mut vec = vec![1, 2];
+        let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let mut w = v.iter().collect::<Vec<_>>();
+        // Do not lint, because w is used.
+        while 1 == w.len() {
+            todo!();
+        }
+
+        w.len();
+    }
+
+    fn test_while_let_cond() {
+        let mut vec = vec![1, 2];
+        let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let mut w = v.iter().collect::<Vec<_>>();
+        // Do lint
+        while let Some(i) = Some(w.len()) {
+            todo!();
+        }
+    }
+
+    fn test_while_let_cond_false_case() {
+        let mut vec = vec![1, 2];
+        let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let mut w = v.iter().collect::<Vec<_>>();
+        // Do not lint, because w is used.
+        while let Some(i) = Some(w.len()) {
+            todo!();
+        }
+        w.len();
+    }
+}
index 0f5e78f91198c27dd50d74e25bce448c89207d37..9f0880cc6069d1449c7ec43d6386387deddcc5b7 100644 (file)
@@ -125,5 +125,122 @@ LL ~
 LL ~         sample.iter().count()
    |
 
-error: aborting due to 9 previous errors
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:127:59
+   |
+LL |             let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+   |                                                           ^^^^^^^
+...
+LL |             y.contains(&i);
+   |             -------------- the iterator could be used here instead
+   |
+help: check if the original Iterator contains an element instead of collecting then checking
+   |
+LL ~             
+LL |             let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+LL |             // Do lint
+LL ~             vec.iter().map(|k| k * k).any(|x| x == i);
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:152:59
+   |
+LL |             let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+   |                                                           ^^^^^^^
+...
+LL |             y.contains(&n);
+   |             -------------- the iterator could be used here instead
+   |
+help: check if the original Iterator contains an element instead of collecting then checking
+   |
+LL ~             
+LL |             let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+LL |             // Do lint
+LL ~             vec.iter().map(|k| k * k).any(|x| x == n);
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:181:63
+   |
+LL |                 let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+   |                                                               ^^^^^^^
+...
+LL |                 y.contains(&n);
+   |                 -------------- the iterator could be used here instead
+   |
+help: check if the original Iterator contains an element instead of collecting then checking
+   |
+LL ~                 
+LL |                 let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+LL |                 // Do lint
+LL ~                 vec.iter().map(|k| k * k).any(|x| x == n);
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:217:59
+   |
+LL |             let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+   |                                                           ^^^^^^^
+...
+LL |                 y.contains(&n);
+   |                 -------------- the iterator could be used here instead
+   |
+help: check if the original Iterator contains an element instead of collecting then checking
+   |
+LL ~             
+LL |             let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+LL |             if n < 2 {
+LL |                 // Do lint
+LL ~                 vec.iter().map(|k| k * k).any(|x| x == n);
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:242:26
+   |
+LL |         let w = v.iter().collect::<Vec<_>>();
+   |                          ^^^^^^^
+LL |         // Do lint
+LL |         for _ in 0..w.len() {
+   |                     ------- the iterator could be used here instead
+   |
+help: take the original Iterator's count instead of collecting it and finding the length
+   |
+LL ~         
+LL |         // Do lint
+LL ~         for _ in 0..v.iter().count() {
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:264:30
+   |
+LL |         let mut w = v.iter().collect::<Vec<_>>();
+   |                              ^^^^^^^
+LL |         // Do lint
+LL |         while 1 == w.len() {
+   |                    ------- the iterator could be used here instead
+   |
+help: take the original Iterator's count instead of collecting it and finding the length
+   |
+LL ~         
+LL |         // Do lint
+LL ~         while 1 == v.iter().count() {
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:286:30
+   |
+LL |         let mut w = v.iter().collect::<Vec<_>>();
+   |                              ^^^^^^^
+LL |         // Do lint
+LL |         while let Some(i) = Some(w.len()) {
+   |                                  ------- the iterator could be used here instead
+   |
+help: take the original Iterator's count instead of collecting it and finding the length
+   |
+LL ~         
+LL |         // Do lint
+LL ~         while let Some(i) = Some(v.iter().count()) {
+   |
+
+error: aborting due to 16 previous errors
 
index 4c98e1827bdbbf56f1c1caea2f8ede273ee7ed90..fee8e3030b8087cb16a52a6ffa55f67967c9158f 100644 (file)
@@ -1,4 +1,5 @@
 // run-rustfix
+#![feature(let_chains)]
 #![allow(
     unused,
     clippy::assign_op_pattern,
index 25e1e0214fb443bd1264042d918c0f9b2ee7a0be..402d9f9ef7f81945f4dd9087c314ca0dfe0f8b32 100644 (file)
@@ -1,4 +1,5 @@
 // run-rustfix
+#![feature(let_chains)]
 #![allow(
     unused,
     clippy::assign_op_pattern,
index 97f0f7019a9df0f24e99c3b3368dd8fa0a9154b2..313cdbbeba183c3222fec8dd7848e48b27bb511b 100644 (file)
@@ -1,5 +1,5 @@
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:22:5
+  --> $DIR/needless_late_init.rs:23:5
    |
 LL |     let a;
    |     ^^^^^^ created here
@@ -13,7 +13,7 @@ LL |     let a = "zero";
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:25:5
+  --> $DIR/needless_late_init.rs:26:5
    |
 LL |     let b;
    |     ^^^^^^ created here
@@ -27,7 +27,7 @@ LL |     let b = 1;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:26:5
+  --> $DIR/needless_late_init.rs:27:5
    |
 LL |     let c;
    |     ^^^^^^ created here
@@ -41,7 +41,7 @@ LL |     let c = 2;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:30:5
+  --> $DIR/needless_late_init.rs:31:5
    |
 LL |     let d: usize;
    |     ^^^^^^^^^^^^^ created here
@@ -54,7 +54,7 @@ LL |     let d: usize = 1;
    |     ~~~~~~~~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:33:5
+  --> $DIR/needless_late_init.rs:34:5
    |
 LL |     let e;
    |     ^^^^^^ created here
@@ -67,7 +67,7 @@ LL |     let e = format!("{}", d);
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:38:5
+  --> $DIR/needless_late_init.rs:39:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -88,7 +88,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:47:5
+  --> $DIR/needless_late_init.rs:48:5
    |
 LL |     let b;
    |     ^^^^^^
@@ -109,7 +109,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:54:5
+  --> $DIR/needless_late_init.rs:55:5
    |
 LL |     let d;
    |     ^^^^^^
@@ -130,7 +130,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:62:5
+  --> $DIR/needless_late_init.rs:63:5
    |
 LL |     let e;
    |     ^^^^^^
@@ -151,7 +151,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:69:5
+  --> $DIR/needless_late_init.rs:70:5
    |
 LL |     let f;
    |     ^^^^^^
@@ -167,7 +167,7 @@ LL +         1 => "three",
    |
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:75:5
+  --> $DIR/needless_late_init.rs:76:5
    |
 LL |     let g: usize;
    |     ^^^^^^^^^^^^^
@@ -187,7 +187,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:83:5
+  --> $DIR/needless_late_init.rs:84:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -201,7 +201,7 @@ LL |     let x = 1;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:87:5
+  --> $DIR/needless_late_init.rs:88:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -215,7 +215,7 @@ LL |     let x = SignificantDrop;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:91:5
+  --> $DIR/needless_late_init.rs:92:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -229,7 +229,7 @@ LL |     let x = SignificantDrop;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:110:5
+  --> $DIR/needless_late_init.rs:111:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -250,7 +250,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:127:5
+  --> $DIR/needless_late_init.rs:128:5
    |
 LL |     let a;
    |     ^^^^^^
index 0c9178fb85efe39a0a3e7938e658b162fcb2efc1..7e47406798cf9b90d96e98893ed8c66c89109406 100644 (file)
@@ -207,4 +207,43 @@ impl Tr for Result<i32, i32> {
     }
 }
 
+mod issue9084 {
+    fn wildcard_if() {
+        let mut some_bool = true;
+        let e = Some(1);
+
+        // should lint
+        let _ = e;
+
+        // should lint
+        let _ = e;
+
+        // should not lint
+        let _ = match e {
+            _ if some_bool => e,
+            _ => Some(2),
+        };
+
+        // should not lint
+        let _ = match e {
+            Some(i) => Some(i + 1),
+            _ if some_bool => e,
+            _ => e,
+        };
+
+        // should not lint (guard has side effects)
+        let _ = match e {
+            Some(i) => Some(i),
+            _ if {
+                some_bool = false;
+                some_bool
+            } =>
+            {
+                e
+            },
+            _ => e,
+        };
+    }
+}
+
 fn main() {}
index f66f01d7ccaf4ef2f96be1e2e2247cebf83884f2..809c694bf400464bb4685b115010b04c63ce6147 100644 (file)
@@ -244,4 +244,50 @@ fn as_mut(&mut self) -> Result<&mut i32, &mut i32> {
     }
 }
 
+mod issue9084 {
+    fn wildcard_if() {
+        let mut some_bool = true;
+        let e = Some(1);
+
+        // should lint
+        let _ = match e {
+            _ if some_bool => e,
+            _ => e,
+        };
+
+        // should lint
+        let _ = match e {
+            Some(i) => Some(i),
+            _ if some_bool => e,
+            _ => e,
+        };
+
+        // should not lint
+        let _ = match e {
+            _ if some_bool => e,
+            _ => Some(2),
+        };
+
+        // should not lint
+        let _ = match e {
+            Some(i) => Some(i + 1),
+            _ if some_bool => e,
+            _ => e,
+        };
+
+        // should not lint (guard has side effects)
+        let _ = match e {
+            Some(i) => Some(i),
+            _ if {
+                some_bool = false;
+                some_bool
+            } =>
+            {
+                e
+            },
+            _ => e,
+        };
+    }
+}
+
 fn main() {}
index 5bc79800a1a748bcbbb696e6fa824c791af3e647..28e78441c2522fcd65528069876fc567cf071b5b 100644 (file)
@@ -109,5 +109,26 @@ LL | |             Complex::D(E::VariantB(ea, eb), b) => Complex::D(E::VariantB(
 LL | |         };
    | |_________^ help: replace it with: `ce`
 
-error: aborting due to 11 previous errors
+error: this match expression is unnecessary
+  --> $DIR/needless_match.rs:253:17
+   |
+LL |           let _ = match e {
+   |  _________________^
+LL | |             _ if some_bool => e,
+LL | |             _ => e,
+LL | |         };
+   | |_________^ help: replace it with: `e`
+
+error: this match expression is unnecessary
+  --> $DIR/needless_match.rs:259:17
+   |
+LL |           let _ = match e {
+   |  _________________^
+LL | |             Some(i) => Some(i),
+LL | |             _ if some_bool => e,
+LL | |             _ => e,
+LL | |         };
+   | |_________^ help: replace it with: `e`
+
+error: aborting due to 13 previous errors
 
index 0bc0d0011efe00cd009475cb7972c3162cde1c62..87c8fc03b3c3627766edaaf6d965f5afdc6ced2c 100644 (file)
@@ -228,13 +228,9 @@ fn needless_return_macro() -> String {
     format!("Hello {}", "world!")
 }
 
-fn check_expect() -> bool {
-    if true {
-        // no error!
-        return true;
-    }
-    #[expect(clippy::needless_return)]
-    return true;
+fn issue_9361() -> i32 {
+    #[allow(clippy::integer_arithmetic)]
+    return 1 + 2;
 }
 
 fn main() {}
index eb9f72e8e7822fe8839060d77bc9ca237d1f5057..5a86e656255dd1413d7ca1e3dd2d543846cf7350 100644 (file)
@@ -228,13 +228,9 @@ fn needless_return_macro() -> String {
     return format!("Hello {}", "world!");
 }
 
-fn check_expect() -> bool {
-    if true {
-        // no error!
-        return true;
-    }
-    #[expect(clippy::needless_return)]
-    return true;
+fn issue_9361() -> i32 {
+    #[allow(clippy::integer_arithmetic)]
+    return 1 + 2;
 }
 
 fn main() {}
index 5768434f988ebf8b141fc4ee5e67a3971df67f29..f71e8ead5195ea27653bbfd7f24869490ffcc41b 100644 (file)
 #![warn(clippy::only_used_in_recursion)]
 
-fn simple(a: usize, b: usize) -> usize {
-    if a == 0 { 1 } else { simple(a - 1, b) }
+fn _simple(x: u32) -> u32 {
+    x
 }
 
-fn with_calc(a: usize, b: isize) -> usize {
-    if a == 0 { 1 } else { with_calc(a - 1, -b + 1) }
+fn _simple2(x: u32) -> u32 {
+    _simple(x)
 }
 
-fn tuple((a, b): (usize, usize)) -> usize {
-    if a == 0 { 1 } else { tuple((a - 1, b + 1)) }
+fn _one_unused(flag: u32, a: usize) -> usize {
+    if flag == 0 { 0 } else { _one_unused(flag - 1, a) }
 }
 
-fn let_tuple(a: usize, b: usize) -> usize {
-    let (c, d) = (a, b);
-    if c == 0 { 1 } else { let_tuple(c - 1, d + 1) }
+fn _two_unused(flag: u32, a: u32, b: i32) -> usize {
+    if flag == 0 { 0 } else { _two_unused(flag - 1, a, b) }
 }
 
-fn array([a, b]: [usize; 2]) -> usize {
-    if a == 0 { 1 } else { array([a - 1, b + 1]) }
-}
-
-fn index(a: usize, mut b: &[usize], c: usize) -> usize {
-    if a == 0 { 1 } else { index(a - 1, b, c + b[0]) }
-}
-
-fn break_(a: usize, mut b: usize, mut c: usize) -> usize {
-    let c = loop {
-        b += 1;
-        c += 1;
-        if c == 10 {
-            break b;
-        }
-    };
-
-    if a == 0 { 1 } else { break_(a - 1, c, c) }
+fn _with_calc(flag: u32, a: i64) -> usize {
+    if flag == 0 {
+        0
+    } else {
+        _with_calc(flag - 1, (-a + 10) * 5)
+    }
 }
 
-// this has a side effect
-fn mut_ref(a: usize, b: &mut usize) -> usize {
-    *b = 1;
-    if a == 0 { 1 } else { mut_ref(a - 1, b) }
+// Don't lint
+fn _used_with_flag(flag: u32, a: u32) -> usize {
+    if flag == 0 { 0 } else { _used_with_flag(flag ^ a, a - 1) }
 }
 
-fn mut_ref2(a: usize, b: &mut usize) -> usize {
-    let mut c = *b;
-    if a == 0 { 1 } else { mut_ref2(a - 1, &mut c) }
+fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize {
+    if flag == 0 {
+        0
+    } else {
+        _used_with_unused(flag - 1, -a, a + b)
+    }
 }
 
-fn not_primitive(a: usize, b: String) -> usize {
-    if a == 0 { 1 } else { not_primitive(a - 1, b) }
+fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize {
+    if flag == 0 {
+        0
+    } else {
+        _codependent_unused(flag - 1, a * b, a + b)
+    }
 }
 
-// this doesn't have a side effect,
-// but `String` is not primitive.
-fn not_primitive_op(a: usize, b: String, c: &str) -> usize {
-    if a == 1 { 1 } else { not_primitive_op(a, b + c, c) }
+fn _not_primitive(flag: u32, b: String) -> usize {
+    if flag == 0 { 0 } else { _not_primitive(flag - 1, b) }
 }
 
 struct A;
 
 impl A {
-    fn method(a: usize, b: usize) -> usize {
-        if a == 0 { 1 } else { A::method(a - 1, b - 1) }
+    fn _method(flag: usize, a: usize) -> usize {
+        if flag == 0 { 0 } else { Self::_method(flag - 1, a) }
     }
 
-    fn method2(&self, a: usize, b: usize) -> usize {
-        if a == 0 { 1 } else { self.method2(a - 1, b + 1) }
+    fn _method_self(&self, flag: usize, a: usize) -> usize {
+        if flag == 0 { 0 } else { self._method_self(flag - 1, a) }
     }
 }
 
 trait B {
-    fn hello(a: usize, b: usize) -> usize;
-
-    fn hello2(&self, a: usize, b: usize) -> usize;
+    fn method(flag: u32, a: usize) -> usize;
+    fn method_self(&self, flag: u32, a: usize) -> usize;
 }
 
 impl B for A {
-    fn hello(a: usize, b: usize) -> usize {
-        if a == 0 { 1 } else { A::hello(a - 1, b + 1) }
+    fn method(flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { Self::method(flag - 1, a) }
     }
 
-    fn hello2(&self, a: usize, b: usize) -> usize {
-        if a == 0 { 1 } else { self.hello2(a - 1, b + 1) }
+    fn method_self(&self, flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { self.method_self(flag - 1, a) }
     }
 }
 
-trait C {
-    fn hello(a: usize, b: usize) -> usize {
-        if a == 0 { 1 } else { Self::hello(a - 1, b + 1) }
+impl B for () {
+    fn method(flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { a }
     }
 
-    fn hello2(&self, a: usize, b: usize) -> usize {
-        if a == 0 { 1 } else { self.hello2(a - 1, b + 1) }
+    fn method_self(&self, flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { a }
     }
 }
 
-fn ignore(a: usize, _: usize) -> usize {
-    if a == 1 { 1 } else { ignore(a - 1, 0) }
-}
+impl B for u32 {
+    fn method(flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { <() as B>::method(flag, a) }
+    }
 
-fn ignore2(a: usize, _b: usize) -> usize {
-    if a == 1 { 1 } else { ignore2(a - 1, _b) }
+    fn method_self(&self, flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { ().method_self(flag, a) }
+    }
 }
 
-fn f1(a: u32) -> u32 {
-    a
-}
+trait C {
+    fn method(flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { Self::method(flag - 1, a) }
+    }
 
-fn f2(a: u32) -> u32 {
-    f1(a)
+    fn method_self(&self, flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { self.method_self(flag - 1, a) }
+    }
 }
 
-fn inner_fn(a: u32) -> u32 {
-    fn inner_fn(a: u32) -> u32 {
-        a
-    }
-    inner_fn(a)
+fn _ignore(flag: usize, _a: usize) -> usize {
+    if flag == 0 { 0 } else { _ignore(flag - 1, _a) }
 }
 
 fn main() {}
index 6fe9361bf5feb2eee0d903887ae911f3673f5706..74057ddcfda4c2cca6e77a64c43313539fe5066c 100644 (file)
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:3:21
+  --> $DIR/only_used_in_recursion.rs:11:27
    |
-LL | fn simple(a: usize, b: usize) -> usize {
-   |                     ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _one_unused(flag: u32, a: usize) -> usize {
+   |                           ^ help: if this is intentional, prefix it with an underscore: `_a`
    |
    = note: `-D clippy::only-used-in-recursion` implied by `-D warnings`
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:12:53
+   |
+LL |     if flag == 0 { 0 } else { _one_unused(flag - 1, a) }
+   |                                                     ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion.rs:15:27
+   |
+LL | fn _two_unused(flag: u32, a: u32, b: i32) -> usize {
+   |                           ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:16:53
+   |
+LL |     if flag == 0 { 0 } else { _two_unused(flag - 1, a, b) }
+   |                                                     ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion.rs:15:35
+   |
+LL | fn _two_unused(flag: u32, a: u32, b: i32) -> usize {
+   |                                   ^ help: if this is intentional, prefix it with an underscore: `_b`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:16:56
+   |
+LL |     if flag == 0 { 0 } else { _two_unused(flag - 1, a, b) }
+   |                                                        ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion.rs:19:26
+   |
+LL | fn _with_calc(flag: u32, a: i64) -> usize {
+   |                          ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:23:32
+   |
+LL |         _with_calc(flag - 1, (-a + 10) * 5)
+   |                                ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:7:24
+  --> $DIR/only_used_in_recursion.rs:32:33
+   |
+LL | fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize {
+   |                                 ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:36:38
    |
-LL | fn with_calc(a: usize, b: isize) -> usize {
-   |                        ^ help: if this is intentional, prefix with an underscore: `_b`
+LL |         _used_with_unused(flag - 1, -a, a + b)
+   |                                      ^  ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:11:14
+  --> $DIR/only_used_in_recursion.rs:32:41
+   |
+LL | fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize {
+   |                                         ^ help: if this is intentional, prefix it with an underscore: `_b`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:36:45
    |
-LL | fn tuple((a, b): (usize, usize)) -> usize {
-   |              ^ help: if this is intentional, prefix with an underscore: `_b`
+LL |         _used_with_unused(flag - 1, -a, a + b)
+   |                                             ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:15:24
+  --> $DIR/only_used_in_recursion.rs:40:35
    |
-LL | fn let_tuple(a: usize, b: usize) -> usize {
-   |                        ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize {
+   |                                   ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:44:39
+   |
+LL |         _codependent_unused(flag - 1, a * b, a + b)
+   |                                       ^      ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:20:14
+  --> $DIR/only_used_in_recursion.rs:40:43
+   |
+LL | fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize {
+   |                                           ^ help: if this is intentional, prefix it with an underscore: `_b`
    |
-LL | fn array([a, b]: [usize; 2]) -> usize {
-   |              ^ help: if this is intentional, prefix with an underscore: `_b`
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:44:43
+   |
+LL |         _codependent_unused(flag - 1, a * b, a + b)
+   |                                           ^      ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:24:20
+  --> $DIR/only_used_in_recursion.rs:48:30
+   |
+LL | fn _not_primitive(flag: u32, b: String) -> usize {
+   |                              ^ help: if this is intentional, prefix it with an underscore: `_b`
    |
-LL | fn index(a: usize, mut b: &[usize], c: usize) -> usize {
-   |                    ^^^^^ help: if this is intentional, prefix with an underscore: `_b`
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:49:56
+   |
+LL |     if flag == 0 { 0 } else { _not_primitive(flag - 1, b) }
+   |                                                        ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:24:37
+  --> $DIR/only_used_in_recursion.rs:55:29
+   |
+LL |     fn _method(flag: usize, a: usize) -> usize {
+   |                             ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:56:59
    |
-LL | fn index(a: usize, mut b: &[usize], c: usize) -> usize {
-   |                                     ^ help: if this is intentional, prefix with an underscore: `_c`
+LL |         if flag == 0 { 0 } else { Self::_method(flag - 1, a) }
+   |                                                           ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:28:21
+  --> $DIR/only_used_in_recursion.rs:59:22
+   |
+LL |     fn _method_self(&self, flag: usize, a: usize) -> usize {
+   |                      ^^^^
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:60:35
    |
-LL | fn break_(a: usize, mut b: usize, mut c: usize) -> usize {
-   |                     ^^^^^ help: if this is intentional, prefix with an underscore: `_b`
+LL |         if flag == 0 { 0 } else { self._method_self(flag - 1, a) }
+   |                                   ^^^^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:46:23
+  --> $DIR/only_used_in_recursion.rs:59:41
    |
-LL | fn mut_ref2(a: usize, b: &mut usize) -> usize {
-   |                       ^ help: if this is intentional, prefix with an underscore: `_b`
+LL |     fn _method_self(&self, flag: usize, a: usize) -> usize {
+   |                                         ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:60:63
+   |
+LL |         if flag == 0 { 0 } else { self._method_self(flag - 1, a) }
+   |                                                               ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:51:28
+  --> $DIR/only_used_in_recursion.rs:70:26
+   |
+LL |     fn method(flag: u32, a: usize) -> usize {
+   |                          ^ help: if this is intentional, prefix it with an underscore: `_a`
    |
-LL | fn not_primitive(a: usize, b: String) -> usize {
-   |                            ^ help: if this is intentional, prefix with an underscore: `_b`
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:71:58
+   |
+LL |         if flag == 0 { 0 } else { Self::method(flag - 1, a) }
+   |                                                          ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:68:33
+  --> $DIR/only_used_in_recursion.rs:74:38
+   |
+LL |     fn method_self(&self, flag: u32, a: usize) -> usize {
+   |                                      ^ help: if this is intentional, prefix it with an underscore: `_a`
    |
-LL |     fn method2(&self, a: usize, b: usize) -> usize {
-   |                                 ^ help: if this is intentional, prefix with an underscore: `_b`
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:75:62
+   |
+LL |         if flag == 0 { 0 } else { self.method_self(flag - 1, a) }
+   |                                                              ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:90:24
+  --> $DIR/only_used_in_recursion.rs:100:26
+   |
+LL |     fn method(flag: u32, a: usize) -> usize {
+   |                          ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:101:58
    |
-LL |     fn hello(a: usize, b: usize) -> usize {
-   |                        ^ help: if this is intentional, prefix with an underscore: `_b`
+LL |         if flag == 0 { 0 } else { Self::method(flag - 1, a) }
+   |                                                          ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:94:32
+  --> $DIR/only_used_in_recursion.rs:104:38
+   |
+LL |     fn method_self(&self, flag: u32, a: usize) -> usize {
+   |                                      ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:105:62
    |
-LL |     fn hello2(&self, a: usize, b: usize) -> usize {
-   |                                ^ help: if this is intentional, prefix with an underscore: `_b`
+LL |         if flag == 0 { 0 } else { self.method_self(flag - 1, a) }
+   |                                                              ^
 
-error: aborting due to 13 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/only_used_in_recursion2.rs b/src/tools/clippy/tests/ui/only_used_in_recursion2.rs
new file mode 100644 (file)
index 0000000..45dd055
--- /dev/null
@@ -0,0 +1,91 @@
+#![warn(clippy::only_used_in_recursion)]
+
+fn _with_inner(flag: u32, a: u32, b: u32) -> usize {
+    fn inner(flag: u32, a: u32) -> u32 {
+        if flag == 0 { 0 } else { inner(flag, a) }
+    }
+
+    let x = inner(flag, a);
+    if flag == 0 { 0 } else { _with_inner(flag, a, b + x) }
+}
+
+fn _with_closure(a: Option<u32>, b: u32, f: impl Fn(u32, u32) -> Option<u32>) -> u32 {
+    if let Some(x) = a.and_then(|x| f(x, x)) {
+        _with_closure(Some(x), b, f)
+    } else {
+        0
+    }
+}
+
+// Issue #8560
+trait D {
+    fn foo(&mut self, arg: u32) -> u32;
+}
+
+mod m {
+    pub struct S(u32);
+    impl S {
+        pub fn foo(&mut self, arg: u32) -> u32 {
+            arg + self.0
+        }
+    }
+}
+
+impl D for m::S {
+    fn foo(&mut self, arg: u32) -> u32 {
+        self.foo(arg)
+    }
+}
+
+// Issue #8782
+fn only_let(x: u32) {
+    let y = 10u32;
+    let _z = x * y;
+}
+
+trait E<T: E<()>> {
+    fn method(flag: u32, a: usize) -> usize {
+        if flag == 0 {
+            0
+        } else {
+            <T as E<()>>::method(flag - 1, a)
+        }
+    }
+}
+
+impl E<()> for () {
+    fn method(flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { a }
+    }
+}
+
+fn overwritten_param(flag: u32, mut a: usize) -> usize {
+    if flag == 0 {
+        return 0;
+    } else if flag > 5 {
+        a += flag as usize;
+    } else {
+        a = 5;
+    }
+    overwritten_param(flag, a)
+}
+
+fn field_direct(flag: u32, mut a: (usize,)) -> usize {
+    if flag == 0 {
+        0
+    } else {
+        a.0 += 5;
+        field_direct(flag - 1, a)
+    }
+}
+
+fn field_deref(flag: u32, a: &mut Box<(usize,)>) -> usize {
+    if flag == 0 {
+        0
+    } else {
+        a.0 += 5;
+        field_deref(flag - 1, a)
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr b/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr
new file mode 100644 (file)
index 0000000..23f6ffd
--- /dev/null
@@ -0,0 +1,63 @@
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion2.rs:3:35
+   |
+LL | fn _with_inner(flag: u32, a: u32, b: u32) -> usize {
+   |                                   ^ help: if this is intentional, prefix it with an underscore: `_b`
+   |
+   = note: `-D clippy::only-used-in-recursion` implied by `-D warnings`
+note: parameter used here
+  --> $DIR/only_used_in_recursion2.rs:9:52
+   |
+LL |     if flag == 0 { 0 } else { _with_inner(flag, a, b + x) }
+   |                                                    ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion2.rs:4:25
+   |
+LL |     fn inner(flag: u32, a: u32) -> u32 {
+   |                         ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion2.rs:5:47
+   |
+LL |         if flag == 0 { 0 } else { inner(flag, a) }
+   |                                               ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion2.rs:12:34
+   |
+LL | fn _with_closure(a: Option<u32>, b: u32, f: impl Fn(u32, u32) -> Option<u32>) -> u32 {
+   |                                  ^ help: if this is intentional, prefix it with an underscore: `_b`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion2.rs:14:32
+   |
+LL |         _with_closure(Some(x), b, f)
+   |                                ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion2.rs:62:37
+   |
+LL | fn overwritten_param(flag: u32, mut a: usize) -> usize {
+   |                                     ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion2.rs:70:29
+   |
+LL |     overwritten_param(flag, a)
+   |                             ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion2.rs:73:32
+   |
+LL | fn field_direct(flag: u32, mut a: (usize,)) -> usize {
+   |                                ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion2.rs:78:32
+   |
+LL |         field_direct(flag - 1, a)
+   |                                ^
+
+error: aborting due to 5 previous errors
+
index b6d5e106f057a36ab1503f701f144a37614e98db..f15ac551bb3ccfeefa774ae183e91f98a66f6ce0 100644 (file)
@@ -179,4 +179,13 @@ fn main() {
 
     let _ = pattern_to_vec("hello world");
     let _ = complex_subpat();
+
+    // issue #8492
+    let _ = s.map_or(1, |string| string.len());
+    let _ = Some(10).map_or(5, |a| a + 1);
+
+    let res: Result<i32, i32> = Ok(5);
+    let _ = res.map_or(1, |a| a + 1);
+    let _ = res.map_or(1, |a| a + 1);
+    let _ = res.map_or(5, |a| a + 1);
 }
index 35bae159343587be7ea1a98c959260a0cc3ab62b..9eeaea12d3bc91e615cb2fac5f3d3b10c0ffd0c9 100644 (file)
@@ -208,4 +208,25 @@ async fn _f2() {
 
     let _ = pattern_to_vec("hello world");
     let _ = complex_subpat();
+
+    // issue #8492
+    let _ = match s {
+        Some(string) => string.len(),
+        None => 1,
+    };
+    let _ = match Some(10) {
+        Some(a) => a + 1,
+        None => 5,
+    };
+
+    let res: Result<i32, i32> = Ok(5);
+    let _ = match res {
+        Ok(a) => a + 1,
+        _ => 1,
+    };
+    let _ = match res {
+        Err(_) => 1,
+        Ok(a) => a + 1,
+    };
+    let _ = if let Ok(a) = res { a + 1 } else { 5 };
 }
index daba606004e114d68ed95d95682e94a4fd59c7f2..a5dbf6e1f2218020a7439059f9a59f5dba493fde 100644 (file)
@@ -206,5 +206,51 @@ LL +         s.len() + x
 LL ~     });
    |
 
-error: aborting due to 15 previous errors
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:213:13
+   |
+LL |       let _ = match s {
+   |  _____________^
+LL | |         Some(string) => string.len(),
+LL | |         None => 1,
+LL | |     };
+   | |_____^ help: try: `s.map_or(1, |string| string.len())`
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:217:13
+   |
+LL |       let _ = match Some(10) {
+   |  _____________^
+LL | |         Some(a) => a + 1,
+LL | |         None => 5,
+LL | |     };
+   | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:223:13
+   |
+LL |       let _ = match res {
+   |  _____________^
+LL | |         Ok(a) => a + 1,
+LL | |         _ => 1,
+LL | |     };
+   | |_____^ help: try: `res.map_or(1, |a| a + 1)`
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:227:13
+   |
+LL |       let _ = match res {
+   |  _____________^
+LL | |         Err(_) => 1,
+LL | |         Ok(a) => a + 1,
+LL | |     };
+   | |_____^ help: try: `res.map_or(1, |a| a + 1)`
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:231:13
+   |
+LL |     let _ = if let Ok(a) = res { a + 1 } else { 5 };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
+
+error: aborting due to 20 previous errors
 
index fdb08d953ff1dbc95263e6d41e88861310d9a6b5..18ea4e550292a4b3ddd5a729f4ba946afe2f4d13 100644 (file)
@@ -90,8 +90,8 @@ fn or_fun_call() {
     let mut btree_vec = BTreeMap::<u64, Vec<i32>>::new();
     btree_vec.entry(42).or_insert(vec![]);
 
-    let stringy = Some(String::from(""));
-    let _ = stringy.unwrap_or_else(|| "".to_owned());
+    let stringy = Some(String::new());
+    let _ = stringy.unwrap_or_default();
 
     let opt = Some(1);
     let hello = "Hello";
index 57ab5f03ee2851318b3ba58d9fcc2c72d23e442e..c353b41e4495d96feee4525b5f1d20634d8bc694 100644 (file)
@@ -90,8 +90,8 @@ fn make<T>() -> T {
     let mut btree_vec = BTreeMap::<u64, Vec<i32>>::new();
     btree_vec.entry(42).or_insert(vec![]);
 
-    let stringy = Some(String::from(""));
-    let _ = stringy.unwrap_or("".to_owned());
+    let stringy = Some(String::new());
+    let _ = stringy.unwrap_or(String::new());
 
     let opt = Some(1);
     let hello = "Hello";
index 4c5938ab88b90926c25c189063ad1b4ab1e268f5..887f23ac9761dfd7167f44f269d3224cb6d75e75 100644 (file)
@@ -66,11 +66,11 @@ 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 `unwrap_or` followed by a function call
+error: use of `unwrap_or` followed by a call to `new`
   --> $DIR/or_fun_call.rs:94:21
    |
-LL |     let _ = stringy.unwrap_or("".to_owned());
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
+LL |     let _ = stringy.unwrap_or(String::new());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
 
 error: use of `unwrap_or` followed by a function call
   --> $DIR/or_fun_call.rs:102:21
index f3e4c58d6949223e0fe16b7e32c5bac5d22a34de..4644ea8f51da1ecd6def7c067aff736cdcebfd8a 100644 (file)
@@ -26,6 +26,18 @@ fn optref() -> &'static &'static Option<()> {
     &&None
 }
 
+pub fn macro_expansion() {
+    macro_rules! foo {
+        () => {
+            None::<()>
+        };
+    }
+
+    let _ = foobar() == foo!();
+    let _ = foo!() == foobar();
+    let _ = foo!() == foo!();
+}
+
 fn main() {
     let x = Some(0);
 
index 767b2a38bcc17ddba17267c2faa09ad10bef6cc1..61011b3a8c553cdb4a70704a1f46aaeea838494a 100644 (file)
@@ -26,6 +26,18 @@ fn optref() -> &'static &'static Option<()> {
     &&None
 }
 
+pub fn macro_expansion() {
+    macro_rules! foo {
+        () => {
+            None::<()>
+        };
+    }
+
+    let _ = foobar() == foo!();
+    let _ = foo!() == foobar();
+    let _ = foo!() == foo!();
+}
+
 fn main() {
     let x = Some(0);
 
index de15a9f7baaf030b02b5d4ab7a33a2e960134082..d06ab7aee558b3e04b59948413d022199a980956 100644 (file)
@@ -7,55 +7,55 @@ LL |     if f != None { "yay" } else { "nay" }
    = note: `-D clippy::partialeq-to-none` implied by `-D warnings`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:32:13
+  --> $DIR/partialeq_to_none.rs:44:13
    |
 LL |     let _ = x == None;
    |             ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:33:13
+  --> $DIR/partialeq_to_none.rs:45:13
    |
 LL |     let _ = x != None;
    |             ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:34:13
+  --> $DIR/partialeq_to_none.rs:46:13
    |
 LL |     let _ = None == x;
    |             ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:35:13
+  --> $DIR/partialeq_to_none.rs:47:13
    |
 LL |     let _ = None != x;
    |             ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:37:8
+  --> $DIR/partialeq_to_none.rs:49:8
    |
 LL |     if foobar() == None {}
    |        ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:39:8
+  --> $DIR/partialeq_to_none.rs:51:8
    |
 LL |     if bar().ok() != None {}
    |        ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:41:13
+  --> $DIR/partialeq_to_none.rs:53:13
    |
 LL |     let _ = Some(1 + 2) != None;
    |             ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:43:13
+  --> $DIR/partialeq_to_none.rs:55:13
    |
 LL |     let _ = { Some(0) } == None;
    |             ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:45:13
+  --> $DIR/partialeq_to_none.rs:57:13
    |
 LL |       let _ = {
    |  _____________^
@@ -77,31 +77,31 @@ LL ~     }.is_some();
    |
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:55:13
+  --> $DIR/partialeq_to_none.rs:67:13
    |
 LL |     let _ = optref() == &&None;
    |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:56:13
+  --> $DIR/partialeq_to_none.rs:68:13
    |
 LL |     let _ = &&None != optref();
    |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:57:13
+  --> $DIR/partialeq_to_none.rs:69:13
    |
 LL |     let _ = **optref() == None;
    |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:58:13
+  --> $DIR/partialeq_to_none.rs:70:13
    |
 LL |     let _ = &None != *optref();
    |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:61:13
+  --> $DIR/partialeq_to_none.rs:73:13
    |
 LL |     let _ = None != *x;
    |             ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()`
diff --git a/src/tools/clippy/tests/ui/positional_named_format_parameters.fixed b/src/tools/clippy/tests/ui/positional_named_format_parameters.fixed
new file mode 100644 (file)
index 0000000..4170e10
--- /dev/null
@@ -0,0 +1,56 @@
+// run-rustfix
+#![allow(unused_must_use)]
+#![allow(named_arguments_used_positionally)] // Unstable at time of writing.
+#![warn(clippy::positional_named_format_parameters)]
+
+use std::io::Write;
+
+fn main() {
+    let mut v = Vec::new();
+    let hello = "Hello";
+
+    println!("{hello:.foo$}", foo = 2);
+    writeln!(v, "{hello:.foo$}", foo = 2);
+
+    // Warnings
+    println!("{zero} {one:?}", zero = 0, one = 1);
+    println!("This is a test {zero} {one:?}", zero = 0, one = 1);
+    println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01);
+    println!("Hello {one:zero$}!", zero = 5, one = 1);
+    println!("Hello {zero:one$}!", zero = 4, one = 1);
+    println!("Hello {zero:0one$}!", zero = 4, one = 1);
+    println!("Hello is {one:.zero$}", zero = 5, one = 0.01);
+    println!("Hello is {one:<6.zero$}", zero = 5, one = 0.01);
+    println!("{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello);
+    println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01);
+    println!("Hello {world} {world}!", world = 5);
+
+    writeln!(v, "{zero} {one:?}", zero = 0, one = 1);
+    writeln!(v, "This is a test {zero} {one:?}", zero = 0, one = 1);
+    writeln!(v, "Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01);
+    writeln!(v, "Hello {one:zero$}!", zero = 4, one = 1);
+    writeln!(v, "Hello {zero:one$}!", zero = 4, one = 1);
+    writeln!(v, "Hello {zero:0one$}!", zero = 4, one = 1);
+    writeln!(v, "Hello is {one:.zero$}", zero = 3, one = 0.01);
+    writeln!(v, "Hello is {one:<6.zero$}", zero = 2, one = 0.01);
+    writeln!(v, "{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello);
+    writeln!(v, "Hello {one} is {two:.zero$}", zero = 1, one = hello, two = 0.01);
+    writeln!(v, "Hello {world} {world}!", world = 0);
+
+    // Tests from other files
+    println!("{w:w$}", w = 1);
+    println!("{p:.p$}", p = 1);
+    println!("{v}", v = 1);
+    println!("{v:v$}", v = 1);
+    println!("{v:v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{w:w$}", w = 1);
+    println!("{p:.p$}", p = 1);
+    println!("{:p$.w$}", 1, w = 1, p = 1);
+}
diff --git a/src/tools/clippy/tests/ui/positional_named_format_parameters.rs b/src/tools/clippy/tests/ui/positional_named_format_parameters.rs
new file mode 100644 (file)
index 0000000..553d849
--- /dev/null
@@ -0,0 +1,56 @@
+// run-rustfix
+#![allow(unused_must_use)]
+#![allow(named_arguments_used_positionally)] // Unstable at time of writing.
+#![warn(clippy::positional_named_format_parameters)]
+
+use std::io::Write;
+
+fn main() {
+    let mut v = Vec::new();
+    let hello = "Hello";
+
+    println!("{hello:.foo$}", foo = 2);
+    writeln!(v, "{hello:.foo$}", foo = 2);
+
+    // Warnings
+    println!("{} {1:?}", zero = 0, one = 1);
+    println!("This is a test { } {000001:?}", zero = 0, one = 1);
+    println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+    println!("Hello {1:0$}!", zero = 5, one = 1);
+    println!("Hello {0:1$}!", zero = 4, one = 1);
+    println!("Hello {0:01$}!", zero = 4, one = 1);
+    println!("Hello is {1:.*}", zero = 5, one = 0.01);
+    println!("Hello is {:<6.*}", zero = 5, one = 0.01);
+    println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
+    println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+    println!("Hello {world} {}!", world = 5);
+
+    writeln!(v, "{} {1:?}", zero = 0, one = 1);
+    writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1);
+    writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+    writeln!(v, "Hello {1:0$}!", zero = 4, one = 1);
+    writeln!(v, "Hello {0:1$}!", zero = 4, one = 1);
+    writeln!(v, "Hello {0:01$}!", zero = 4, one = 1);
+    writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01);
+    writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01);
+    writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
+    writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
+    writeln!(v, "Hello {world} {}!", world = 0);
+
+    // Tests from other files
+    println!("{:w$}", w = 1);
+    println!("{:.p$}", p = 1);
+    println!("{}", v = 1);
+    println!("{:0$}", v = 1);
+    println!("{0:0$}", v = 1);
+    println!("{:0$.0$}", v = 1);
+    println!("{0:0$.0$}", v = 1);
+    println!("{0:0$.v$}", v = 1);
+    println!("{0:v$.0$}", v = 1);
+    println!("{v:0$.0$}", v = 1);
+    println!("{v:v$.0$}", v = 1);
+    println!("{v:0$.v$}", v = 1);
+    println!("{:w$}", w = 1);
+    println!("{:.p$}", p = 1);
+    println!("{:p$.w$}", 1, w = 1, p = 1);
+}
diff --git a/src/tools/clippy/tests/ui/positional_named_format_parameters.stderr b/src/tools/clippy/tests/ui/positional_named_format_parameters.stderr
new file mode 100644 (file)
index 0000000..48ddb6d
--- /dev/null
@@ -0,0 +1,418 @@
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:16:16
+   |
+LL |     println!("{} {1:?}", zero = 0, one = 1);
+   |                ^ help: replace it with: `zero`
+   |
+   = note: `-D clippy::positional-named-format-parameters` implied by `-D warnings`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:16:19
+   |
+LL |     println!("{} {1:?}", zero = 0, one = 1);
+   |                   ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:17:31
+   |
+LL |     println!("This is a test { } {000001:?}", zero = 0, one = 1);
+   |                               ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:17:35
+   |
+LL |     println!("This is a test { } {000001:?}", zero = 0, one = 1);
+   |                                   ^^^^^^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:18:32
+   |
+LL |     println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                                ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:18:22
+   |
+LL |     println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                      ^ help: replace it with: `one`
+
+error: named parameter two is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:18:29
+   |
+LL |     println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                             ^ help: replace it with: `two`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:19:24
+   |
+LL |     println!("Hello {1:0$}!", zero = 5, one = 1);
+   |                        ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:19:22
+   |
+LL |     println!("Hello {1:0$}!", zero = 5, one = 1);
+   |                      ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:20:22
+   |
+LL |     println!("Hello {0:1$}!", zero = 4, one = 1);
+   |                      ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:20:24
+   |
+LL |     println!("Hello {0:1$}!", zero = 4, one = 1);
+   |                        ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:21:22
+   |
+LL |     println!("Hello {0:01$}!", zero = 4, one = 1);
+   |                      ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:21:25
+   |
+LL |     println!("Hello {0:01$}!", zero = 4, one = 1);
+   |                         ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:22:28
+   |
+LL |     println!("Hello is {1:.*}", zero = 5, one = 0.01);
+   |                            ^ help: replace it with: `zero$`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:22:25
+   |
+LL |     println!("Hello is {1:.*}", zero = 5, one = 0.01);
+   |                         ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:23:29
+   |
+LL |     println!("Hello is {:<6.*}", zero = 5, one = 0.01);
+   |                             ^ help: replace it with: `zero$`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:23:25
+   |
+LL |     println!("Hello is {:<6.*}", zero = 5, one = 0.01);
+   |                         ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:24:16
+   |
+LL |     println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
+   |                ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:24:28
+   |
+LL |     println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
+   |                            ^ help: replace it with: `one$`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:25:32
+   |
+LL |     println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                                ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:25:22
+   |
+LL |     println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                      ^ help: replace it with: `one`
+
+error: named parameter two is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:25:29
+   |
+LL |     println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                             ^ help: replace it with: `two`
+
+error: named parameter world is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:26:30
+   |
+LL |     println!("Hello {world} {}!", world = 5);
+   |                              ^ help: replace it with: `world`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:28:19
+   |
+LL |     writeln!(v, "{} {1:?}", zero = 0, one = 1);
+   |                   ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:28:22
+   |
+LL |     writeln!(v, "{} {1:?}", zero = 0, one = 1);
+   |                      ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:29:34
+   |
+LL |     writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1);
+   |                                  ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:29:38
+   |
+LL |     writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1);
+   |                                      ^^^^^^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:30:35
+   |
+LL |     writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                                   ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:30:25
+   |
+LL |     writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                         ^ help: replace it with: `one`
+
+error: named parameter two is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:30:32
+   |
+LL |     writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                                ^ help: replace it with: `two`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:31:27
+   |
+LL |     writeln!(v, "Hello {1:0$}!", zero = 4, one = 1);
+   |                           ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:31:25
+   |
+LL |     writeln!(v, "Hello {1:0$}!", zero = 4, one = 1);
+   |                         ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:32:25
+   |
+LL |     writeln!(v, "Hello {0:1$}!", zero = 4, one = 1);
+   |                         ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:32:27
+   |
+LL |     writeln!(v, "Hello {0:1$}!", zero = 4, one = 1);
+   |                           ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:33:25
+   |
+LL |     writeln!(v, "Hello {0:01$}!", zero = 4, one = 1);
+   |                         ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:33:28
+   |
+LL |     writeln!(v, "Hello {0:01$}!", zero = 4, one = 1);
+   |                            ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:34:31
+   |
+LL |     writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01);
+   |                               ^ help: replace it with: `zero$`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:34:28
+   |
+LL |     writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01);
+   |                            ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:35:32
+   |
+LL |     writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01);
+   |                                ^ help: replace it with: `zero$`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:35:28
+   |
+LL |     writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01);
+   |                            ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:36:19
+   |
+LL |     writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
+   |                   ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:36:31
+   |
+LL |     writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
+   |                               ^ help: replace it with: `one$`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:37:35
+   |
+LL |     writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
+   |                                   ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:37:25
+   |
+LL |     writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
+   |                         ^ help: replace it with: `one`
+
+error: named parameter two is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:37:32
+   |
+LL |     writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
+   |                                ^ help: replace it with: `two`
+
+error: named parameter world is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:38:33
+   |
+LL |     writeln!(v, "Hello {world} {}!", world = 0);
+   |                                 ^ help: replace it with: `world`
+
+error: named parameter w is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:41:16
+   |
+LL |     println!("{:w$}", w = 1);
+   |                ^ help: replace it with: `w`
+
+error: named parameter p is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:42:16
+   |
+LL |     println!("{:.p$}", p = 1);
+   |                ^ help: replace it with: `p`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:43:16
+   |
+LL |     println!("{}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:44:16
+   |
+LL |     println!("{:0$}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:44:17
+   |
+LL |     println!("{:0$}", v = 1);
+   |                 ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:45:16
+   |
+LL |     println!("{0:0$}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:45:18
+   |
+LL |     println!("{0:0$}", v = 1);
+   |                  ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:46:16
+   |
+LL |     println!("{:0$.0$}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:46:20
+   |
+LL |     println!("{:0$.0$}", v = 1);
+   |                    ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:46:17
+   |
+LL |     println!("{:0$.0$}", v = 1);
+   |                 ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:47:16
+   |
+LL |     println!("{0:0$.0$}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:47:21
+   |
+LL |     println!("{0:0$.0$}", v = 1);
+   |                     ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:47:18
+   |
+LL |     println!("{0:0$.0$}", v = 1);
+   |                  ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:48:16
+   |
+LL |     println!("{0:0$.v$}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:48:18
+   |
+LL |     println!("{0:0$.v$}", v = 1);
+   |                  ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:49:16
+   |
+LL |     println!("{0:v$.0$}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:49:21
+   |
+LL |     println!("{0:v$.0$}", v = 1);
+   |                     ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:50:21
+   |
+LL |     println!("{v:0$.0$}", v = 1);
+   |                     ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:50:18
+   |
+LL |     println!("{v:0$.0$}", v = 1);
+   |                  ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:51:21
+   |
+LL |     println!("{v:v$.0$}", v = 1);
+   |                     ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:52:18
+   |
+LL |     println!("{v:0$.v$}", v = 1);
+   |                  ^ help: replace it with: `v`
+
+error: named parameter w is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:53:16
+   |
+LL |     println!("{:w$}", w = 1);
+   |                ^ help: replace it with: `w`
+
+error: named parameter p is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:54:16
+   |
+LL |     println!("{:.p$}", p = 1);
+   |                ^ help: replace it with: `p`
+
+error: aborting due to 69 previous errors
+
index c4c9c82143336647e2dafb04292544c81797c6d5..57f23bd1916ffaa46272f152ebc52f5d79c1f8e3 100644 (file)
@@ -207,4 +207,19 @@ fn option_map() -> Option<bool> {
     }
 }
 
+pub struct PatternedError {
+    flag: bool,
+}
+
+// No warning
+fn pattern() -> Result<(), PatternedError> {
+    let res = Ok(());
+
+    if let Err(err @ PatternedError { flag: true }) = res {
+        return Err(err);
+    }
+
+    res
+}
+
 fn main() {}
index cdbc7b1606f80782c7d107e213311e4b79cb6769..436f027c215d54f459d244628acd9b358899c51c 100644 (file)
@@ -243,4 +243,19 @@ fn option_map() -> Option<bool> {
     }
 }
 
+pub struct PatternedError {
+    flag: bool,
+}
+
+// No warning
+fn pattern() -> Result<(), PatternedError> {
+    let res = Ok(());
+
+    if let Err(err @ PatternedError { flag: true }) = res {
+        return Err(err);
+    }
+
+    res
+}
+
 fn main() {}
index f7f3b195ccc18f28143e4503dceab210a0d583e9..f0e1a8128d7c36b5bc44d3d77c7ee270988780d7 100644 (file)
@@ -1,4 +1,4 @@
-#![allow(unused)]
+#![allow(unused, clippy::needless_borrow)]
 #![warn(clippy::invalid_regex, clippy::trivial_regex)]
 
 extern crate regex;
diff --git a/src/tools/clippy/tests/ui/result_large_err.rs b/src/tools/clippy/tests/ui/result_large_err.rs
new file mode 100644 (file)
index 0000000..78d8f76
--- /dev/null
@@ -0,0 +1,98 @@
+#![warn(clippy::result_large_err)]
+
+pub fn small_err() -> Result<(), u128> {
+    Ok(())
+}
+
+pub fn large_err() -> Result<(), [u8; 512]> {
+    Ok(())
+}
+
+pub struct FullyDefinedLargeError {
+    _foo: u128,
+    _bar: [u8; 100],
+    _foobar: [u8; 120],
+}
+
+impl FullyDefinedLargeError {
+    pub fn ret() -> Result<(), Self> {
+        Ok(())
+    }
+}
+
+pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
+    Ok(())
+}
+
+type Fdlr<T> = std::result::Result<T, FullyDefinedLargeError>;
+pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
+    Ok(x)
+}
+
+pub fn param_small_error<R>() -> Result<(), (R, u128)> {
+    Ok(())
+}
+
+pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeError)> {
+    Ok(())
+}
+
+pub enum LargeErrorVariants<T> {
+    _Small(u8),
+    _Omg([u8; 512]),
+    _Param(T),
+}
+
+impl LargeErrorVariants<()> {
+    pub fn large_enum_error() -> Result<(), Self> {
+        Ok(())
+    }
+}
+
+trait TraitForcesLargeError {
+    fn large_error() -> Result<(), [u8; 512]> {
+        Ok(())
+    }
+}
+
+struct TraitImpl;
+
+impl TraitForcesLargeError for TraitImpl {
+    // Should not lint
+    fn large_error() -> Result<(), [u8; 512]> {
+        Ok(())
+    }
+}
+
+pub union FullyDefinedUnionError {
+    _maybe: u8,
+    _or_even: [[u8; 16]; 32],
+}
+
+pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
+    Ok(())
+}
+
+pub union UnionError<T: Copy> {
+    _maybe: T,
+    _or_perhaps_even: (T, [u8; 512]),
+}
+
+pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
+    Ok(())
+}
+
+pub struct ArrayError<T, U> {
+    _large_array: [T; 32],
+    _other_stuff: U,
+}
+
+pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
+    Ok(())
+}
+
+pub fn array_error<T, U>() -> Result<(), ArrayError<(i32, T), U>> {
+    Ok(())
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/result_large_err.stderr b/src/tools/clippy/tests/ui/result_large_err.stderr
new file mode 100644 (file)
index 0000000..0f1f39d
--- /dev/null
@@ -0,0 +1,91 @@
+error: the `Err`-variant returned from this function is very large
+  --> $DIR/result_large_err.rs:7:23
+   |
+LL | pub fn large_err() -> Result<(), [u8; 512]> {
+   |                       ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
+   |
+   = note: `-D clippy::result-large-err` implied by `-D warnings`
+   = 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
+   |
+LL |     pub fn ret() -> Result<(), Self> {
+   |                     ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
+   |
+   = 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
+   |
+LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
+   |
+   = 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
+   |
+LL | pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
+   |                                             ^^^^^^^ the `Err`-variant is at least 240 bytes
+   |
+   = 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
+   |
+LL | pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeError)> {
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 256 bytes
+   |
+   = 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
+   |
+LL |     pub fn large_enum_error() -> Result<(), Self> {
+   |                                  ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 513 bytes
+   |
+   = 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
+   |
+LL |     fn large_error() -> Result<(), [u8; 512]> {
+   |                         ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
+   |
+   = 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
+   |
+LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
+   |
+   = 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
+   |
+LL | pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
+   |
+   = 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
+   |
+LL | pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes
+   |
+   = 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
+   |
+LL | pub fn array_error<T, U>() -> Result<(), ArrayError<(i32, T), U>> {
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes
+   |
+   = help: try reducing the size of `ArrayError<(i32, T), U>`, for example by boxing large elements or replacing it with `Box<ArrayError<(i32, T), U>>`
+
+error: aborting due to 11 previous errors
+
index 99964f0de075c04a53467f12fd732e2f97a9506e..af01a8df71b015cff39987006088878f8a4db000 100644 (file)
@@ -151,6 +151,7 @@ impl T for S {}
 
     // Fix #6987
     let mut vec = Vec::new();
+    #[allow(clippy::needless_borrow)]
     for _ in 0..10 {
         vec.push(1);
         vec.extend(&[2]);
index 30fd17c59e518ed931dd82d8ed01c5e64865cf62..16673c01e63017da5769a39ea8085cf9f348dc76 100644 (file)
@@ -7,13 +7,13 @@
 #[allow(clippy::string_add_assign, unused)]
 fn main() {
     // ignores assignment distinction
-    let mut x = "".to_owned();
+    let mut x = String::new();
 
     for _ in 1..3 {
         x = x + ".";
     }
 
-    let y = "".to_owned();
+    let y = String::new();
     let z = y + "...";
 
     assert_eq!(&x, &z);
index db71bab1e5214a96baceeb1a62ee426e3d6173a3..b687f43b2541a016af4cb3abe8a07ce865b5de2c 100644 (file)
@@ -4,13 +4,13 @@
 #[warn(clippy::string_add_assign)]
 fn main() {
     // ignores assignment distinction
-    let mut x = "".to_owned();
+    let mut x = String::new();
 
     for _ in 1..3 {
         x += ".";
     }
 
-    let y = "".to_owned();
+    let y = String::new();
     let z = y + "...";
 
     assert_eq!(&x, &z);
index 644991945cbe2b77da49ca71a1e5e8a8830301a3..e5dbde108fbdbebd46df2e51583b9f18f34603c8 100644 (file)
@@ -4,13 +4,13 @@
 #[warn(clippy::string_add_assign)]
 fn main() {
     // ignores assignment distinction
-    let mut x = "".to_owned();
+    let mut x = String::new();
 
     for _ in 1..3 {
         x = x + ".";
     }
 
-    let y = "".to_owned();
+    let y = String::new();
     let z = y + "...";
 
     assert_eq!(&x, &z);
diff --git a/src/tools/clippy/tests/ui/suspicious_to_owned.rs b/src/tools/clippy/tests/ui/suspicious_to_owned.rs
new file mode 100644 (file)
index 0000000..cba21bf
--- /dev/null
@@ -0,0 +1,62 @@
+#![warn(clippy::suspicious_to_owned)]
+#![warn(clippy::implicit_clone)]
+#![allow(clippy::redundant_clone)]
+use std::borrow::Cow;
+use std::ffi::{c_char, CStr};
+
+fn main() {
+    let moo = "Moooo";
+    let c_moo = b"Moooo\0";
+    let c_moo_ptr = c_moo.as_ptr() as *const c_char;
+    let moos = ['M', 'o', 'o'];
+    let moos_vec = moos.to_vec();
+
+    // we expect this to be linted
+    let cow = Cow::Borrowed(moo);
+    let _ = cow.to_owned();
+    // we expect no lints for this
+    let cow = Cow::Borrowed(moo);
+    let _ = cow.into_owned();
+    // we expect no lints for this
+    let cow = Cow::Borrowed(moo);
+    let _ = cow.clone();
+
+    // we expect this to be linted
+    let cow = Cow::Borrowed(&moos);
+    let _ = cow.to_owned();
+    // we expect no lints for this
+    let cow = Cow::Borrowed(&moos);
+    let _ = cow.into_owned();
+    // we expect no lints for this
+    let cow = Cow::Borrowed(&moos);
+    let _ = cow.clone();
+
+    // we expect this to be linted
+    let cow = Cow::Borrowed(&moos_vec);
+    let _ = cow.to_owned();
+    // we expect no lints for this
+    let cow = Cow::Borrowed(&moos_vec);
+    let _ = cow.into_owned();
+    // we expect no lints for this
+    let cow = Cow::Borrowed(&moos_vec);
+    let _ = cow.clone();
+
+    // we expect this to be linted
+    let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy();
+    let _ = cow.to_owned();
+    // we expect no lints for this
+    let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy();
+    let _ = cow.into_owned();
+    // we expect no lints for this
+    let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy();
+    let _ = cow.clone();
+
+    // we expect no lints for these
+    let _ = moo.to_owned();
+    let _ = c_moo.to_owned();
+    let _ = moos.to_owned();
+
+    // we expect implicit_clone lints for these
+    let _ = String::from(moo).to_owned();
+    let _ = moos_vec.to_owned();
+}
diff --git a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr
new file mode 100644 (file)
index 0000000..92e1024
--- /dev/null
@@ -0,0 +1,42 @@
+error: this `to_owned` call clones the std::borrow::Cow<str> itself and does not cause the std::borrow::Cow<str> contents to become owned
+  --> $DIR/suspicious_to_owned.rs:16:13
+   |
+LL |     let _ = cow.to_owned();
+   |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+   |
+   = note: `-D clippy::suspicious-to-owned` implied by `-D warnings`
+
+error: this `to_owned` call clones the std::borrow::Cow<[char; 3]> itself and does not cause the std::borrow::Cow<[char; 3]> contents to become owned
+  --> $DIR/suspicious_to_owned.rs:26:13
+   |
+LL |     let _ = cow.to_owned();
+   |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+
+error: this `to_owned` call clones the std::borrow::Cow<std::vec::Vec<char>> itself and does not cause the std::borrow::Cow<std::vec::Vec<char>> contents to become owned
+  --> $DIR/suspicious_to_owned.rs:36:13
+   |
+LL |     let _ = cow.to_owned();
+   |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+
+error: this `to_owned` call clones the std::borrow::Cow<str> itself and does not cause the std::borrow::Cow<str> contents to become owned
+  --> $DIR/suspicious_to_owned.rs:46:13
+   |
+LL |     let _ = cow.to_owned();
+   |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+
+error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type
+  --> $DIR/suspicious_to_owned.rs:60:13
+   |
+LL |     let _ = String::from(moo).to_owned();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::from(moo).clone()`
+   |
+   = note: `-D clippy::implicit-clone` implied by `-D warnings`
+
+error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type
+  --> $DIR/suspicious_to_owned.rs:61:13
+   |
+LL |     let _ = moos_vec.to_owned();
+   |             ^^^^^^^^^^^^^^^^^^^ help: consider using: `moos_vec.clone()`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed
new file mode 100644 (file)
index 0000000..4ce5d42
--- /dev/null
@@ -0,0 +1,112 @@
+// run-rustfix
+#![deny(clippy::trait_duplication_in_bounds)]
+#![allow(unused)]
+
+fn bad_foo<T: Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
+    unimplemented!();
+}
+
+fn bad_bar<T, U>(arg0: T, arg1: U)
+where
+    T: Clone + Copy,
+    U: Clone + Copy,
+{
+    unimplemented!();
+}
+
+fn good_bar<T: Clone + Copy, U: Clone + Copy>(arg0: T, arg1: U) {
+    unimplemented!();
+}
+
+fn good_foo<T, U>(arg0: T, arg1: U)
+where
+    T: Clone + Copy,
+    U: Clone + Copy,
+{
+    unimplemented!();
+}
+
+trait GoodSelfTraitBound: Clone + Copy {
+    fn f();
+}
+
+trait GoodSelfWhereClause {
+    fn f()
+    where
+        Self: Clone + Copy;
+}
+
+trait BadSelfTraitBound: Clone {
+    fn f();
+}
+
+trait BadSelfWhereClause {
+    fn f()
+    where
+        Self: Clone;
+}
+
+trait GoodTraitBound<T: Clone + Copy, U: Clone + Copy> {
+    fn f();
+}
+
+trait GoodWhereClause<T, U> {
+    fn f()
+    where
+        T: Clone + Copy,
+        U: Clone + Copy;
+}
+
+trait BadTraitBound<T: Clone + Copy, U: Clone + Copy> {
+    fn f();
+}
+
+trait BadWhereClause<T, U> {
+    fn f()
+    where
+        T: Clone + Copy,
+        U: Clone + Copy;
+}
+
+struct GoodStructBound<T: Clone + Copy, U: Clone + Copy> {
+    t: T,
+    u: U,
+}
+
+impl<T: Clone + Copy, U: Clone + Copy> GoodTraitBound<T, U> for GoodStructBound<T, U> {
+    // this should not warn
+    fn f() {}
+}
+
+struct GoodStructWhereClause;
+
+impl<T, U> GoodTraitBound<T, U> for GoodStructWhereClause
+where
+    T: Clone + Copy,
+    U: Clone + Copy,
+{
+    // this should not warn
+    fn f() {}
+}
+
+fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
+
+trait GenericTrait<T> {}
+
+fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
+    unimplemented!();
+}
+
+fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
+    unimplemented!();
+}
+
+mod foo {
+    pub trait Clone {}
+}
+
+fn qualified_path<T: std::clone::Clone + foo::Clone>(arg0: T) {
+    unimplemented!();
+}
+
+fn main() {}
index a5751c58aab8f09f1b7c032f281d4281e001e2d5..7f2e96a22e6648eb27aaf1178eec55ff2c86cab5 100644 (file)
+// run-rustfix
 #![deny(clippy::trait_duplication_in_bounds)]
 #![allow(unused)]
 
-use std::collections::BTreeMap;
-use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
+fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
+    unimplemented!();
+}
 
-fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+fn bad_bar<T, U>(arg0: T, arg1: U)
 where
-    T: Clone,
-    T: Default,
+    T: Clone + Clone + Clone + Copy,
+    U: Clone + Copy,
 {
     unimplemented!();
 }
 
-fn good_bar<T: Clone + Default>(arg: T) {
+fn good_bar<T: Clone + Copy, U: Clone + Copy>(arg0: T, arg1: U) {
     unimplemented!();
 }
 
-fn good_foo<T>(arg: T)
+fn good_foo<T, U>(arg0: T, arg1: U)
 where
-    T: Clone + Default,
+    T: Clone + Copy,
+    U: Clone + Copy,
 {
     unimplemented!();
 }
 
-fn good_foobar<T: Default>(arg: T)
-where
-    T: Clone,
-{
-    unimplemented!();
+trait GoodSelfTraitBound: Clone + Copy {
+    fn f();
 }
 
-trait T: Default {
+trait GoodSelfWhereClause {
     fn f()
     where
-        Self: Default;
+        Self: Clone + Copy;
 }
 
-trait U: Default {
+trait BadSelfTraitBound: Clone + Clone + Clone {
+    fn f();
+}
+
+trait BadSelfWhereClause {
     fn f()
     where
-        Self: Clone;
+        Self: Clone + Clone + Clone;
+}
+
+trait GoodTraitBound<T: Clone + Copy, U: Clone + Copy> {
+    fn f();
 }
 
-trait ZZ: Default {
-    fn g();
-    fn h();
+trait GoodWhereClause<T, U> {
     fn f()
     where
-        Self: Default + Clone;
+        T: Clone + Copy,
+        U: Clone + Copy;
 }
 
-trait BadTrait: Default + Clone {
+trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
+    fn f();
+}
+
+trait BadWhereClause<T, U> {
     fn f()
     where
-        Self: Default + Clone;
-    fn g()
-    where
-        Self: Default;
-    fn h()
-    where
-        Self: Copy;
+        T: Clone + Clone + Clone + Copy,
+        U: Clone + Copy;
 }
 
-#[derive(Default, Clone)]
-struct Life;
+struct GoodStructBound<T: Clone + Copy, U: Clone + Copy> {
+    t: T,
+    u: U,
+}
 
-impl T for Life {
+impl<T: Clone + Copy, U: Clone + Copy> GoodTraitBound<T, U> for GoodStructBound<T, U> {
     // this should not warn
     fn f() {}
 }
 
-impl U for Life {
+struct GoodStructWhereClause;
+
+impl<T, U> GoodTraitBound<T, U> for GoodStructWhereClause
+where
+    T: Clone + Copy,
+    U: Clone + Copy,
+{
     // this should not warn
     fn f() {}
 }
 
-// should not warn
-trait Iter: Iterator {
-    fn into_group_btreemap<K, V>(self) -> BTreeMap<K, Vec<V>>
-    where
-        Self: Iterator<Item = (K, V)> + Sized,
-        K: Ord + Eq,
-    {
-        unimplemented!();
-    }
-}
+fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
 
-struct Foo;
+trait GenericTrait<T> {}
 
-trait FooIter: Iterator<Item = Foo> {
-    fn bar()
-    where
-        Self: Iterator<Item = Foo>,
-    {
-    }
+fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
+    unimplemented!();
 }
 
-// This should not lint
-fn impl_trait(_: impl AsRef<str>, _: impl AsRef<str>) {}
-
-mod repeated_where_clauses_or_trait_bounds {
-    fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
-        unimplemented!();
-    }
-
-    fn bad_bar<T, U>(arg0: T, arg1: U)
-    where
-        T: Clone + Clone + Clone + Copy,
-        U: Clone + Copy,
-    {
-        unimplemented!();
-    }
-
-    fn good_bar<T: Clone + Copy, U: Clone + Copy>(arg0: T, arg1: U) {
-        unimplemented!();
-    }
-
-    fn good_foo<T, U>(arg0: T, arg1: U)
-    where
-        T: Clone + Copy,
-        U: Clone + Copy,
-    {
-        unimplemented!();
-    }
-
-    trait GoodSelfTraitBound: Clone + Copy {
-        fn f();
-    }
-
-    trait GoodSelfWhereClause {
-        fn f()
-        where
-            Self: Clone + Copy;
-    }
-
-    trait BadSelfTraitBound: Clone + Clone + Clone {
-        fn f();
-    }
-
-    trait BadSelfWhereClause {
-        fn f()
-        where
-            Self: Clone + Clone + Clone;
-    }
-
-    trait GoodTraitBound<T: Clone + Copy, U: Clone + Copy> {
-        fn f();
-    }
-
-    trait GoodWhereClause<T, U> {
-        fn f()
-        where
-            T: Clone + Copy,
-            U: Clone + Copy;
-    }
-
-    trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
-        fn f();
-    }
-
-    trait BadWhereClause<T, U> {
-        fn f()
-        where
-            T: Clone + Clone + Clone + Copy,
-            U: Clone + Copy;
-    }
-
-    struct GoodStructBound<T: Clone + Copy, U: Clone + Copy> {
-        t: T,
-        u: U,
-    }
-
-    impl<T: Clone + Copy, U: Clone + Copy> GoodTraitBound<T, U> for GoodStructBound<T, U> {
-        // this should not warn
-        fn f() {}
-    }
-
-    struct GoodStructWhereClause;
-
-    impl<T, U> GoodTraitBound<T, U> for GoodStructWhereClause
-    where
-        T: Clone + Copy,
-        U: Clone + Copy,
-    {
-        // this should not warn
-        fn f() {}
-    }
-
-    fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
-
-    trait GenericTrait<T> {}
-
-    // This should not warn but currently does see #8757
-    fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
-        unimplemented!();
-    }
-
-    fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
-        unimplemented!();
-    }
+fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
+    unimplemented!();
+}
 
-    mod foo {
-        pub trait Clone {}
-    }
+mod foo {
+    pub trait Clone {}
+}
 
-    fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
-        unimplemented!();
-    }
+fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
+    unimplemented!();
 }
 
 fn main() {}
index 7ef04e52708f4c91e16c67c6dddf6cc786779c9b..af800ba78880c39ed5e5b936c850e5138f993c59 100644 (file)
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:7:15
+error: these bounds contain repeated elements
+  --> $DIR/trait_duplication_in_bounds.rs:5:15
    |
-LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
-   |               ^^^^^
+LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
    |
 note: the lint level is defined here
-  --> $DIR/trait_duplication_in_bounds.rs:1:9
+  --> $DIR/trait_duplication_in_bounds.rs:2:9
    |
 LL | #![deny(clippy::trait_duplication_in_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:7:23
-   |
-LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
-   |                       ^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:36:15
-   |
-LL |         Self: Default;
-   |               ^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:50:15
-   |
-LL |         Self: Default + Clone;
-   |               ^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:56:15
-   |
-LL |         Self: Default + Clone;
-   |               ^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:56:25
-   |
-LL |         Self: Default + Clone;
-   |                         ^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:59:15
-   |
-LL |         Self: Default;
-   |               ^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:94:15
-   |
-LL |         Self: Iterator<Item = Foo>,
-   |               ^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:103:19
-   |
-LL |     fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
-   |                   ^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:103:19
-   |
-LL |     fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:109:12
-   |
-LL |         T: Clone + Clone + Clone + Copy,
-   |            ^^^^^
-   |
-   = help: consider removing this trait bound
 
 error: these where clauses contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:109:12
+  --> $DIR/trait_duplication_in_bounds.rs:11:8
    |
-LL |         T: Clone + Clone + Clone + Copy,
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
+LL |     T: Clone + Clone + Clone + Copy,
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
 
 error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:137:30
+  --> $DIR/trait_duplication_in_bounds.rs:39:26
    |
-LL |     trait BadSelfTraitBound: Clone + Clone + Clone {
-   |                              ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
+LL | trait BadSelfTraitBound: Clone + Clone + Clone {
+   |                          ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
 
 error: these where clauses contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:144:19
-   |
-LL |             Self: Clone + Clone + Clone;
-   |                   ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:158:28
+  --> $DIR/trait_duplication_in_bounds.rs:46:15
    |
-LL |     trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
-   |                            ^^^^^
-   |
-   = help: consider removing this trait bound
+LL |         Self: Clone + Clone + Clone;
+   |               ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
 
 error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:158:28
+  --> $DIR/trait_duplication_in_bounds.rs:60:24
    |
-LL |     trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
+LL | trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
 
 error: these where clauses contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:165:16
-   |
-LL |             T: Clone + Clone + Clone + Copy,
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:195:24
-   |
-LL |     fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
-   |                        ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:199:23
+  --> $DIR/trait_duplication_in_bounds.rs:67:12
    |
-LL |     fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
-   |                       ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider removing this trait bound
+LL |         T: Clone + Clone + Clone + Copy,
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
 
 error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:199:23
-   |
-LL |     fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait<u32> + GenericTrait<u64>`
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:207:26
-   |
-LL |     fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
-   |                          ^^^^^^^^^^^^^^^^^
+  --> $DIR/trait_duplication_in_bounds.rs:100:19
    |
-   = help: consider removing this trait bound
+LL | fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait<u64> + GenericTrait<u32>`
 
 error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:207:26
+  --> $DIR/trait_duplication_in_bounds.rs:108:22
    |
-LL |     fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + foo::Clone`
+LL | fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone`
 
-error: aborting due to 22 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.rs
new file mode 100644 (file)
index 0000000..5630a03
--- /dev/null
@@ -0,0 +1,166 @@
+#![deny(clippy::trait_duplication_in_bounds)]
+
+use std::collections::BTreeMap;
+use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
+
+fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+where
+    T: Clone,
+    T: Default,
+{
+    unimplemented!();
+}
+
+fn good_bar<T: Clone + Default>(arg: T) {
+    unimplemented!();
+}
+
+fn good_foo<T>(arg: T)
+where
+    T: Clone + Default,
+{
+    unimplemented!();
+}
+
+fn good_foobar<T: Default>(arg: T)
+where
+    T: Clone,
+{
+    unimplemented!();
+}
+
+trait T: Default {
+    fn f()
+    where
+        Self: Default;
+}
+
+trait U: Default {
+    fn f()
+    where
+        Self: Clone;
+}
+
+trait ZZ: Default {
+    fn g();
+    fn h();
+    fn f()
+    where
+        Self: Default + Clone;
+}
+
+trait BadTrait: Default + Clone {
+    fn f()
+    where
+        Self: Default + Clone;
+    fn g()
+    where
+        Self: Default;
+    fn h()
+    where
+        Self: Copy;
+}
+
+#[derive(Default, Clone)]
+struct Life;
+
+impl T for Life {
+    // this should not warn
+    fn f() {}
+}
+
+impl U for Life {
+    // this should not warn
+    fn f() {}
+}
+
+// should not warn
+trait Iter: Iterator {
+    fn into_group_btreemap<K, V>(self) -> BTreeMap<K, Vec<V>>
+    where
+        Self: Iterator<Item = (K, V)> + Sized,
+        K: Ord + Eq,
+    {
+        unimplemented!();
+    }
+}
+
+struct Foo;
+
+trait FooIter: Iterator<Item = Foo> {
+    fn bar()
+    where
+        Self: Iterator<Item = Foo>,
+    {
+    }
+}
+
+// The below should not lint and exist to guard against false positives
+fn impl_trait(_: impl AsRef<str>, _: impl AsRef<str>) {}
+
+pub mod one {
+    #[derive(Clone, Debug)]
+    struct MultiProductIter<I>
+    where
+        I: Iterator + Clone,
+        I::Item: Clone,
+    {
+        _marker: I,
+    }
+
+    pub struct MultiProduct<I>(Vec<MultiProductIter<I>>)
+    where
+        I: Iterator + Clone,
+        I::Item: Clone;
+
+    pub fn multi_cartesian_product<H>(_: H) -> MultiProduct<<H::Item as IntoIterator>::IntoIter>
+    where
+        H: Iterator,
+        H::Item: IntoIterator,
+        <H::Item as IntoIterator>::IntoIter: Clone,
+        <H::Item as IntoIterator>::Item: Clone,
+    {
+        todo!()
+    }
+}
+
+pub mod two {
+    use std::iter::Peekable;
+
+    pub struct MergeBy<I, J, F>
+    where
+        I: Iterator,
+        J: Iterator<Item = I::Item>,
+    {
+        _i: Peekable<I>,
+        _j: Peekable<J>,
+        _f: F,
+    }
+
+    impl<I, J, F> Clone for MergeBy<I, J, F>
+    where
+        I: Iterator,
+        J: Iterator<Item = I::Item>,
+        std::iter::Peekable<I>: Clone,
+        std::iter::Peekable<J>: Clone,
+        F: Clone,
+    {
+        fn clone(&self) -> Self {
+            Self {
+                _i: self._i.clone(),
+                _j: self._j.clone(),
+                _f: self._f.clone(),
+            }
+        }
+    }
+}
+
+pub trait Trait {}
+
+pub fn f(_a: impl Trait, _b: impl Trait) {}
+
+pub trait ImplTrait<T> {}
+
+impl<A, B> ImplTrait<(A, B)> for Foo where Foo: ImplTrait<A> + ImplTrait<B> {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.stderr
new file mode 100644 (file)
index 0000000..fbd9abb
--- /dev/null
@@ -0,0 +1,71 @@
+error: this trait bound is already specified in the where clause
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:15
+   |
+LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+   |               ^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:1:9
+   |
+LL | #![deny(clippy::trait_duplication_in_bounds)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in the where clause
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:23
+   |
+LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+   |                       ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:35:15
+   |
+LL |         Self: Default;
+   |               ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:49:15
+   |
+LL |         Self: Default + Clone;
+   |               ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:15
+   |
+LL |         Self: Default + Clone;
+   |               ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:25
+   |
+LL |         Self: Default + Clone;
+   |                         ^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:58:15
+   |
+LL |         Self: Default;
+   |               ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:93:15
+   |
+LL |         Self: Iterator<Item = Foo>,
+   |               ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: aborting due to 8 previous errors
+
index ebcaa7a84cfb1e9efc1601d6ac0691c4ad89f790..5aad0b44270a3cc5b9e72a5dd1405e9d52fee5e7 100644 (file)
@@ -4,6 +4,7 @@
 use core::any::TypeId;
 use core::ffi::c_void;
 use core::mem::{size_of, transmute, MaybeUninit};
+use core::ptr::NonNull;
 
 fn value<T>() -> T {
     unimplemented!()
@@ -109,6 +110,17 @@ trait Trait {}
         let _: Ty2<u32, u32> = transmute(value::<MaybeUninit<Ty2<u32, u32>>>()); // Ok
 
         let _: Ty<&[u32]> = transmute::<&[u32], _>(value::<&Vec<u32>>()); // Ok
+
+        let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<Ty2<u32, u32>, u32>>()); // Ok
+        let _: *const Ty2C<Ty2<u32, u32>, u32> = transmute(value::<*const Ty2<u32, u32>>()); // Ok
+        let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<(), Ty2<u32, u32>>>()); // Ok
+        let _: *const Ty2C<(), Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Ok
+
+        let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>()); // Err
+        let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Err
+
+        let _: NonNull<u8> = transmute(value::<NonNull<(String, String)>>()); // Ok
+        let _: NonNull<(String, String)> = transmute(value::<NonNull<u8>>()); // Ok
     }
 }
 
index 28bfba6c7571dc249ad3c97ae5c31982a4e07f9a..e50a773290e17c60fe6a5bc839e0d009fe821650 100644 (file)
@@ -1,5 +1,5 @@
 error: transmute from `Ty2<u32, i32>` which has an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:27:33
+  --> $DIR/transmute_undefined_repr.rs:28:33
    |
 LL |         let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>()); // Lint, Ty2 is unordered
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,13 +7,13 @@ LL |         let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>()); // Lin
    = note: `-D clippy::transmute-undefined-repr` implied by `-D warnings`
 
 error: transmute into `Ty2<u32, i32>` which has an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:28:32
+  --> $DIR/transmute_undefined_repr.rs:29:32
    |
 LL |         let _: Ty2<u32, i32> = transmute(value::<Ty2C<u32, i32>>()); // Lint, Ty2 is unordered
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `Ty<Ty2<u32, i32>>` to `Ty2<u32, f32>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:33:32
+  --> $DIR/transmute_undefined_repr.rs:34:32
    |
 LL |         let _: Ty2<u32, f32> = transmute(value::<Ty<Ty2<u32, i32>>>()); // Lint, different Ty2 instances
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -21,7 +21,7 @@ LL |         let _: Ty2<u32, f32> = transmute(value::<Ty<Ty2<u32, i32>>>()); //
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `Ty2<u32, f32>` to `Ty<Ty2<u32, i32>>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:34:36
+  --> $DIR/transmute_undefined_repr.rs:35:36
    |
 LL |         let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, f32>>()); // Lint, different Ty2 instances
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL |         let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, f32>>()); //
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `Ty<&Ty2<u32, i32>>` to `&Ty2<u32, f32>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:39:33
+  --> $DIR/transmute_undefined_repr.rs:40:33
    |
 LL |         let _: &Ty2<u32, f32> = transmute(value::<Ty<&Ty2<u32, i32>>>()); // Lint, different Ty2 instances
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL |         let _: &Ty2<u32, f32> = transmute(value::<Ty<&Ty2<u32, i32>>>()); /
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `&Ty2<u32, f32>` to `Ty<&Ty2<u32, i32>>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:40:37
+  --> $DIR/transmute_undefined_repr.rs:41:37
    |
 LL |         let _: Ty<&Ty2<u32, i32>> = transmute(value::<&Ty2<u32, f32>>()); // Lint, different Ty2 instances
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL |         let _: Ty<&Ty2<u32, i32>> = transmute(value::<&Ty2<u32, f32>>()); /
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `std::boxed::Box<Ty2<u32, u32>>` to `&mut Ty2<u32, f32>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:57:45
+  --> $DIR/transmute_undefined_repr.rs:58:45
    |
 LL |         let _: &'static mut Ty2<u32, f32> = transmute(value::<Box<Ty2<u32, u32>>>()); // Lint, different Ty2 instances
    |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,15 +53,31 @@ LL |         let _: &'static mut Ty2<u32, f32> = transmute(value::<Box<Ty2<u32,
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `&mut Ty2<u32, f32>` to `std::boxed::Box<Ty2<u32, u32>>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:58:37
+  --> $DIR/transmute_undefined_repr.rs:59:37
    |
 LL |         let _: Box<Ty2<u32, u32>> = transmute(value::<&'static mut Ty2<u32, f32>>()); // Lint, different Ty2 instances
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
+error: transmute into `*const Ty2<u32, u32>` which has an undefined layout
+  --> $DIR/transmute_undefined_repr.rs:119:39
+   |
+LL |         let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>()); // Err
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the contained type `Ty2<u32, u32>` has an undefined layout
+
+error: transmute from `*const Ty2<u32, u32>` which has an undefined layout
+  --> $DIR/transmute_undefined_repr.rs:120:50
+   |
+LL |         let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Err
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the contained type `Ty2<u32, u32>` has an undefined layout
+
 error: transmute from `std::vec::Vec<Ty2<U, i32>>` to `std::vec::Vec<Ty2<T, u32>>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:138:35
+  --> $DIR/transmute_undefined_repr.rs:150:35
    |
 LL |         let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); // Err
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -69,12 +85,12 @@ LL |         let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); /
    = note: two instances of the same generic type (`Vec`) may have different layouts
 
 error: transmute from `std::vec::Vec<Ty2<T, u32>>` to `std::vec::Vec<Ty2<U, i32>>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:139:35
+  --> $DIR/transmute_undefined_repr.rs:151:35
    |
 LL |         let _: Vec<Ty2<U, i32>> = transmute(value::<Vec<Ty2<T, u32>>>()); // Err
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: two instances of the same generic type (`Vec`) may have different layouts
 
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors
 
index 328cda369e11bb89a59a5db907abb14deefbf91e..94b4723452fada45a142dcd5dc7992e028ae8b60 100644 (file)
@@ -1,4 +1,7 @@
 // run-rustfix
+// compile-flags: --test
+#![allow(dead_code)]
+
 #[warn(clippy::invisible_characters)]
 fn zero() {
     print!("Here >\u{200B}< is a ZWS, and \u{200B}another");
@@ -15,22 +18,43 @@ fn canon() {
     print!("a\u{0300}h?"); // also ok
 }
 
-#[warn(clippy::non_ascii_literal)]
-fn uni() {
-    print!("\u{dc}ben!");
-    print!("\u{DC}ben!"); // this is ok
-}
+mod non_ascii_literal {
+    #![deny(clippy::non_ascii_literal)]
+
+    fn uni() {
+        print!("\u{dc}ben!");
+        print!("\u{DC}ben!"); // this is ok
+    }
+
+    // issue 8013
+    fn single_quote() {
+        const _EMPTY_BLOCK: char = '\u{25b1}';
+        const _FULL_BLOCK: char = '\u{25b0}';
+    }
+
+    #[test]
+    pub fn issue_7739() {
+        // Ryū crate: https://github.com/dtolnay/ryu
+    }
+
+    mod issue_8263 {
+        #![deny(clippy::non_ascii_literal)]
+
+        // Re-allow for a single test
+        #[test]
+        #[allow(clippy::non_ascii_literal)]
+        fn allowed() {
+            let _ = "悲しいかな、ここに日本語を書くことはできない。";
+        }
 
-// issue 8013
-#[warn(clippy::non_ascii_literal)]
-fn single_quote() {
-    const _EMPTY_BLOCK: char = '\u{25b1}';
-    const _FULL_BLOCK: char = '\u{25b0}';
+        #[test]
+        fn denied() {
+            let _ = "\u{60b2}\u{3057}\u{3044}\u{304b}\u{306a}\u{3001}\u{3053}\u{3053}\u{306b}\u{65e5}\u{672c}\u{8a9e}\u{3092}\u{66f8}\u{304f}\u{3053}\u{3068}\u{306f}\u{3067}\u{304d}\u{306a}\u{3044}\u{3002}";
+        }
+    }
 }
 
 fn main() {
     zero();
-    uni();
     canon();
-    single_quote();
 }
index 7828d6bcbea7ad39e4a68c82ef69b9c9ede16015..6ad0b255b94856c96943f0af5d329db3f7d46f8e 100644 (file)
@@ -1,4 +1,7 @@
 // run-rustfix
+// compile-flags: --test
+#![allow(dead_code)]
+
 #[warn(clippy::invisible_characters)]
 fn zero() {
     print!("Here >​< is a ZWS, and ​another");
@@ -15,22 +18,43 @@ fn canon() {
     print!("a\u{0300}h?"); // also ok
 }
 
-#[warn(clippy::non_ascii_literal)]
-fn uni() {
-    print!("Üben!");
-    print!("\u{DC}ben!"); // this is ok
-}
+mod non_ascii_literal {
+    #![deny(clippy::non_ascii_literal)]
+
+    fn uni() {
+        print!("Üben!");
+        print!("\u{DC}ben!"); // this is ok
+    }
+
+    // issue 8013
+    fn single_quote() {
+        const _EMPTY_BLOCK: char = '▱';
+        const _FULL_BLOCK: char = '▰';
+    }
+
+    #[test]
+    pub fn issue_7739() {
+        // Ryū crate: https://github.com/dtolnay/ryu
+    }
+
+    mod issue_8263 {
+        #![deny(clippy::non_ascii_literal)]
+
+        // Re-allow for a single test
+        #[test]
+        #[allow(clippy::non_ascii_literal)]
+        fn allowed() {
+            let _ = "悲しいかな、ここに日本語を書くことはできない。";
+        }
 
-// issue 8013
-#[warn(clippy::non_ascii_literal)]
-fn single_quote() {
-    const _EMPTY_BLOCK: char = '▱';
-    const _FULL_BLOCK: char = '▰';
+        #[test]
+        fn denied() {
+            let _ = "悲しいかな、ここに日本語を書くことはできない。";
+        }
+    }
 }
 
 fn main() {
     zero();
-    uni();
     canon();
-    single_quote();
 }
index 01d3f3c0296799cc15b4cabcbc811b786e8da427..ea74a81451e3a9c3157bd99d3819c1690d602266 100644 (file)
@@ -1,5 +1,5 @@
 error: invisible character detected
-  --> $DIR/unicode.rs:4:12
+  --> $DIR/unicode.rs:7:12
    |
 LL |     print!("Here >​< is a ZWS, and ​another");
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{200B}< is a ZWS, and /u{200B}another"`
@@ -7,19 +7,19 @@ LL |     print!("Here >​< is a ZWS, and ​another");
    = note: `-D clippy::invisible-characters` implied by `-D warnings`
 
 error: invisible character detected
-  --> $DIR/unicode.rs:6:12
+  --> $DIR/unicode.rs:9:12
    |
 LL |     print!("Here >­< is a SHY, and ­another");
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{AD}< is a SHY, and /u{AD}another"`
 
 error: invisible character detected
-  --> $DIR/unicode.rs:8:12
+  --> $DIR/unicode.rs:11:12
    |
 LL |     print!("Here >⁠< is a WJ, and ⁠another");
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{2060}< is a WJ, and /u{2060}another"`
 
 error: non-NFC Unicode sequence detected
-  --> $DIR/unicode.rs:14:12
+  --> $DIR/unicode.rs:17:12
    |
 LL |     print!("̀àh?");
    |            ^^^^^ help: consider replacing the string with: `"̀àh?"`
@@ -27,24 +27,40 @@ LL |     print!("̀àh?");
    = note: `-D clippy::unicode-not-nfc` implied by `-D warnings`
 
 error: literal non-ASCII character detected
-  --> $DIR/unicode.rs:20:12
+  --> $DIR/unicode.rs:25:16
    |
-LL |     print!("Üben!");
-   |            ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"`
+LL |         print!("Üben!");
+   |                ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"`
    |
-   = note: `-D clippy::non-ascii-literal` implied by `-D warnings`
+note: the lint level is defined here
+  --> $DIR/unicode.rs:22:13
+   |
+LL |     #![deny(clippy::non_ascii_literal)]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: literal non-ASCII character detected
+  --> $DIR/unicode.rs:31:36
+   |
+LL |         const _EMPTY_BLOCK: char = '▱';
+   |                                    ^^^ help: consider replacing the string with: `'/u{25b1}'`
 
 error: literal non-ASCII character detected
-  --> $DIR/unicode.rs:27:32
+  --> $DIR/unicode.rs:32:35
    |
-LL |     const _EMPTY_BLOCK: char = '▱';
-   |                                ^^^ help: consider replacing the string with: `'/u{25b1}'`
+LL |         const _FULL_BLOCK: char = '▰';
+   |                                   ^^^ help: consider replacing the string with: `'/u{25b0}'`
 
 error: literal non-ASCII character detected
-  --> $DIR/unicode.rs:28:31
+  --> $DIR/unicode.rs:52:21
+   |
+LL |             let _ = "悲しいかな、ここに日本語を書くことはできない。";
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"/u{60b2}/u{3057}/u{3044}/u{304b}/u{306a}/u{3001}/u{3053}/u{3053}/u{306b}/u{65e5}/u{672c}/u{8a9e}/u{3092}/u{66f8}/u{304f}/u{3053}/u{3068}/u{306f}/u{3067}/u{304d}/u{306a}/u{3044}/u{3002}"`
+   |
+note: the lint level is defined here
+  --> $DIR/unicode.rs:41:17
    |
-LL |     const _FULL_BLOCK: char = '▰';
-   |                               ^^^ help: consider replacing the string with: `'/u{25b0}'`
+LL |         #![deny(clippy::non_ascii_literal)]
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
index dac5ce272c02665133022468802bbfe679768d0d..2113173170868409b861f0eaa34fc54ec27a34de 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(stmt_expr_attributes)]
-#![allow(clippy::let_unit_value)]
+#![allow(clippy::let_unit_value, invalid_value)]
 
 use std::mem::{self, MaybeUninit};
 
index b352b285c86267f42fed1f4be2ce85d51c544afd..ee9f157342d48f835a39883ffa3736e9f9a30885 100644 (file)
@@ -88,4 +88,13 @@ mod fixable {
     }
 
     type I32Alias = i32;
+
+    fn issue_9380() {
+        let _: i32 = -1_i32;
+        let _: f32 = -(1) as f32;
+        let _: i64 = -1_i64;
+        let _: i64 = -(1.0) as i64;
+
+        let _ = -(1 + 1) as i64;
+    }
 }
index 6c8cc3effe8fefcc9ca0cf5c806549bd0037b0f2..5b70412424c06f602e02d3ecf02025f5f7b59dc7 100644 (file)
@@ -88,4 +88,13 @@ fn main() {
     }
 
     type I32Alias = i32;
+
+    fn issue_9380() {
+        let _: i32 = -(1) as i32;
+        let _: f32 = -(1) as f32;
+        let _: i64 = -(1) as i64;
+        let _: i64 = -(1.0) as i64;
+
+        let _ = -(1 + 1) as i64;
+    }
 }
index bad45f0025b2292fe0360c52ec59effefac4c361..f7829ff3b0efd049d72f7619bcdeb6e7708b1d8d 100644 (file)
@@ -150,5 +150,17 @@ error: casting float literal to `f32` is unnecessary
 LL |         let _ = -1.0 as f32;
    |                 ^^^^^^^^^^^ help: try: `-1.0_f32`
 
-error: aborting due to 25 previous errors
+error: casting integer literal to `i32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:93:22
+   |
+LL |         let _: i32 = -(1) as i32;
+   |                      ^^^^^^^^^^^ help: try: `-1_i32`
+
+error: casting integer literal to `i64` is unnecessary
+  --> $DIR/unnecessary_cast.rs:95:22
+   |
+LL |         let _: i64 = -(1) as i64;
+   |                      ^^^^^^^^^^^ help: try: `-1_i64`
+
+error: aborting due to 27 previous errors
 
index f95f91329a2faeeae22da74496d42568e89512c8..40052c41039e5d01c320f34743fe48331fc9e81a 100644 (file)
@@ -12,6 +12,7 @@ fn main() {
     ref_str_argument("");
 
     // should be linted
+    #[allow(clippy::manual_string_new)]
     ref_str_argument("");
 
     // should not be linted
index 0cbdc151ed9b1b0b3a2056ed6e4e78665f175ee0..2304dff5192b9ee66c34805feab80ab2d55bd62c 100644 (file)
@@ -12,6 +12,7 @@ fn main() {
     ref_str_argument(&String::new());
 
     // should be linted
+    #[allow(clippy::manual_string_new)]
     ref_str_argument(&String::from(""));
 
     // should not be linted
index 46bc4597b335f0bfb7be4ce8053f46b3735e95b4..1eb198a8675ea1b2f172667f6f8807d2f624d0fa 100644 (file)
@@ -7,7 +7,7 @@ LL |     ref_str_argument(&String::new());
    = note: `-D clippy::unnecessary-owned-empty-strings` implied by `-D warnings`
 
 error: usage of `&String::from("")` for a function expecting a `&str` argument
-  --> $DIR/unnecessary_owned_empty_strings.rs:15:22
+  --> $DIR/unnecessary_owned_empty_strings.rs:16:22
    |
 LL |     ref_str_argument(&String::from(""));
    |                      ^^^^^^^^^^^^^^^^^ help: try: `""`
index f4f76cd3dd493e159a656fe95276b2a41002299b..9cd5bc73b1ec51852af3c2bbeae84cb5ddf05594 100644 (file)
@@ -329,3 +329,31 @@ mod issue_8759_variant {
         rw.set_view(&rw.default_view().to_owned());
     }
 }
+
+mod issue_9317 {
+    #![allow(dead_code)]
+
+    struct Bytes {}
+
+    impl ToString for Bytes {
+        fn to_string(&self) -> String {
+            "123".to_string()
+        }
+    }
+
+    impl AsRef<[u8]> for Bytes {
+        fn as_ref(&self) -> &[u8] {
+            &[1, 2, 3]
+        }
+    }
+
+    fn consume<C: AsRef<[u8]>>(c: C) {
+        let _ = c;
+    }
+
+    pub fn main() {
+        let b = Bytes {};
+        // Should not lint.
+        consume(b.to_string());
+    }
+}
index fe09a489ab0a67b81cf5280f3dc8b9c1140aa061..7f62ba3ab5d559ea0d8a60da23f977389044f054 100644 (file)
@@ -329,3 +329,31 @@ fn main() {
         rw.set_view(&rw.default_view().to_owned());
     }
 }
+
+mod issue_9317 {
+    #![allow(dead_code)]
+
+    struct Bytes {}
+
+    impl ToString for Bytes {
+        fn to_string(&self) -> String {
+            "123".to_string()
+        }
+    }
+
+    impl AsRef<[u8]> for Bytes {
+        fn as_ref(&self) -> &[u8] {
+            &[1, 2, 3]
+        }
+    }
+
+    fn consume<C: AsRef<[u8]>>(c: C) {
+        let _ = c;
+    }
+
+    pub fn main() {
+        let b = Bytes {};
+        // Should not lint.
+        consume(b.to_string());
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unused_peekable.rs b/src/tools/clippy/tests/ui/unused_peekable.rs
new file mode 100644 (file)
index 0000000..153457e
--- /dev/null
@@ -0,0 +1,144 @@
+#![warn(clippy::unused_peekable)]
+#![allow(clippy::no_effect)]
+
+use std::iter::Empty;
+use std::iter::Peekable;
+
+fn main() {
+    invalid();
+    valid();
+}
+
+#[allow(clippy::unused_unit)]
+fn invalid() {
+    let peekable = std::iter::empty::<u32>().peekable();
+
+    // Only lint `new_local`
+    let old_local = std::iter::empty::<u32>().peekable();
+    let new_local = old_local;
+
+    // Behind mut ref
+    let mut by_mut_ref_test = std::iter::empty::<u32>().peekable();
+    let by_mut_ref = &mut by_mut_ref_test;
+
+    // Explicitly returns `Peekable`
+    fn returns_peekable() -> Peekable<Empty<u32>> {
+        std::iter::empty().peekable()
+    }
+
+    let peekable_from_fn = returns_peekable();
+
+    // Using a method not exclusive to `Peekable`
+    let mut peekable_using_iterator_method = std::iter::empty::<u32>().peekable();
+    peekable_using_iterator_method.next();
+
+    // Passed by ref to another function
+    fn takes_ref(_peek: &Peekable<Empty<u32>>) {}
+    let passed_along_ref = std::iter::empty::<u32>().peekable();
+    takes_ref(&passed_along_ref);
+
+    // `by_ref` without `peek`
+    let mut by_ref_test = std::iter::empty::<u32>().peekable();
+    let _by_ref = by_ref_test.by_ref();
+
+    let mut peekable_in_for_loop = std::iter::empty::<u32>().peekable();
+    for x in peekable_in_for_loop {}
+}
+
+fn valid() {
+    fn takes_peekable(_peek: Peekable<Empty<u32>>) {}
+
+    // Passed to another function
+    let passed_along = std::iter::empty::<u32>().peekable();
+    takes_peekable(passed_along);
+
+    // Passed to another method
+    struct PeekableConsumer;
+    impl PeekableConsumer {
+        fn consume(&self, _: Peekable<Empty<u32>>) {}
+        fn consume_mut_ref(&self, _: &mut Peekable<Empty<u32>>) {}
+    }
+
+    let peekable_consumer = PeekableConsumer;
+    let mut passed_along_to_method = std::iter::empty::<u32>().peekable();
+    peekable_consumer.consume_mut_ref(&mut passed_along_to_method);
+    peekable_consumer.consume(passed_along_to_method);
+
+    // `peek` called in another block
+    let mut peekable_in_block = std::iter::empty::<u32>().peekable();
+    {
+        peekable_in_block.peek();
+    }
+
+    // Check the other `Peekable` methods :)
+    {
+        let mut peekable_with_peek_mut = std::iter::empty::<u32>().peekable();
+        peekable_with_peek_mut.peek_mut();
+
+        let mut peekable_with_next_if = std::iter::empty::<u32>().peekable();
+        peekable_with_next_if.next_if(|_| true);
+
+        let mut peekable_with_next_if_eq = std::iter::empty::<u32>().peekable();
+        peekable_with_next_if_eq.next_if_eq(&3);
+    }
+
+    let mut peekable_in_closure = std::iter::empty::<u32>().peekable();
+    let call_peek = |p: &mut Peekable<Empty<u32>>| {
+        p.peek();
+    };
+    call_peek(&mut peekable_in_closure);
+
+    // From a macro
+    macro_rules! make_me_a_peekable_please {
+        () => {
+            std::iter::empty::<u32>().peekable()
+        };
+    }
+
+    let _unsuspecting_macro_user = make_me_a_peekable_please!();
+
+    // Generic Iterator returned
+    fn return_an_iter() -> impl Iterator<Item = u32> {
+        std::iter::empty::<u32>().peekable()
+    }
+
+    let _unsuspecting_user = return_an_iter();
+
+    // Call `peek` in a macro
+    macro_rules! peek_iter {
+        ($iter:ident) => {
+            $iter.peek();
+        };
+    }
+
+    let mut peek_in_macro = std::iter::empty::<u32>().peekable();
+    peek_iter!(peek_in_macro);
+
+    // Behind mut ref
+    let mut by_mut_ref_test = std::iter::empty::<u32>().peekable();
+    let by_mut_ref = &mut by_mut_ref_test;
+    by_mut_ref.peek();
+
+    // Behind ref
+    let mut by_ref_test = std::iter::empty::<u32>().peekable();
+    let by_ref = &by_ref_test;
+    by_ref_test.peek();
+
+    // In struct
+    struct PeekableWrapper {
+        f: Peekable<Empty<u32>>,
+    }
+
+    let struct_test = std::iter::empty::<u32>().peekable();
+    PeekableWrapper { f: struct_test };
+
+    // `by_ref` before `peek`
+    let mut by_ref_test = std::iter::empty::<u32>().peekable();
+    let peeked_val = by_ref_test.by_ref().peek();
+
+    // `peek` called in another block as the last expression
+    let mut peekable_last_expr = std::iter::empty::<u32>().peekable();
+    {
+        peekable_last_expr.peek();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unused_peekable.stderr b/src/tools/clippy/tests/ui/unused_peekable.stderr
new file mode 100644 (file)
index 0000000..d557f54
--- /dev/null
@@ -0,0 +1,67 @@
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:14:9
+   |
+LL |     let peekable = std::iter::empty::<u32>().peekable();
+   |         ^^^^^^^^
+   |
+   = note: `-D clippy::unused-peekable` implied by `-D warnings`
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:18:9
+   |
+LL |     let new_local = old_local;
+   |         ^^^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:22:9
+   |
+LL |     let by_mut_ref = &mut by_mut_ref_test;
+   |         ^^^^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:29:9
+   |
+LL |     let peekable_from_fn = returns_peekable();
+   |         ^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:32:13
+   |
+LL |     let mut peekable_using_iterator_method = std::iter::empty::<u32>().peekable();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:37:9
+   |
+LL |     let passed_along_ref = std::iter::empty::<u32>().peekable();
+   |         ^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:42:9
+   |
+LL |     let _by_ref = by_ref_test.by_ref();
+   |         ^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:44:13
+   |
+LL |     let mut peekable_in_for_loop = std::iter::empty::<u32>().peekable();
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: aborting due to 8 previous errors
+
index a4a3cd1d37977d3dcb16181db4ad8c20a54ffaab..d9fd402e7cfb9d200cc79f794e9b4b41c9c94c82 100644 (file)
@@ -6,8 +6,9 @@ fn unwrap_option() {
 }
 
 fn unwrap_result() {
-    let res: Result<u8, ()> = Ok(0);
+    let res: Result<u8, u8> = Ok(0);
     let _ = res.unwrap();
+    let _ = res.unwrap_err();
 }
 
 fn main() {
index 4f0858005f6e7f140cd0c69bcea3c9111e82b673..78422757819d502d3ba231fdc6b803e2a5407205 100644 (file)
@@ -15,5 +15,13 @@ LL |     let _ = res.unwrap();
    |
    = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message
 
-error: aborting due to 2 previous errors
+error: used `unwrap_err()` on `a Result` value
+  --> $DIR/unwrap.rs:11:13
+   |
+LL |     let _ = res.unwrap_err();
+   |             ^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `Ok` case gracefully, consider using `expect_err()` to provide a better panic message
+
+error: aborting due to 3 previous errors
 
index 0d4a0504a6e04142ea69b6940c01833b7d9f7bbb..9f27fef82494b8207437530017889d3bd523455d 100644 (file)
@@ -1,10 +1,35 @@
 #![warn(clippy::unwrap_used, clippy::expect_used)]
 
+trait OptionExt {
+    type Item;
+
+    fn unwrap_err(self) -> Self::Item;
+
+    fn expect_err(self, msg: &str) -> Self::Item;
+}
+
+impl<T> OptionExt for Option<T> {
+    type Item = T;
+    fn unwrap_err(self) -> T {
+        panic!();
+    }
+
+    fn expect_err(self, msg: &str) -> T {
+        panic!();
+    }
+}
+
 fn main() {
     Some(3).unwrap();
     Some(3).expect("Hello world!");
 
+    // Don't trigger on unwrap_err on an option
+    Some(3).unwrap_err();
+    Some(3).expect_err("Hellow none!");
+
     let a: Result<i32, i32> = Ok(3);
     a.unwrap();
     a.expect("Hello world!");
+    a.unwrap_err();
+    a.expect_err("Hello error!");
 }
index f54bfd617c4ee5589b1c906e4ab066c99fb7981e..1a19459b2c174c0ca8dfaee96d6148effd554094 100644 (file)
@@ -1,5 +1,5 @@
 error: used `unwrap()` on `an Option` value
-  --> $DIR/unwrap_expect_used.rs:4:5
+  --> $DIR/unwrap_expect_used.rs:23:5
    |
 LL |     Some(3).unwrap();
    |     ^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     Some(3).unwrap();
    = help: if this value is `None`, it will panic
 
 error: used `expect()` on `an Option` value
-  --> $DIR/unwrap_expect_used.rs:5:5
+  --> $DIR/unwrap_expect_used.rs:24:5
    |
 LL |     Some(3).expect("Hello world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     Some(3).expect("Hello world!");
    = help: if this value is `None`, it will panic
 
 error: used `unwrap()` on `a Result` value
-  --> $DIR/unwrap_expect_used.rs:8:5
+  --> $DIR/unwrap_expect_used.rs:31:5
    |
 LL |     a.unwrap();
    |     ^^^^^^^^^^
@@ -25,12 +25,28 @@ LL |     a.unwrap();
    = help: if this value is an `Err`, it will panic
 
 error: used `expect()` on `a Result` value
-  --> $DIR/unwrap_expect_used.rs:9:5
+  --> $DIR/unwrap_expect_used.rs:32:5
    |
 LL |     a.expect("Hello world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: if this value is an `Err`, it will panic
 
-error: aborting due to 4 previous errors
+error: used `unwrap_err()` on `a Result` value
+  --> $DIR/unwrap_expect_used.rs:33:5
+   |
+LL |     a.unwrap_err();
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: if this value is an `Ok`, it will panic
+
+error: used `expect_err()` on `a Result` value
+  --> $DIR/unwrap_expect_used.rs:34:5
+   |
+LL |     a.expect_err("Hello error!");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this value is an `Ok`, it will panic
+
+error: aborting due to 6 previous errors
 
index 39f54c27bee1a6356e40ad4628a9b6f10e086e14..4acf5b5fa2d1ba8ab717631f61210aa301ff90c5 100644 (file)
@@ -29,10 +29,10 @@ fn main() {
     let _ = String::try_from("foo".to_string()).unwrap();
     let _ = String::try_from(format!("A: {:04}", 123)).unwrap();
     let _: String = format!("Hello {}", "world").try_into().unwrap();
-    let _: String = "".to_owned().try_into().unwrap();
+    let _: String = String::new().try_into().unwrap();
     let _: String = match String::from("_").try_into() {
         Ok(a) => a,
-        Err(_) => "".into(),
+        Err(_) => String::new(),
     };
     // FIXME this is a false negative
     #[allow(clippy::cmp_owned)]
index b691c13f7dbb747ac540e2258a071b53419a186e..12e74d614717db6ee5c6d8068f894958d53e7dad 100644 (file)
@@ -62,7 +62,7 @@ LL |     let _: String = format!("Hello {}", "world").try_into().unwrap();
 error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion_try.rs:32:21
    |
-LL |     let _: String = "".to_owned().try_into().unwrap();
+LL |     let _: String = String::new().try_into().unwrap();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider removing `.try_into()`
index 7ed27439ec6e4432372224dd696d485024918b96..a8307e741cf17b0c8ff64fd53cf2096b22c7f068 100644 (file)
@@ -1,15 +1,19 @@
 #![warn(clippy::vec_resize_to_zero)]
 
 fn main() {
+    let mut v = vec![1, 2, 3, 4, 5];
+
     // applicable here
-    vec![1, 2, 3, 4, 5].resize(0, 5);
+    v.resize(0, 5);
 
     // not applicable
-    vec![1, 2, 3, 4, 5].resize(2, 5);
+    v.resize(2, 5);
+
+    let mut v = vec!["foo", "bar", "baz"];
 
     // applicable here, but only implemented for integer literals for now
-    vec!["foo", "bar", "baz"].resize(0, "bar");
+    v.resize(0, "bar");
 
     // not applicable
-    vec!["foo", "bar", "baz"].resize(2, "bar")
+    v.resize(2, "bar")
 }
index feb846298c656878246193fd8968b2c67127b260..7428cf62d6c429554d8a54e37cc641dfb93f8536 100644 (file)
@@ -1,10 +1,10 @@
 error: emptying a vector with `resize`
-  --> $DIR/vec_resize_to_zero.rs:5:5
+  --> $DIR/vec_resize_to_zero.rs:7:5
    |
-LL |     vec![1, 2, 3, 4, 5].resize(0, 5);
-   |     ^^^^^^^^^^^^^^^^^^^^------------
-   |                         |
-   |                         help: ...or you can empty the vector with: `clear()`
+LL |     v.resize(0, 5);
+   |     ^^------------
+   |       |
+   |       help: ...or you can empty the vector with: `clear()`
    |
    = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings`
    = help: the arguments may be inverted...
index e0065e05ade62d31ba9c21f7fe8b75f2b368d973..df267e9872a0a0a6bdd6984c7aeca3e77c4e4d88 100644 (file)
@@ -18,7 +18,7 @@ fn main() -> std::io::Result<()> {
     s.read_to_end();
     s.read_to_string();
     // Should catch this
-    let mut f = File::open(&path)?;
+    let mut f = File::open(path)?;
     let mut buffer = Vec::new();
     f.read_to_end(&mut buffer)?;
     // ...and this
index e13efb3e0164b638f96b05861b818fdc70b23ed0..95325e06037829c2fb9a519f5b3a50e10ddee1e1 100644 (file)
@@ -20,8 +20,8 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
         .current_dir(&cwd)
         .env("CARGO_TARGET_DIR", &target_dir)
         .arg("clean")
-        .args(&["-p", "subcrate"])
-        .args(&["-p", "path_dep"])
+        .args(["-p", "subcrate"])
+        .args(["-p", "path_dep"])
         .output()
         .unwrap();
 
@@ -32,11 +32,11 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
         .env("CARGO_INCREMENTAL", "0")
         .env("CARGO_TARGET_DIR", &target_dir)
         .arg("clippy")
-        .args(&["-p", "subcrate"])
+        .args(["-p", "subcrate"])
         .arg("--no-deps")
         .arg("--")
         .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
-        .args(&["--cfg", r#"feature="primary_package_test""#])
+        .args(["--cfg", r#"feature="primary_package_test""#])
         .output()
         .unwrap();
     println!("status: {}", output.status);
@@ -52,10 +52,10 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
             .env("CARGO_INCREMENTAL", "0")
             .env("CARGO_TARGET_DIR", &target_dir)
             .arg("clippy")
-            .args(&["-p", "subcrate"])
+            .args(["-p", "subcrate"])
             .arg("--")
             .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
-            .args(&["--cfg", r#"feature="primary_package_test""#])
+            .args(["--cfg", r#"feature="primary_package_test""#])
             .output()
             .unwrap();
         println!("status: {}", output.status);
@@ -79,7 +79,7 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
             .env("CARGO_INCREMENTAL", "0")
             .env("CARGO_TARGET_DIR", &target_dir)
             .arg("clippy")
-            .args(&["-p", "subcrate"])
+            .args(["-p", "subcrate"])
             .arg("--")
             .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
             .output()
index b9fd852f742cf81360c0cb167683acde754b63eb..f4dac6e947e323e37c7c1996fb982061159d7c39 100644 (file)
@@ -4,7 +4,7 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
-rustdoc = { path = "../../librustdoc" }
+mdbook = { version = "0.4", default-features = false, features = ["search"] }
 
 [[bin]]
 name = "error_index_generator"
diff --git a/src/tools/error_index_generator/book_config.toml b/src/tools/error_index_generator/book_config.toml
new file mode 100644 (file)
index 0000000..885100a
--- /dev/null
@@ -0,0 +1,19 @@
+[book]
+title = "Error codes index"
+description = "Book listing all Rust error codes"
+src = ""
+
+[output.html]
+git-repository-url = "https://github.com/rust-lang/rust/"
+additional-css = ["error-index.css"]
+additional-js = ["error-index.js"]
+
+[output.html.search]
+enable = true
+limit-results = 20
+use-boolean-and = true
+boost-title = 2
+boost-hierarchy = 2
+boost-paragraph = 1
+expand = true
+heading-split-level = 0
diff --git a/src/tools/error_index_generator/error-index.css b/src/tools/error_index_generator/error-index.css
new file mode 100644 (file)
index 0000000..8975af8
--- /dev/null
@@ -0,0 +1,38 @@
+code.compile_fail {
+       border-left: 2px solid red;
+}
+
+pre .tooltip {
+       position: absolute;
+       left: -25px;
+       top: 0;
+       z-index: 1;
+       color: red;
+       cursor: pointer;
+}
+pre .tooltip::after {
+       display: none;
+       content: "This example deliberately fails to compile";
+       background-color: #000;
+       color: #fff;
+       border-color: #000;
+       text-align: center;
+       padding: 5px 3px 3px 3px;
+       border-radius: 6px;
+       margin-left: 5px;
+}
+pre .tooltip::before {
+       display: none;
+       border-color: transparent black transparent transparent;
+       content: " ";
+       position: absolute;
+       top: 50%;
+       left: 16px;
+       margin-top: -5px;
+       border-width: 5px;
+       border-style: solid;
+}
+
+pre .tooltip:hover::before, pre .tooltip:hover::after {
+       display: inline;
+}
diff --git a/src/tools/error_index_generator/error-index.js b/src/tools/error_index_generator/error-index.js
new file mode 100644 (file)
index 0000000..39b371b
--- /dev/null
@@ -0,0 +1,9 @@
+for (const elem of document.querySelectorAll("pre.playground")) {
+    if (elem.querySelector(".compile_fail") === null) {
+        continue;
+    }
+    const child = document.createElement("div");
+    child.className = "tooltip";
+    child.textContent = "ⓘ";
+    elem.appendChild(child);
+}
index 68c46700361a8da36dd766f53a69e5720760b6b9..1bde8e007826dffca053aa69474ecba3530ea68a 100644 (file)
@@ -1,20 +1,21 @@
 #![feature(rustc_private)]
 
 extern crate rustc_driver;
-extern crate rustc_span;
 
+// We use the function we generate from `register_diagnostics!`.
 use crate::error_codes::error_codes;
 
 use std::env;
 use std::error::Error;
-use std::fs::{create_dir_all, File};
+use std::fs::{self, File};
 use std::io::Write;
 use std::path::Path;
 use std::path::PathBuf;
 
-use rustc_span::edition::DEFAULT_EDITION;
+use std::str::FromStr;
 
-use rustdoc::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
+use mdbook::book::{parse_summary, BookItem, Chapter};
+use mdbook::{Config, MDBook};
 
 macro_rules! register_diagnostics {
     ($($error_code:ident: $message:expr,)+ ; $($undocumented:ident,)* ) => {
@@ -33,104 +34,21 @@ pub fn error_codes() -> Vec<(&'static str, Option<&'static str>)> {
 mod error_codes;
 
 enum OutputFormat {
-    HTML(HTMLFormatter),
+    HTML,
     Markdown,
     Unknown(String),
 }
 
 impl OutputFormat {
-    fn from(format: &str, resource_suffix: &str) -> OutputFormat {
+    fn from(format: &str) -> OutputFormat {
         match &*format.to_lowercase() {
-            "html" => OutputFormat::HTML(HTMLFormatter(resource_suffix.to_owned())),
+            "html" => OutputFormat::HTML,
             "markdown" => OutputFormat::Markdown,
             s => OutputFormat::Unknown(s.to_owned()),
         }
     }
 }
 
-struct HTMLFormatter(String);
-
-impl HTMLFormatter {
-    fn create_error_code_file(
-        &self,
-        err_code: &str,
-        explanation: &str,
-        parent_dir: &Path,
-    ) -> Result<(), Box<dyn Error>> {
-        let mut output_file = File::create(parent_dir.join(err_code).with_extension("html"))?;
-
-        self.header(&mut output_file, "../", "")?;
-        self.title(&mut output_file, &format!("Error code {}", err_code))?;
-
-        let mut id_map = IdMap::new();
-        let playground =
-            Playground { crate_name: None, url: String::from("https://play.rust-lang.org/") };
-        write!(
-            output_file,
-            "{}",
-            Markdown {
-                content: explanation,
-                links: &[],
-                ids: &mut id_map,
-                error_codes: ErrorCodes::Yes,
-                edition: DEFAULT_EDITION,
-                playground: &Some(playground),
-                heading_offset: HeadingOffset::H1,
-            }
-            .into_string()
-        )?;
-        write!(
-            output_file,
-            "<p>\
-                <a style='text-align: center;display: block;width: 100%;' \
-                   href='../error-index.html'>Back to list of error codes</a>\
-             </p>",
-        )?;
-
-        self.footer(&mut output_file)
-    }
-
-    fn header(
-        &self,
-        output: &mut dyn Write,
-        extra_path: &str,
-        extra: &str,
-    ) -> Result<(), Box<dyn Error>> {
-        write!(
-            output,
-            r##"<!DOCTYPE html>
-<html>
-<head>
-<title>Rust Compiler Error Index</title>
-<meta charset="utf-8">
-<!-- Include rust.css after light.css so its rules take priority. -->
-<link rel="stylesheet" type="text/css" href="{extra_path}rustdoc{suffix}.css"/>
-<link rel="stylesheet" type="text/css" href="{extra_path}light{suffix}.css"/>
-<link rel="stylesheet" type="text/css" href="{extra_path}rust.css"/>
-<style>
-.error-undescribed {{
-    display: none;
-}}
-</style>{extra}
-</head>
-<body>
-"##,
-            suffix = self.0,
-        )?;
-        Ok(())
-    }
-
-    fn title(&self, output: &mut dyn Write, title: &str) -> Result<(), Box<dyn Error>> {
-        write!(output, "<h1>{}</h1>\n", title)?;
-        Ok(())
-    }
-
-    fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>> {
-        write!(output, "</body></html>")?;
-        Ok(())
-    }
-}
-
 /// Output an HTML page for the errors in `err_map` to `output_path`.
 fn render_markdown(output_path: &Path) -> Result<(), Box<dyn Error>> {
     let mut output_file = File::create(output_path)?;
@@ -147,61 +65,119 @@ fn render_markdown(output_path: &Path) -> Result<(), Box<dyn Error>> {
     Ok(())
 }
 
-fn render_html(output_path: &Path, formatter: HTMLFormatter) -> Result<(), Box<dyn Error>> {
-    let mut output_file = File::create(output_path)?;
+// By default, mdbook doesn't consider code blocks as Rust ones contrary to rustdoc so we have
+// to manually add `rust` attribute whenever needed.
+fn add_rust_attribute_on_codeblock(explanation: &str) -> String {
+    // Very hacky way to add the rust attribute on all code blocks.
+    let mut skip = true;
+    explanation.split("\n```").fold(String::new(), |mut acc, part| {
+        if !acc.is_empty() {
+            acc.push_str("\n```");
+        }
+        if !skip {
+            if let Some(attrs) = part.split('\n').next() {
+                if !attrs.contains("rust")
+                    && (attrs.is_empty()
+                        || attrs.contains("compile_fail")
+                        || attrs.contains("ignore")
+                        || attrs.contains("edition"))
+                {
+                    if !attrs.is_empty() {
+                        acc.push_str("rust,");
+                    } else {
+                        acc.push_str("rust");
+                    }
+                }
+            }
+        }
+        skip = !skip;
+        acc.push_str(part);
+        acc
+    })
+}
 
-    let error_codes_dir = "error_codes";
+fn render_html(output_path: &Path) -> Result<(), Box<dyn Error>> {
+    let mut introduction = format!(
+        "<script src='redirect.js'></script>
+# Rust error codes index
 
-    let parent = output_path.parent().expect("There should have a parent").join(error_codes_dir);
+This page lists all the error codes emitted by the Rust compiler.
 
-    if !parent.exists() {
-        create_dir_all(&parent)?;
-    }
+"
+    );
 
-    formatter.header(
-        &mut output_file,
-        "",
-        &format!(
-            r#"<script>(function() {{
-    if (window.location.hash) {{
-        let code = window.location.hash.replace(/^#/, '');
-        // We have to make sure this pattern matches to avoid inadvertently creating an
-        // open redirect.
-        if (/^E[0-9]+$/.test(code)) {{
-            window.location = './{error_codes_dir}/' + code + '.html';
-        }}
-    }}
-}})()</script>"#
-        ),
-    )?;
-    formatter.title(&mut output_file, "Rust Compiler Error Index")?;
+    let err_codes = error_codes();
+    let mut chapters = Vec::with_capacity(err_codes.len());
 
-    write!(
-        output_file,
-        "<p>This page lists all the error codes emitted by the Rust compiler. If you want a full \
-            explanation on an error code, click on it.</p>\
-         <ul>",
-    )?;
-    for (err_code, explanation) in error_codes().iter() {
+    for (err_code, explanation) in err_codes.iter() {
         if let Some(explanation) = explanation {
-            write!(
-                output_file,
-                "<li><a href='./{0}/{1}.html'>{1}</a></li>",
-                error_codes_dir, err_code
-            )?;
-            formatter.create_error_code_file(err_code, explanation, &parent)?;
+            introduction.push_str(&format!(" * [{0}](./{0}.html)\n", err_code));
+
+            let content = add_rust_attribute_on_codeblock(explanation);
+            chapters.push(BookItem::Chapter(Chapter {
+                name: err_code.to_string(),
+                content: format!("# Error code {}\n\n{}\n", err_code, content),
+                number: None,
+                sub_items: Vec::new(),
+                // We generate it into the `error_codes` folder.
+                path: Some(PathBuf::from(&format!("{}.html", err_code))),
+                source_path: None,
+                parent_names: Vec::new(),
+            }));
         } else {
-            write!(output_file, "<li>{}</li>", err_code)?;
+            introduction.push_str(&format!(" * {}\n", err_code));
         }
     }
-    write!(output_file, "</ul>")?;
-    formatter.footer(&mut output_file)
+
+    let mut config = Config::from_str(include_str!("book_config.toml"))?;
+    config.build.build_dir = output_path.join("error_codes").to_path_buf();
+    let mut book = MDBook::load_with_config_and_summary(
+        env!("CARGO_MANIFEST_DIR"),
+        config,
+        parse_summary("")?,
+    )?;
+    let chapter = Chapter {
+        name: "Rust error codes index".to_owned(),
+        content: introduction,
+        number: None,
+        sub_items: chapters,
+        // Very important: this file is named as `error-index.html` and not `index.html`!
+        path: Some(PathBuf::from("error-index.html")),
+        source_path: None,
+        parent_names: Vec::new(),
+    };
+    book.book.sections.push(BookItem::Chapter(chapter));
+    book.build()?;
+
+    // We can't put this content into another file, otherwise `mbdbook` will also put it into the
+    // output directory, making a duplicate.
+    fs::write(
+        output_path.join("error-index.html"),
+        r#"<!DOCTYPE html>
+<html>
+    <head>
+        <title>Rust error codes index - Error codes index</title>
+        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+        <meta name="description" content="Book listing all Rust error codes">
+        <script src="error_codes/redirect.js"></script>
+    </head>
+    <body>
+        <div>If you are not automatically redirected to the error code index, please <a id="index-link" href="./error_codes/error-index.html">here</a>.
+        <script>document.getElementById("index-link").click()</script>
+    </body>
+</html>"#,
+    )?;
+
+    // No need for a 404 file, it's already handled by the server.
+    fs::remove_file(output_path.join("error_codes/404.html"))?;
+
+    Ok(())
 }
 
 fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<dyn Error>> {
     match format {
         OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
-        OutputFormat::HTML(h) => render_html(dst, h),
+        OutputFormat::HTML => render_html(dst),
         OutputFormat::Markdown => render_markdown(dst),
     }
 }
@@ -210,12 +186,9 @@ fn parse_args() -> (OutputFormat, PathBuf) {
     let mut args = env::args().skip(1);
     let format = args.next();
     let dst = args.next();
-    let resource_suffix = args.next().unwrap_or_else(String::new);
-    let format = format
-        .map(|a| OutputFormat::from(&a, &resource_suffix))
-        .unwrap_or(OutputFormat::from("html", &resource_suffix));
+    let format = format.map(|a| OutputFormat::from(&a)).unwrap_or(OutputFormat::from("html"));
     let dst = dst.map(PathBuf::from).unwrap_or_else(|| match format {
-        OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"),
+        OutputFormat::HTML => PathBuf::from("doc"),
         OutputFormat::Markdown => PathBuf::from("doc/error-index.md"),
         OutputFormat::Unknown(..) => PathBuf::from("<nul>"),
     });
@@ -225,9 +198,8 @@ fn parse_args() -> (OutputFormat, PathBuf) {
 fn main() {
     rustc_driver::init_env_logger("RUST_LOG");
     let (format, dst) = parse_args();
-    let result =
-        rustc_span::create_default_session_globals_then(move || main_with_result(format, &dst));
+    let result = main_with_result(format, &dst);
     if let Err(e) = result {
-        panic!("{}", e.to_string());
+        panic!("{:?}", e);
     }
 }
diff --git a/src/tools/error_index_generator/redirect.js b/src/tools/error_index_generator/redirect.js
new file mode 100644 (file)
index 0000000..8c907f5
--- /dev/null
@@ -0,0 +1,16 @@
+(function() {
+    if (window.location.hash) {
+        let code = window.location.hash.replace(/^#/, '');
+        // We have to make sure this pattern matches to avoid inadvertently creating an
+        // open redirect.
+        if (!/^E[0-9]+$/.test(code)) {
+            return;
+        }
+        if (window.location.pathname.indexOf("/error_codes/") !== -1) {
+            // We're not at the top level, so we don't prepend with "./error_codes/".
+            window.location = './' + code + '.html';
+        } else {
+            window.location = './error_codes/' + code + '.html';
+        }
+    }
+})()
index 9696e35b7963f8a42f880c78f11ecb015a168e76..2a923a61b0a70b74a78127746059ff568d470386 100644 (file)
@@ -8,6 +8,7 @@
 /// Descriptions of rustc lint groups.
 static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
     ("unused", "Lints that detect things being declared but not used, or excess syntax"),
+    ("let-underscore", "Lints that detect wildcard let bindings that are likely to be invalid"),
     ("rustdoc", "Rustdoc-specific lints"),
     ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"),
     ("nonstandard-style", "Violation of standard naming conventions"),
index 90bd24a75e0649d82863c41536a532267e96bac0..1795f3d7fe5bc5a3a0a9b908f333681274971dbb 100644 (file)
@@ -8,8 +8,8 @@
 //! make gcc/clang pass `-flavor <flavor>` as the first two arguments in the linker invocation
 //! and since Windows does not support symbolic links for files this wrapper is used in place of a
 //! symbolic link. It execs `../rust-lld -flavor <flavor>` by propagating the flavor argument
-//! passed to the wrapper as the first two arguments. On Windows it spawns a `..\rust-lld.exe`
-//! child process.
+//! obtained from the wrapper's name as the first two arguments.
+//! On Windows it spawns a `..\rust-lld.exe` child process.
 
 use std::fmt::Display;
 use std::path::{Path, PathBuf};
@@ -53,29 +53,32 @@ fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf {
     rust_lld_path
 }
 
+/// 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()) {
+        Some("ld.lld") => "gnu",
+        Some("ld64.lld") => "darwin",
+        Some("lld-link") => "link",
+        Some("wasm-ld") => "wasm",
+        _ => return Err(format!("{:?}", stem)),
+    })
+}
+
 /// Returns the command for invoking rust-lld with the correct flavor.
-/// LLD only accepts the flavor argument at the first two arguments, so move it there.
+/// LLD only accepts the flavor argument at the first two arguments, so pass it there.
 ///
 /// Exits on error.
 fn get_rust_lld_command(current_exe_path: &Path) -> process::Command {
     let rust_lld_path = get_rust_lld_path(current_exe_path);
     let mut command = process::Command::new(rust_lld_path);
 
-    let mut flavor = None;
-    let args = env::args_os()
-        .skip(1)
-        .filter(|arg| match arg.to_str().and_then(|s| s.strip_prefix("-rustc-lld-flavor=")) {
-            Some(suffix) => {
-                flavor = Some(suffix.to_string());
-                false
-            }
-            None => true,
-        })
-        .collect::<Vec<_>>();
+    let flavor =
+        get_lld_flavor(current_exe_path).unwrap_or_exit_with("executable has unexpected name");
 
     command.arg("-flavor");
-    command.arg(flavor.unwrap_or_exit_with("-rustc-lld-flavor=<flavor> is not passed"));
-    command.args(args);
+    command.arg(flavor);
+    command.args(env::args_os().skip(1));
     command
 }
 
index ab88e64b152d3704c35db96dbbc6efaaed67773f..dba35d2be72f4b78343d1a0f0b4737306f310672 160000 (submodule)
@@ -1 +1 @@
-Subproject commit ab88e64b152d3704c35db96dbbc6efaaed67773f
+Subproject commit dba35d2be72f4b78343d1a0f0b4737306f310672
index 146e53f2e9a0f16a1bf1e07bfa3fd3e2fb6e23ce..33b35d05415763f06d8af2d9f484e7536cd64d9c 100644 (file)
@@ -14,7 +14,7 @@ fn main() {
             walk::filter_dirs(path)
                 // We exempt these as they require the placeholder
                 // for their operation
-                || path.ends_with("compiler/rustc_passes/src/lib_features.rs")
+                || path.ends_with("compiler/rustc_attr/src/builtin.rs")
                 || path.ends_with("src/tools/tidy/src/features/version.rs")
                 || path.ends_with("src/tools/replace-version-placeholder")
         },
index 8a61ea1c9241422451a8a3ea1a0b1145159c50c4..9f10d92c4e3ab0dc90c60ff09287ade92fbdff6d 100644 (file)
@@ -247,20 +247,6 @@ dependencies = [
  "cfg-if",
 ]
 
-[[package]]
-name = "crossbeam"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c"
-dependencies = [
- "cfg-if",
- "crossbeam-channel",
- "crossbeam-deque",
- "crossbeam-epoch",
- "crossbeam-queue",
- "crossbeam-utils",
-]
-
 [[package]]
 name = "crossbeam-channel"
 version = "0.5.6"
@@ -296,16 +282,6 @@ dependencies = [
  "scopeguard",
 ]
 
-[[package]]
-name = "crossbeam-queue"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7"
-dependencies = [
- "cfg-if",
- "crossbeam-utils",
-]
-
 [[package]]
 name = "crossbeam-utils"
 version = "0.8.11"
@@ -728,6 +704,7 @@ dependencies = [
  "ide-db",
  "itertools",
  "parser",
+ "stdx",
  "syntax",
  "test-utils",
  "text-edit",
@@ -895,9 +872,9 @@ dependencies = [
 
 [[package]]
 name = "lsp-types"
-version = "0.93.0"
+version = "0.93.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70c74e2173b2b31f8655d33724b4b45ac13f439386f66290f539c22b144c2212"
+checksum = "a3bcfee315dde785ba887edb540b08765fd7df75a7d948844be6bf5712246734"
 dependencies = [
  "bitflags",
  "serde",
@@ -1178,7 +1155,6 @@ dependencies = [
 name = "proc-macro-srv"
 version = "0.0.0"
 dependencies = [
- "crossbeam",
  "expect-test",
  "libloading",
  "mbe",
@@ -1254,6 +1230,26 @@ dependencies = [
  "tracing",
 ]
 
+[[package]]
+name = "protobuf"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ee4a7d8b91800c8f167a6268d1a1026607368e1adc84e98fe044aeb905302f7"
+dependencies = [
+ "once_cell",
+ "protobuf-support",
+ "thiserror",
+]
+
+[[package]]
+name = "protobuf-support"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ca157fe12fc7ee2e315f2f735e27df41b3d97cdd70ea112824dac1ffb08ee1c"
+dependencies = [
+ "thiserror",
+]
+
 [[package]]
 name = "pulldown-cmark"
 version = "0.9.2"
@@ -1385,6 +1381,7 @@ dependencies = [
  "project-model",
  "rayon",
  "rustc-hash",
+ "scip",
  "serde",
  "serde_json",
  "sourcegen",
@@ -1471,6 +1468,15 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "scip"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2bfbb10286f69fad7c78db71004b7839bf957788359fe0c479f029f9849136b"
+dependencies = [
+ "protobuf",
+]
+
 [[package]]
 name = "scoped-tls"
 version = "1.0.0"
@@ -1656,6 +1662,26 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a"
 
+[[package]]
+name = "thiserror"
+version = "1.0.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "thread_local"
 version = "1.1.4"
@@ -1896,6 +1922,7 @@ dependencies = [
  "indexmap",
  "paths",
  "rustc-hash",
+ "stdx",
 ]
 
 [[package]]
index 9580ce8007c76a2224f5f2ba90a2acfbc6680d11..b388e47dee6e4ecd4411158467ca7e39a4da34f5 100644 (file)
@@ -9,10 +9,11 @@
 use std::{fmt, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc};
 
 use cfg::CfgOptions;
-use rustc_hash::{FxHashMap, FxHashSet};
+use rustc_hash::FxHashMap;
+use stdx::hash::{NoHashHashMap, NoHashHashSet};
 use syntax::SmolStr;
 use tt::Subtree;
-use vfs::{file_set::FileSet, FileId, VfsPath};
+use vfs::{file_set::FileSet, AnchoredPath, FileId, VfsPath};
 
 /// Files are grouped into source roots. A source root is a directory on the
 /// file systems which is watched for changes. Typically it corresponds to a
@@ -31,22 +32,30 @@ pub struct SourceRoot {
     /// Libraries are considered mostly immutable, this assumption is used to
     /// optimize salsa's query structure
     pub is_library: bool,
-    pub(crate) file_set: FileSet,
+    file_set: FileSet,
 }
 
 impl SourceRoot {
     pub fn new_local(file_set: FileSet) -> SourceRoot {
         SourceRoot { is_library: false, file_set }
     }
+
     pub fn new_library(file_set: FileSet) -> SourceRoot {
         SourceRoot { is_library: true, file_set }
     }
+
     pub fn path_for_file(&self, file: &FileId) -> Option<&VfsPath> {
         self.file_set.path_for_file(file)
     }
+
     pub fn file_for_path(&self, path: &VfsPath) -> Option<&FileId> {
         self.file_set.file_for_path(path)
     }
+
+    pub fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
+        self.file_set.resolve_path(path)
+    }
+
     pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ {
         self.file_set.iter()
     }
@@ -72,12 +81,19 @@ pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ {
 /// <https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/architecture.md#serialization>
 #[derive(Debug, Clone, Default /* Serialize, Deserialize */)]
 pub struct CrateGraph {
-    arena: FxHashMap<CrateId, CrateData>,
+    arena: NoHashHashMap<CrateId, CrateData>,
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 pub struct CrateId(pub u32);
 
+impl stdx::hash::NoHashHashable for CrateId {}
+impl std::hash::Hash for CrateId {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+    }
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct CrateName(SmolStr);
 
@@ -342,7 +358,7 @@ pub fn add_dep(
         // Check if adding a dep from `from` to `to` creates a cycle. To figure
         // that out, look for a  path in the *opposite* direction, from `to` to
         // `from`.
-        if let Some(path) = self.find_path(&mut FxHashSet::default(), dep.crate_id, from) {
+        if let Some(path) = self.find_path(&mut NoHashHashSet::default(), dep.crate_id, from) {
             let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect();
             let err = CyclicDependenciesError { path };
             assert!(err.from().0 == from && err.to().0 == dep.crate_id);
@@ -365,7 +381,7 @@ pub fn iter(&self) -> impl Iterator<Item = CrateId> + '_ {
     /// including the crate itself.
     pub fn transitive_deps(&self, of: CrateId) -> impl Iterator<Item = CrateId> {
         let mut worklist = vec![of];
-        let mut deps = FxHashSet::default();
+        let mut deps = NoHashHashSet::default();
 
         while let Some(krate) = worklist.pop() {
             if !deps.insert(krate) {
@@ -382,10 +398,10 @@ pub fn transitive_deps(&self, of: CrateId) -> impl Iterator<Item = CrateId> {
     /// including the crate itself.
     pub fn transitive_rev_deps(&self, of: CrateId) -> impl Iterator<Item = CrateId> {
         let mut worklist = vec![of];
-        let mut rev_deps = FxHashSet::default();
+        let mut rev_deps = NoHashHashSet::default();
         rev_deps.insert(of);
 
-        let mut inverted_graph = FxHashMap::<_, Vec<_>>::default();
+        let mut inverted_graph = NoHashHashMap::<_, Vec<_>>::default();
         self.arena.iter().for_each(|(&krate, data)| {
             data.dependencies
                 .iter()
@@ -409,7 +425,7 @@ pub fn transitive_rev_deps(&self, of: CrateId) -> impl Iterator<Item = CrateId>
     /// come before the crate itself).
     pub fn crates_in_topological_order(&self) -> Vec<CrateId> {
         let mut res = Vec::new();
-        let mut visited = FxHashSet::default();
+        let mut visited = NoHashHashSet::default();
 
         for krate in self.arena.keys().copied() {
             go(self, &mut visited, &mut res, krate);
@@ -419,7 +435,7 @@ pub fn crates_in_topological_order(&self) -> Vec<CrateId> {
 
         fn go(
             graph: &CrateGraph,
-            visited: &mut FxHashSet<CrateId>,
+            visited: &mut NoHashHashSet<CrateId>,
             res: &mut Vec<CrateId>,
             source: CrateId,
         ) {
@@ -459,7 +475,7 @@ pub fn extend(&mut self, other: CrateGraph) -> u32 {
 
     fn find_path(
         &self,
-        visited: &mut FxHashSet<CrateId>,
+        visited: &mut NoHashHashSet<CrateId>,
         from: CrateId,
         to: CrateId,
     ) -> Option<Vec<CrateId>> {
index 2d0a95b09d9a1a5b7d0bcb5116ad0572f4a1930f..da11e4ae7bb96f36b2532b79423407e93786cfcf 100644 (file)
@@ -8,7 +8,7 @@
 
 use std::{panic, sync::Arc};
 
-use rustc_hash::FxHashSet;
+use stdx::hash::NoHashHashSet;
 use syntax::{ast, Parse, SourceFile, TextRange, TextSize};
 
 pub use crate::{
@@ -58,7 +58,7 @@ pub trait FileLoader {
     /// Text of the file.
     fn file_text(&self, file_id: FileId) -> Arc<String>;
     fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId>;
-    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>;
+    fn relevant_crates(&self, file_id: FileId) -> Arc<NoHashHashSet<CrateId>>;
 }
 
 /// Database which stores all significant input facts: source code and project
@@ -94,10 +94,10 @@ pub trait SourceDatabaseExt: SourceDatabase {
     #[salsa::input]
     fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
 
-    fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>;
+    fn source_root_crates(&self, id: SourceRootId) -> Arc<NoHashHashSet<CrateId>>;
 }
 
-fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<FxHashSet<CrateId>> {
+fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<NoHashHashSet<CrateId>> {
     let graph = db.crate_graph();
     let res = graph
         .iter()
@@ -120,10 +120,10 @@ fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
         // FIXME: this *somehow* should be platform agnostic...
         let source_root = self.0.file_source_root(path.anchor);
         let source_root = self.0.source_root(source_root);
-        source_root.file_set.resolve_path(path)
+        source_root.resolve_path(path)
     }
 
-    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
+    fn relevant_crates(&self, file_id: FileId) -> Arc<NoHashHashSet<CrateId>> {
         let _p = profile::span("relevant_crates");
         let source_root = self.0.file_source_root(file_id);
         self.0.source_root_crates(source_root)
index c22945c81fcb93b1971721c6d5f6446cf950142c..d9f4ef5b7ff578deceae41a0a1866b15d7dd9753 100644 (file)
@@ -125,6 +125,7 @@ pub enum Progress {
     DidCheckCrate(String),
     DidFinish(io::Result<()>),
     DidCancel,
+    DidFailToRestart(String),
 }
 
 enum Restart {
@@ -193,10 +194,11 @@ fn run(mut self, inbox: Receiver<Restart>) {
                             self.progress(Progress::DidStart);
                         }
                         Err(error) => {
-                            tracing::error!(
-                                command = ?self.check_command(),
-                                %error, "failed to restart flycheck"
-                            );
+                            self.progress(Progress::DidFailToRestart(format!(
+                                "Failed to run the following command: {:?} error={}",
+                                self.check_command(),
+                                error
+                            )));
                         }
                     }
                 }
index 35c8708955a77757b56635b9c28845e1c3916514..631ae3cf11fa7e0fc9ddc2d57843ac383d1d6e65 100644 (file)
@@ -2,7 +2,7 @@
 
 use std::sync::Arc;
 
-use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, MacroCallId, MacroDefKind};
+use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroDefKind};
 use smallvec::SmallVec;
 use syntax::ast;
 
     db::DefDatabase,
     intern::Interned,
     item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId},
-    nameres::{attr_resolution::ResolvedAttr, proc_macro::ProcMacroKind, DefMap},
+    nameres::{
+        attr_resolution::ResolvedAttr, diagnostics::DefDiagnostic, proc_macro::ProcMacroKind,
+        DefMap,
+    },
     type_ref::{TraitRef, TypeBound, TypeRef},
     visibility::RawVisibility,
     AssocItemId, AstIdWithPath, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
@@ -210,6 +213,13 @@ pub struct TraitData {
 
 impl TraitData {
     pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
+        db.trait_data_with_diagnostics(tr).0
+    }
+
+    pub(crate) fn trait_data_with_diagnostics_query(
+        db: &dyn DefDatabase,
+        tr: TraitId,
+    ) -> (Arc<TraitData>, Arc<Vec<DefDiagnostic>>) {
         let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
         let item_tree = tree_id.item_tree(db);
         let tr_def = &item_tree[tree_id.value];
@@ -229,17 +239,20 @@ pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitDa
         let mut collector =
             AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr));
         collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items);
-        let (items, attribute_calls) = collector.finish();
-
-        Arc::new(TraitData {
-            name,
-            attribute_calls,
-            items,
-            is_auto,
-            is_unsafe,
-            visibility,
-            skip_array_during_method_dispatch,
-        })
+        let (items, attribute_calls, diagnostics) = collector.finish();
+
+        (
+            Arc::new(TraitData {
+                name,
+                attribute_calls,
+                items,
+                is_auto,
+                is_unsafe,
+                visibility,
+                skip_array_during_method_dispatch,
+            }),
+            Arc::new(diagnostics),
+        )
     }
 
     pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
@@ -280,7 +293,14 @@ pub struct ImplData {
 
 impl ImplData {
     pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> {
-        let _p = profile::span("impl_data_query");
+        db.impl_data_with_diagnostics(id).0
+    }
+
+    pub(crate) fn impl_data_with_diagnostics_query(
+        db: &dyn DefDatabase,
+        id: ImplId,
+    ) -> (Arc<ImplData>, Arc<Vec<DefDiagnostic>>) {
+        let _p = profile::span("impl_data_with_diagnostics_query");
         let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
 
         let item_tree = tree_id.item_tree(db);
@@ -293,10 +313,13 @@ pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData>
             AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::ImplId(id));
         collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items);
 
-        let (items, attribute_calls) = collector.finish();
+        let (items, attribute_calls, diagnostics) = collector.finish();
         let items = items.into_iter().map(|(_, item)| item).collect();
 
-        Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls })
+        (
+            Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls }),
+            Arc::new(diagnostics),
+        )
     }
 
     pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
@@ -437,6 +460,7 @@ struct AssocItemCollector<'a> {
     db: &'a dyn DefDatabase,
     module_id: ModuleId,
     def_map: Arc<DefMap>,
+    inactive_diagnostics: Vec<DefDiagnostic>,
     container: ItemContainerId,
     expander: Expander,
 
@@ -459,15 +483,21 @@ fn new(
             expander: Expander::new(db, file_id, module_id),
             items: Vec::new(),
             attr_calls: Vec::new(),
+            inactive_diagnostics: Vec::new(),
         }
     }
 
     fn finish(
         self,
-    ) -> (Vec<(Name, AssocItemId)>, Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>) {
+    ) -> (
+        Vec<(Name, AssocItemId)>,
+        Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
+        Vec<DefDiagnostic>,
+    ) {
         (
             self.items,
             if self.attr_calls.is_empty() { None } else { Some(Box::new(self.attr_calls)) },
+            self.inactive_diagnostics,
         )
     }
 
@@ -479,6 +509,12 @@ fn collect(&mut self, item_tree: &ItemTree, tree_id: TreeId, assoc_items: &[Asso
         'items: for &item in assoc_items {
             let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into());
             if !attrs.is_cfg_enabled(self.expander.cfg_options()) {
+                self.inactive_diagnostics.push(DefDiagnostic::unconfigured_code(
+                    self.module_id.local_id,
+                    InFile::new(self.expander.current_file_id(), item.ast_id(&item_tree).upcast()),
+                    attrs.cfg().unwrap(),
+                    self.expander.cfg_options().clone(),
+                ));
                 continue;
             }
 
index df6dcb024b5eafb9b71b12d7517903b075da81de..40b2f734b7117192afa1fb51b52de20be9a250c8 100644 (file)
@@ -20,7 +20,7 @@
     intern::Interned,
     item_tree::{AttrOwner, ItemTree},
     lang_item::{LangItemTarget, LangItems},
-    nameres::DefMap,
+    nameres::{diagnostics::DefDiagnostic, DefMap},
     visibility::{self, Visibility},
     AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId,
     ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId,
@@ -106,9 +106,16 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
     #[salsa::invoke(ImplData::impl_data_query)]
     fn impl_data(&self, e: ImplId) -> Arc<ImplData>;
 
+    #[salsa::invoke(ImplData::impl_data_with_diagnostics_query)]
+    fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc<ImplData>, Arc<Vec<DefDiagnostic>>);
+
     #[salsa::invoke(TraitData::trait_data_query)]
     fn trait_data(&self, e: TraitId) -> Arc<TraitData>;
 
+    #[salsa::invoke(TraitData::trait_data_with_diagnostics_query)]
+    fn trait_data_with_diagnostics(&self, tr: TraitId)
+        -> (Arc<TraitData>, Arc<Vec<DefDiagnostic>>);
+
     #[salsa::invoke(TypeAliasData::type_alias_data_query)]
     fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>;
 
index 0d01f6d0aba3449517dca190319af8dedeb57b4e..ed7e920fd2b83a00ac28b69fca443dc6723a83d1 100644 (file)
@@ -73,7 +73,7 @@ pub(super) fn unresolved_import(
         Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } }
     }
 
-    pub(super) fn unconfigured_code(
+    pub fn unconfigured_code(
         container: LocalModuleId,
         ast: AstId<ast::Item>,
         cfg: CfgExpr,
index 9cdc18d6b66fdfb07ba53e85dcb00a65cc4aede7..b7908bddaa1cf785d392cf1e7f4449eee0f64e82 100644 (file)
@@ -10,7 +10,7 @@
     SourceDatabase, Upcast,
 };
 use hir_expand::{db::AstDatabase, InFile};
-use rustc_hash::FxHashSet;
+use stdx::hash::NoHashHashSet;
 use syntax::{algo, ast, AstNode};
 
 use crate::{
@@ -76,7 +76,7 @@ fn file_text(&self, file_id: FileId) -> Arc<String> {
     fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
         FileLoaderDelegate(self).resolve_path(path)
     }
-    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
+    fn relevant_crates(&self, file_id: FileId) -> Arc<NoHashHashSet<CrateId>> {
         FileLoaderDelegate(self).relevant_crates(file_id)
     }
 }
index ae115c8c0da85ad7afa7a84dd4fbee7fbd01cc47..3f6d0844e9c1f27afc10ece6dde6b3414c169937 100644 (file)
@@ -6,7 +6,7 @@
 //!
 //! This usually involves resolving names, collecting generic arguments etc.
 use std::{
-    cell::{Cell, RefCell},
+    cell::{Cell, RefCell, RefMut},
     iter,
     sync::Arc,
 };
@@ -330,26 +330,26 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
                 }
             }
             TypeRef::Macro(macro_call) => {
-                let (expander, recursion_start) = {
-                    let mut expander = self.expander.borrow_mut();
-                    if expander.is_some() {
-                        (Some(expander), false)
-                    } else {
-                        *expander = Some(Expander::new(
-                            self.db.upcast(),
-                            macro_call.file_id,
-                            self.resolver.module(),
-                        ));
-                        (Some(expander), true)
+                let (mut expander, recursion_start) = {
+                    match RefMut::filter_map(self.expander.borrow_mut(), Option::as_mut) {
+                        Ok(expander) => (expander, false),
+                        Err(expander) => (
+                            RefMut::map(expander, |it| {
+                                it.insert(Expander::new(
+                                    self.db.upcast(),
+                                    macro_call.file_id,
+                                    self.resolver.module(),
+                                ))
+                            }),
+                            true,
+                        ),
                     }
                 };
-                let ty = if let Some(mut expander) = expander {
-                    let expander_mut = expander.as_mut().unwrap();
+                let ty = {
                     let macro_call = macro_call.to_node(self.db.upcast());
-                    match expander_mut.enter_expand::<ast::Type>(self.db.upcast(), macro_call) {
+                    match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call) {
                         Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
-                            let ctx =
-                                LowerCtx::new(self.db.upcast(), expander_mut.current_file_id());
+                            let ctx = LowerCtx::new(self.db.upcast(), expander.current_file_id());
                             let type_ref = TypeRef::from_ast(&ctx, expanded);
 
                             drop(expander);
@@ -364,8 +364,6 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
                         }
                         _ => None,
                     }
-                } else {
-                    None
                 };
                 if recursion_start {
                     *self.expander.borrow_mut() = None;
@@ -479,7 +477,14 @@ pub(crate) fn lower_partly_resolved_path(
                         TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
                     }
                     ParamLoweringMode::Variable => {
-                        let idx = generics.param_idx(param_id.into()).expect("matching generics");
+                        let idx = match generics.param_idx(param_id.into()) {
+                            None => {
+                                never!("no matching generics");
+                                return (TyKind::Error.intern(Interner), None);
+                            }
+                            Some(idx) => idx,
+                        };
+
                         TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
                     }
                 }
index dc7252f7072d86a052eb2c2d365938bcf867bb28..118e5311e9a6414ebf6ab084762257883bb2d4dd 100644 (file)
@@ -10,7 +10,7 @@
 };
 use hir_def::{db::DefDatabase, ModuleId};
 use hir_expand::db::AstDatabase;
-use rustc_hash::{FxHashMap, FxHashSet};
+use stdx::hash::{NoHashHashMap, NoHashHashSet};
 use syntax::TextRange;
 use test_utils::extract_annotations;
 
@@ -80,7 +80,7 @@ fn file_text(&self, file_id: FileId) -> Arc<String> {
     fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
         FileLoaderDelegate(self).resolve_path(path)
     }
-    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
+    fn relevant_crates(&self, file_id: FileId) -> Arc<NoHashHashSet<CrateId>> {
         FileLoaderDelegate(self).relevant_crates(file_id)
     }
 }
@@ -102,7 +102,7 @@ pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
         self.module_for_file_opt(file_id).unwrap()
     }
 
-    pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
+    pub(crate) fn extract_annotations(&self) -> NoHashHashMap<FileId, Vec<(TextRange, String)>> {
         let mut files = Vec::new();
         let crate_graph = self.crate_graph();
         for krate in crate_graph.iter() {
index 1b5ed0603bfd137696aeb4fd7c79cf86bf8cb46f..c7895db1afbf5e523a3e6c9a03f09df74cd0aa73 100644 (file)
@@ -1526,6 +1526,34 @@ unsafe impl Storage for InlineStorage {
     );
 }
 
+#[test]
+fn gat_crash_3() {
+    // FIXME: This test currently crashes rust analyzer in a debug build but not in a
+    // release build (i.e. for the user). With the assumption that tests will always be run
+    // in debug mode, we catch the unwind and expect that it panicked. See the
+    // [`crate::utils::generics`] function for more information.
+    cov_mark::check!(ignore_gats);
+    std::panic::catch_unwind(|| {
+        check_no_mismatches(
+            r#"
+trait Collection {
+    type Item;
+    type Member<T>: Collection<Item = T>;
+    fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
+}
+struct ConstGen<T, const N: usize> {
+    data: [T; N],
+}
+impl<T, const N: usize> Collection for ConstGen<T, N> {
+    type Item = T;
+    type Member<U> = ConstGen<U, N>;
+}
+        "#,
+        );
+    })
+    .expect_err("must panic");
+}
+
 #[test]
 fn cfgd_out_self_param() {
     cov_mark::check!(cfgd_out_self_param);
index 83319755da73aa5fbce84053edf06cbbcd9a7e8f..d6638db02851183c5f080dc8cfc3fed5503ae76c 100644 (file)
@@ -176,10 +176,19 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
     let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
     if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) {
         let params = db.generic_params(def);
+        let parent_params = &parent_generics.as_ref().unwrap().params;
         let has_consts =
             params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
-        return if has_consts {
-            // XXX: treat const generic associated types as not existing to avoid crashes (#11769)
+        let parent_has_consts =
+            parent_params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
+        return if has_consts || parent_has_consts {
+            // XXX: treat const generic associated types as not existing to avoid crashes
+            // (#11769)
+            //
+            // Note: Also crashes when the parent has const generics (also even if the GAT
+            // doesn't use them), see `tests::regression::gat_crash_3` for an example.
+            // Avoids that by disabling GATs when the parent (i.e. `impl` block) has
+            // const generics (#12193).
             //
             // Chalk expects the inner associated type's parameters to come
             // *before*, not after the trait's generics as we've always done it.
@@ -264,12 +273,8 @@ pub(crate) fn param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
 
     fn find_param(&self, param: TypeOrConstParamId) -> Option<(usize, &TypeOrConstParamData)> {
         if param.parent == self.def {
-            let (idx, (_local_id, data)) = self
-                .params
-                .iter()
-                .enumerate()
-                .find(|(_, (idx, _))| *idx == param.local_id)
-                .unwrap();
+            let (idx, (_local_id, data)) =
+                self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?;
             let parent_len = self.parent_generics().map_or(0, Generics::len);
             Some((parent_len + idx, data))
         } else {
index aa019ca48381adc9230359094bdf6e69f23701f9..6dccf2ed20b8e8e6dc00534678e42e7a558de526 100644 (file)
@@ -511,6 +511,7 @@ pub fn scope(
             .collect()
     }
 
+    /// Fills `acc` with the module's diagnostics.
     pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
         let _p = profile::span("Module::diagnostics").detail(|| {
             format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
@@ -531,11 +532,21 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
                         m.diagnostics(db, acc)
                     }
                 }
+                ModuleDef::Trait(t) => {
+                    for diag in db.trait_data_with_diagnostics(t.id).1.iter() {
+                        emit_def_diagnostic(db, acc, diag);
+                    }
+                    acc.extend(decl.diagnostics(db))
+                }
                 _ => acc.extend(decl.diagnostics(db)),
             }
         }
 
         for impl_def in self.impl_defs(db) {
+            for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() {
+                emit_def_diagnostic(db, acc, diag);
+            }
+
             for item in impl_def.items(db) {
                 let def: DefWithBody = match item {
                     AssocItem::Function(it) => it.into(),
index af584cdb4384aa96b508775bfaec88932b14b456..03aa8601d14e1ef3e34207da916dd4574d175bbf 100644 (file)
@@ -171,6 +171,25 @@ fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
         ast::Type::RefType(ref_) => generics.extend(
             ref_.lifetime().and_then(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
         ),
+        ast::Type::ArrayType(ar) => {
+            if let Some(expr) = ar.expr() {
+                if let ast::Expr::PathExpr(p) = expr {
+                    if let Some(path) = p.path() {
+                        if let Some(name_ref) = path.as_single_name_ref() {
+                            if let Some(param) = known_generics.iter().find(|gp| {
+                                if let ast::GenericParam::ConstParam(cp) = gp {
+                                    cp.name().map_or(false, |n| n.text() == name_ref.text())
+                                } else {
+                                    false
+                                }
+                            }) {
+                                generics.push(param);
+                            }
+                        }
+                    }
+                }
+            }
+        }
         _ => (),
     });
     // stable resort to lifetime, type, const
@@ -357,4 +376,29 @@ fn func<'inner, Inner, const INNER: usize>(_: Type<'inner, 'outer, Outer, Inner,
 "#,
         );
     }
+
+    #[test]
+    fn issue_11197() {
+        check_assist(
+            extract_type_alias,
+            r#"
+struct Foo<T, const N: usize>
+where
+    [T; N]: Sized,
+{
+    arr: $0[T; N]$0,
+}
+            "#,
+            r#"
+type $0Type<T, const N: usize> = [T; N];
+
+struct Foo<T, const N: usize>
+where
+    [T; N]: Sized,
+{
+    arr: Type<T, N>,
+}
+            "#,
+        );
+    }
 }
index b5d092e39b02972b24da8cdfaedf9432e8e42691..96890ad51a6f941e3399fea772058ab19d653af9 100644 (file)
@@ -311,12 +311,16 @@ fn inline(
     } else {
         fn_body.clone_for_update()
     };
-    if let Some(t) = body.syntax().ancestors().find_map(ast::Impl::cast).and_then(|i| i.self_ty()) {
-        body.syntax()
-            .descendants_with_tokens()
-            .filter_map(NodeOrToken::into_token)
-            .filter(|tok| tok.kind() == SyntaxKind::SELF_TYPE_KW)
-            .for_each(|tok| ted::replace(tok, t.syntax()));
+    if let Some(imp) = body.syntax().ancestors().find_map(ast::Impl::cast) {
+        if !node.syntax().ancestors().any(|anc| &anc == imp.syntax()) {
+            if let Some(t) = imp.self_ty() {
+                body.syntax()
+                    .descendants_with_tokens()
+                    .filter_map(NodeOrToken::into_token)
+                    .filter(|tok| tok.kind() == SyntaxKind::SELF_TYPE_KW)
+                    .for_each(|tok| ted::replace(tok, t.syntax()));
+            }
+        }
     }
     let usages_for_locals = |local| {
         Definition::Local(local)
@@ -1221,6 +1225,31 @@ fn f() -> Self { Self(114514) }
 fn main() {
     A(114514);
 }
+"#,
+        )
+    }
+
+    #[test]
+    fn inline_call_with_self_type_but_within_same_impl() {
+        check_assist(
+            inline_call,
+            r#"
+struct A(u32);
+impl A {
+    fn f() -> Self { Self(1919810) }
+    fn main() {
+        Self::f$0();
+    }
+}
+"#,
+            r#"
+struct A(u32);
+impl A {
+    fn f() -> Self { Self(1919810) }
+    fn main() {
+        Self(1919810);
+    }
+}
 "#,
         )
     }
index 759742d347237520b0de7d09410ac5b92916f5b9..a5e854b74df9d268504f2b4e39684c6002e4c335 100644 (file)
@@ -64,8 +64,11 @@ pub(crate) struct PathCompletionCtx {
     pub(super) qualified: Qualified,
     /// The parent of the path we are completing.
     pub(super) parent: Option<ast::Path>,
+    #[allow(dead_code)]
     /// The path of which we are completing the segment
     pub(super) path: ast::Path,
+    /// The path of which we are completing the segment in the original file
+    pub(crate) original_path: Option<ast::Path>,
     pub(super) kind: PathKind,
     /// Whether the path segment has type args or not.
     pub(super) has_type_args: bool,
index 22ec7cead4988cc54d33b9f8c49e6c4b34cd1d88..01dd9a234f553c354a47eb3487fc610a37b8df26 100644 (file)
@@ -588,12 +588,15 @@ fn classify_name_ref(
         };
 
         let path = segment.parent_path();
+        let original_path = find_node_in_file_compensated(sema, original_file, &path);
+
         let mut path_ctx = PathCompletionCtx {
             has_call_parens: false,
             has_macro_bang: false,
             qualified: Qualified::No,
             parent: None,
             path: path.clone(),
+            original_path,
             kind: PathKind::Item { kind: ItemListKind::SourceFile },
             has_type_args: false,
             use_tree_parent: false,
index a2cf6d68e5b3a08529ece70ce8b455a232cf5010..86302cb0678f198687dfe2b4eed26997c642efa6 100644 (file)
@@ -323,9 +323,7 @@ fn render_resolution_path(
             ..CompletionRelevance::default()
         });
 
-        if let Some(ref_match) = compute_ref_match(completion, &ty) {
-            item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
-        }
+        path_ref_match(completion, path_ctx, &ty, &mut item);
     };
     item
 }
@@ -453,6 +451,29 @@ fn compute_ref_match(
     None
 }
 
+fn path_ref_match(
+    completion: &CompletionContext<'_>,
+    path_ctx: &PathCompletionCtx,
+    ty: &hir::Type,
+    item: &mut Builder,
+) {
+    if let Some(original_path) = &path_ctx.original_path {
+        // At least one char was typed by the user already, in that case look for the original path
+        if let Some(original_path) = completion.sema.original_ast_node(original_path.clone()) {
+            if let Some(ref_match) = compute_ref_match(completion, ty) {
+                item.ref_match(ref_match, original_path.syntax().text_range().start());
+            }
+        }
+    } else {
+        // completion requested on an empty identifier, there is no path here yet.
+        // FIXME: This might create inconsistent completions where we show a ref match in macro inputs
+        // as long as nothing was typed yet
+        if let Some(ref_match) = compute_ref_match(completion, ty) {
+            item.ref_match(ref_match, completion.position.offset);
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use std::cmp;
index 9cf64691298ebcfe74576bbbbbc844edd217d3b4..37612084604764eee2c66ec568d9dc7fda0c236f 100644 (file)
@@ -79,18 +79,18 @@ fn render(
         ..ctx.completion_relevance()
     });
 
-    if let Some(ref_match) = compute_ref_match(completion, &ret_type) {
-        match func_kind {
-            FuncKind::Function(path_ctx) => {
-                item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
-            }
-            FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => {
-                if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) {
+    match func_kind {
+        FuncKind::Function(path_ctx) => {
+            super::path_ref_match(completion, path_ctx, &ret_type, &mut item);
+        }
+        FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => {
+            if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) {
+                if let Some(ref_match) = compute_ref_match(completion, &ret_type) {
                     item.ref_match(ref_match, original_expr.syntax().text_range().start());
                 }
             }
-            _ => (),
         }
+        _ => (),
     }
 
     item.set_documentation(ctx.docs(func))
index af9c88a7e0a6cc87cbcb1f11ea22e9f4c207238b..0c791ac570c566f95f511c1a94805ffe03b96af1 100644 (file)
@@ -2,13 +2,12 @@
 
 use hir::{db::HirDatabase, Documentation, HasAttrs, StructKind};
 use ide_db::SymbolKind;
-use syntax::AstNode;
 
 use crate::{
     context::{CompletionContext, PathCompletionCtx, PathKind},
     item::{Builder, CompletionItem},
     render::{
-        compute_ref_match, compute_type_match,
+        compute_type_match,
         variant::{
             format_literal_label, format_literal_lookup, render_record_lit, render_tuple_lit,
             visible_fields, RenderedLiteral,
@@ -125,9 +124,8 @@ fn render(
         type_match: compute_type_match(ctx.completion, &ty),
         ..ctx.completion_relevance()
     });
-    if let Some(ref_match) = compute_ref_match(completion, &ty) {
-        item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
-    }
+
+    super::path_ref_match(completion, path_ctx, &ty, &mut item);
 
     if let Some(import_to_add) = ctx.import_to_add {
         item.add_import(import_to_add);
index 966bba616f6277aa3a97d9dbbec808927fce05b8..1ec62a8425a39b3fcb5f1fb6287047e7cf1b4002 100644 (file)
@@ -52,6 +52,7 @@ pub mod syntax_helpers {
     db::{AstDatabase, DefDatabase, HirDatabase},
     symbols::FileSymbolKind,
 };
+use stdx::hash::NoHashHashSet;
 
 use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
 pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
@@ -118,7 +119,7 @@ fn file_text(&self, file_id: FileId) -> Arc<String> {
     fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
         FileLoaderDelegate(self).resolve_path(path)
     }
-    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
+    fn relevant_crates(&self, file_id: FileId) -> Arc<NoHashHashSet<CrateId>> {
         FileLoaderDelegate(self).relevant_crates(file_id)
     }
 }
index 68ad07ee83fde307cbf5f754fae1872a48063fcb..75d49ff2fd77fc040779ee51238811c3b4348777 100644 (file)
@@ -2,7 +2,7 @@
 //! representation.
 use std::{iter, mem};
 
-use rustc_hash::FxHashMap;
+use stdx::hash::NoHashHashMap;
 use syntax::{TextRange, TextSize};
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -10,7 +10,7 @@ pub struct LineIndex {
     /// Offset the the beginning of each line, zero-based
     pub(crate) newlines: Vec<TextSize>,
     /// List of non-ASCII characters on each line
-    pub(crate) utf16_lines: FxHashMap<u32, Vec<Utf16Char>>,
+    pub(crate) utf16_lines: NoHashHashMap<u32, Vec<Utf16Char>>,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -55,7 +55,7 @@ fn len_utf16(&self) -> usize {
 
 impl LineIndex {
     pub fn new(text: &str) -> LineIndex {
-        let mut utf16_lines = FxHashMap::default();
+        let mut utf16_lines = NoHashHashMap::default();
         let mut utf16_chars = Vec::new();
 
         let mut newlines = vec![0.into()];
index 2f4aa113170a6f6865a3b6e560db8aa2727cfcce..7deffe8e0f637917c2ab05cac45ee069037caf69 100644 (file)
@@ -9,7 +9,7 @@
 use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
 use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility};
 use once_cell::unsync::Lazy;
-use rustc_hash::FxHashMap;
+use stdx::hash::NoHashHashMap;
 use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
 
 use crate::{
@@ -20,7 +20,7 @@
 
 #[derive(Debug, Default, Clone)]
 pub struct UsageSearchResult {
-    pub references: FxHashMap<FileId, Vec<FileReference>>,
+    pub references: NoHashHashMap<FileId, Vec<FileReference>>,
 }
 
 impl UsageSearchResult {
@@ -45,7 +45,7 @@ pub fn file_ranges(&self) -> impl Iterator<Item = FileRange> + '_ {
 
 impl IntoIterator for UsageSearchResult {
     type Item = (FileId, Vec<FileReference>);
-    type IntoIter = <FxHashMap<FileId, Vec<FileReference>> as IntoIterator>::IntoIter;
+    type IntoIter = <NoHashHashMap<FileId, Vec<FileReference>> as IntoIterator>::IntoIter;
 
     fn into_iter(self) -> Self::IntoIter {
         self.references.into_iter()
@@ -78,17 +78,17 @@ pub enum ReferenceCategory {
 /// e.g. for things like local variables.
 #[derive(Clone, Debug)]
 pub struct SearchScope {
-    entries: FxHashMap<FileId, Option<TextRange>>,
+    entries: NoHashHashMap<FileId, Option<TextRange>>,
 }
 
 impl SearchScope {
-    fn new(entries: FxHashMap<FileId, Option<TextRange>>) -> SearchScope {
+    fn new(entries: NoHashHashMap<FileId, Option<TextRange>>) -> SearchScope {
         SearchScope { entries }
     }
 
     /// Build a search scope spanning the entire crate graph of files.
     fn crate_graph(db: &RootDatabase) -> SearchScope {
-        let mut entries = FxHashMap::default();
+        let mut entries = NoHashHashMap::default();
 
         let graph = db.crate_graph();
         for krate in graph.iter() {
@@ -102,7 +102,7 @@ fn crate_graph(db: &RootDatabase) -> SearchScope {
 
     /// Build a search scope spanning all the reverse dependencies of the given crate.
     fn reverse_dependencies(db: &RootDatabase, of: hir::Crate) -> SearchScope {
-        let mut entries = FxHashMap::default();
+        let mut entries = NoHashHashMap::default();
         for rev_dep in of.transitive_reverse_dependencies(db) {
             let root_file = rev_dep.root_file(db);
             let source_root_id = db.file_source_root(root_file);
@@ -117,14 +117,12 @@ fn krate(db: &RootDatabase, of: hir::Crate) -> SearchScope {
         let root_file = of.root_file(db);
         let source_root_id = db.file_source_root(root_file);
         let source_root = db.source_root(source_root_id);
-        SearchScope {
-            entries: source_root.iter().map(|id| (id, None)).collect::<FxHashMap<_, _>>(),
-        }
+        SearchScope { entries: source_root.iter().map(|id| (id, None)).collect() }
     }
 
     /// Build a search scope spanning the given module and all its submodules.
     fn module_and_children(db: &RootDatabase, module: hir::Module) -> SearchScope {
-        let mut entries = FxHashMap::default();
+        let mut entries = NoHashHashMap::default();
 
         let (file_id, range) = {
             let InFile { file_id, value } = module.definition_source(db);
@@ -157,7 +155,7 @@ fn module_and_children(db: &RootDatabase, module: hir::Module) -> SearchScope {
 
     /// Build an empty search scope.
     pub fn empty() -> SearchScope {
-        SearchScope::new(FxHashMap::default())
+        SearchScope::new(NoHashHashMap::default())
     }
 
     /// Build a empty search scope spanning the given file.
index 21314ad74ef9387eee0e0b81d8d8bc3d4e5a10bf..8e338061df43345c6d18b2cd6eb1d7fefb41a707 100644 (file)
@@ -6,8 +6,7 @@
 use std::{collections::hash_map::Entry, iter, mem};
 
 use base_db::{AnchoredPathBuf, FileId};
-use rustc_hash::FxHashMap;
-use stdx::never;
+use stdx::{hash::NoHashHashMap, never};
 use syntax::{algo, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize};
 use text_edit::{TextEdit, TextEditBuilder};
 
@@ -15,7 +14,7 @@
 
 #[derive(Default, Debug, Clone)]
 pub struct SourceChange {
-    pub source_file_edits: FxHashMap<FileId, TextEdit>,
+    pub source_file_edits: NoHashHashMap<FileId, TextEdit>,
     pub file_system_edits: Vec<FileSystemEdit>,
     pub is_snippet: bool,
 }
@@ -24,7 +23,7 @@ impl SourceChange {
     /// Creates a new SourceChange with the given label
     /// from the edits.
     pub fn from_edits(
-        source_file_edits: FxHashMap<FileId, TextEdit>,
+        source_file_edits: NoHashHashMap<FileId, TextEdit>,
         file_system_edits: Vec<FileSystemEdit>,
     ) -> Self {
         SourceChange { source_file_edits, file_system_edits, is_snippet: false }
@@ -78,8 +77,8 @@ fn extend<T: IntoIterator<Item = FileSystemEdit>>(&mut self, iter: T) {
     }
 }
 
-impl From<FxHashMap<FileId, TextEdit>> for SourceChange {
-    fn from(source_file_edits: FxHashMap<FileId, TextEdit>) -> SourceChange {
+impl From<NoHashHashMap<FileId, TextEdit>> for SourceChange {
+    fn from(source_file_edits: NoHashHashMap<FileId, TextEdit>) -> SourceChange {
         SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false }
     }
 }
index 5694f33525e0114890f3ebd29e7fb16c4e65af81..04918891b254ca4a45f7cd12ef8187fc60d9c2c2 100644 (file)
@@ -106,18 +106,17 @@ fn inactive_item() {
 
     #[test]
     fn inactive_assoc_item() {
-        // FIXME these currently don't work, hence the *
         check(
             r#"
 struct Foo;
 impl Foo {
     #[cfg(any())] pub fn f() {}
-  //*************************** weak: code is inactive due to #[cfg] directives
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives
 }
 
 trait Bar {
     #[cfg(any())] pub fn f() {}
-  //*************************** weak: code is inactive due to #[cfg] directives
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives
 }
 "#,
         );
index d36dd02d45c5976a5f2576cbbbbe8ae1fe6f24e2..73314e0f330bc67a30b291e55bdb588ff30bdde7 100644 (file)
@@ -20,6 +20,7 @@ parser = { path = "../parser", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
 ide-db = { path = "../ide-db", version = "0.0.0" }
 hir = { path = "../hir", version = "0.0.0" }
+stdx = { path = "../stdx", version = "0.0.0" }
 
 [dev-dependencies]
 test-utils = { path = "../test-utils" }
index 739e0ccb436dbeebad6112430c610ca79a93688e..d9834ee63adccf1368681f8397672e93ef0c3e66 100644 (file)
 
 use crate::{errors::bail, matching::MatchFailureReason};
 use hir::Semantics;
-use ide_db::{
-    base_db::{FileId, FilePosition, FileRange},
-    FxHashMap,
-};
+use ide_db::base_db::{FileId, FilePosition, FileRange};
 use resolving::ResolvedRule;
+use stdx::hash::NoHashHashMap;
 use syntax::{ast, AstNode, SyntaxNode, TextRange};
 use text_edit::TextEdit;
 
@@ -170,9 +168,9 @@ pub fn add_rule(&mut self, rule: SsrRule) -> Result<(), SsrError> {
     }
 
     /// Finds matches for all added rules and returns edits for all found matches.
-    pub fn edits(&self) -> FxHashMap<FileId, TextEdit> {
+    pub fn edits(&self) -> NoHashHashMap<FileId, TextEdit> {
         use ide_db::base_db::SourceDatabaseExt;
-        let mut matches_by_file = FxHashMap::default();
+        let mut matches_by_file = NoHashHashMap::default();
         for m in self.matches().matches {
             matches_by_file
                 .entry(m.range.file_id)
index 582e9fe7e808c05b933de4293d5e66bc719dba70..92ce26b422e1dab0f13af86930c8c62e674fd7fd 100644 (file)
@@ -184,10 +184,10 @@ pub(crate) fn resolve_doc_path_for_def(
         Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
         Definition::Macro(it) => it.resolve_doc_path(db, link, ns),
         Definition::Field(it) => it.resolve_doc_path(db, link, ns),
+        Definition::SelfType(it) => it.resolve_doc_path(db, link, ns),
         Definition::BuiltinAttr(_)
         | Definition::ToolModule(_)
         | Definition::BuiltinType(_)
-        | Definition::SelfType(_)
         | Definition::Local(_)
         | Definition::GenericParam(_)
         | Definition::Label(_)
index dd108fa799970879d333b0d2d4de7b25d99f4d1e..d61d69a090b33850049acfa36b8327ba7b887965 100644 (file)
@@ -87,7 +87,7 @@ macro_rules! eprintln {
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
-    moniker::{MonikerKind, MonikerResult, PackageInformation},
+    moniker::{MonikerDescriptorKind, MonikerKind, MonikerResult, PackageInformation},
     move_item::Direction,
     navigation_target::NavigationTarget,
     prime_caches::ParallelPrimeCachesProgress,
@@ -98,7 +98,7 @@ macro_rules! eprintln {
     static_index::{StaticIndex, StaticIndexedFile, TokenId, TokenStaticData},
     syntax_highlighting::{
         tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag},
-        HlRange,
+        HighlightConfig, HlRange,
     },
 };
 pub use hir::{Documentation, Semantics};
@@ -517,8 +517,12 @@ pub fn related_tests(
     }
 
     /// Computes syntax highlighting for the given file
-    pub fn highlight(&self, file_id: FileId) -> Cancellable<Vec<HlRange>> {
-        self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false))
+    pub fn highlight(
+        &self,
+        highlight_config: HighlightConfig,
+        file_id: FileId,
+    ) -> Cancellable<Vec<HlRange>> {
+        self.with_db(|db| syntax_highlighting::highlight(db, highlight_config, file_id, None))
     }
 
     /// Computes all ranges to highlight for a given item in a file.
@@ -533,9 +537,13 @@ pub fn highlight_related(
     }
 
     /// Computes syntax highlighting for the given file range.
-    pub fn highlight_range(&self, frange: FileRange) -> Cancellable<Vec<HlRange>> {
+    pub fn highlight_range(
+        &self,
+        highlight_config: HighlightConfig,
+        frange: FileRange,
+    ) -> Cancellable<Vec<HlRange>> {
         self.with_db(|db| {
-            syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false)
+            syntax_highlighting::highlight(db, highlight_config, frange.file_id, Some(frange.range))
         })
     }
 
index 4f758967b46194538d41c753da10372f997ba7de..600a526300c76a10594fe7f4b8b5c28ec4a072b8 100644 (file)
 
 use crate::{doc_links::token_as_doc_comment, RangeInfo};
 
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum MonikerDescriptorKind {
+    Namespace,
+    Type,
+    Term,
+    Method,
+    TypeParameter,
+    Parameter,
+    Macro,
+    Meta,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct MonikerDescriptor {
+    pub name: Name,
+    pub desc: MonikerDescriptorKind,
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct MonikerIdentifier {
-    crate_name: String,
-    path: Vec<Name>,
+    pub crate_name: String,
+    pub description: Vec<MonikerDescriptor>,
 }
 
 impl ToString for MonikerIdentifier {
     fn to_string(&self) -> String {
         match self {
-            MonikerIdentifier { path, crate_name } => {
-                format!("{}::{}", crate_name, path.iter().map(|x| x.to_string()).join("::"))
+            MonikerIdentifier { description, crate_name } => {
+                format!(
+                    "{}::{}",
+                    crate_name,
+                    description.iter().map(|x| x.name.to_string()).join("::")
+                )
             }
         }
     }
@@ -42,6 +64,12 @@ pub struct MonikerResult {
     pub package_information: PackageInformation,
 }
 
+impl MonikerResult {
+    pub fn from_def(db: &RootDatabase, def: Definition, from_crate: Crate) -> Option<Self> {
+        def_to_moniker(db, def, from_crate)
+    }
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct PackageInformation {
     pub name: String,
@@ -105,13 +133,23 @@ pub(crate) fn def_to_moniker(
     def: Definition,
     from_crate: Crate,
 ) -> Option<MonikerResult> {
-    if matches!(def, Definition::GenericParam(_) | Definition::SelfType(_) | Definition::Local(_)) {
+    if matches!(
+        def,
+        Definition::GenericParam(_)
+            | Definition::Label(_)
+            | Definition::DeriveHelper(_)
+            | Definition::BuiltinAttr(_)
+            | Definition::ToolModule(_)
+    ) {
         return None;
     }
+
     let module = def.module(db)?;
     let krate = module.krate();
-    let mut path = vec![];
-    path.extend(module.path_to_root(db).into_iter().filter_map(|x| x.name(db)));
+    let mut description = vec![];
+    description.extend(module.path_to_root(db).into_iter().filter_map(|x| {
+        Some(MonikerDescriptor { name: x.name(db)?, desc: MonikerDescriptorKind::Namespace })
+    }));
 
     // Handle associated items within a trait
     if let Some(assoc) = def.as_assoc_item(db) {
@@ -120,31 +158,98 @@ pub(crate) fn def_to_moniker(
             AssocItemContainer::Trait(trait_) => {
                 // Because different traits can have functions with the same name,
                 // we have to include the trait name as part of the moniker for uniqueness.
-                path.push(trait_.name(db));
+                description.push(MonikerDescriptor {
+                    name: trait_.name(db),
+                    desc: MonikerDescriptorKind::Type,
+                });
             }
             AssocItemContainer::Impl(impl_) => {
                 // Because a struct can implement multiple traits, for implementations
                 // we add both the struct name and the trait name to the path
                 if let Some(adt) = impl_.self_ty(db).as_adt() {
-                    path.push(adt.name(db));
+                    description.push(MonikerDescriptor {
+                        name: adt.name(db),
+                        desc: MonikerDescriptorKind::Type,
+                    });
                 }
 
                 if let Some(trait_) = impl_.trait_(db) {
-                    path.push(trait_.name(db));
+                    description.push(MonikerDescriptor {
+                        name: trait_.name(db),
+                        desc: MonikerDescriptorKind::Type,
+                    });
                 }
             }
         }
     }
 
     if let Definition::Field(it) = def {
-        path.push(it.parent_def(db).name(db));
+        description.push(MonikerDescriptor {
+            name: it.parent_def(db).name(db),
+            desc: MonikerDescriptorKind::Type,
+        });
     }
 
-    path.push(def.name(db)?);
+    let name_desc = match def {
+        // These are handled by top-level guard (for performance).
+        Definition::GenericParam(_)
+        | Definition::Label(_)
+        | Definition::DeriveHelper(_)
+        | Definition::BuiltinAttr(_)
+        | Definition::ToolModule(_) => return None,
+
+        Definition::Local(local) => {
+            if !local.is_param(db) {
+                return None;
+            }
+
+            MonikerDescriptor { name: local.name(db), desc: MonikerDescriptorKind::Parameter }
+        }
+        Definition::Macro(m) => {
+            MonikerDescriptor { name: m.name(db), desc: MonikerDescriptorKind::Macro }
+        }
+        Definition::Function(f) => {
+            MonikerDescriptor { name: f.name(db), desc: MonikerDescriptorKind::Method }
+        }
+        Definition::Variant(v) => {
+            MonikerDescriptor { name: v.name(db), desc: MonikerDescriptorKind::Type }
+        }
+        Definition::Const(c) => {
+            MonikerDescriptor { name: c.name(db)?, desc: MonikerDescriptorKind::Term }
+        }
+        Definition::Trait(trait_) => {
+            MonikerDescriptor { name: trait_.name(db), desc: MonikerDescriptorKind::Type }
+        }
+        Definition::TypeAlias(ta) => {
+            MonikerDescriptor { name: ta.name(db), desc: MonikerDescriptorKind::TypeParameter }
+        }
+        Definition::Module(m) => {
+            MonikerDescriptor { name: m.name(db)?, desc: MonikerDescriptorKind::Namespace }
+        }
+        Definition::BuiltinType(b) => {
+            MonikerDescriptor { name: b.name(), desc: MonikerDescriptorKind::Type }
+        }
+        Definition::SelfType(imp) => MonikerDescriptor {
+            name: imp.self_ty(db).as_adt()?.name(db),
+            desc: MonikerDescriptorKind::Type,
+        },
+        Definition::Field(it) => {
+            MonikerDescriptor { name: it.name(db), desc: MonikerDescriptorKind::Term }
+        }
+        Definition::Adt(adt) => {
+            MonikerDescriptor { name: adt.name(db), desc: MonikerDescriptorKind::Type }
+        }
+        Definition::Static(s) => {
+            MonikerDescriptor { name: s.name(db), desc: MonikerDescriptorKind::Meta }
+        }
+    };
+
+    description.push(name_desc);
+
     Some(MonikerResult {
         identifier: MonikerIdentifier {
             crate_name: krate.display_name(db)?.crate_name().to_string(),
-            path,
+            description,
         },
         kind: if krate == from_crate { MonikerKind::Export } else { MonikerKind::Import },
         package_information: {
index 296270036002b906a8ec950621291a11bdca9486..87b3ef380c5943e0986ea4521be48591c74c9317 100644 (file)
@@ -12,8 +12,9 @@
         salsa::{Database, ParallelDatabase, Snapshot},
         Cancelled, CrateGraph, CrateId, SourceDatabase, SourceDatabaseExt,
     },
-    FxHashSet, FxIndexMap,
+    FxIndexMap,
 };
+use stdx::hash::NoHashHashSet;
 
 use crate::RootDatabase;
 
@@ -141,7 +142,7 @@ enum ParallelPrimeCacheWorkerProgress {
     }
 }
 
-fn compute_crates_to_prime(db: &RootDatabase, graph: &CrateGraph) -> FxHashSet<CrateId> {
+fn compute_crates_to_prime(db: &RootDatabase, graph: &CrateGraph) -> NoHashHashSet<CrateId> {
     // We're only interested in the workspace crates and the `ImportMap`s of their direct
     // dependencies, though in practice the latter also compute the `DefMap`s.
     // We don't prime transitive dependencies because they're generally not visible in
index 1a6beec1881b00faf061a2e3b52b54429cda90ec..99614b645e48ff02160b38fcf377f12bf01b4705 100644 (file)
@@ -14,8 +14,9 @@
     base_db::FileId,
     defs::{Definition, NameClass, NameRefClass},
     search::{ReferenceCategory, SearchScope, UsageSearchResult},
-    FxHashMap, RootDatabase,
+    RootDatabase,
 };
+use stdx::hash::NoHashHashMap;
 use syntax::{
     algo::find_node_at_offset,
     ast::{self, HasName},
@@ -29,7 +30,7 @@
 #[derive(Debug, Clone)]
 pub struct ReferenceSearchResult {
     pub declaration: Option<Declaration>,
-    pub references: FxHashMap<FileId, Vec<(TextRange, Option<ReferenceCategory>)>>,
+    pub references: NoHashHashMap<FileId, Vec<(TextRange, Option<ReferenceCategory>)>>,
 }
 
 #[derive(Debug, Clone)]
index 3fb49b45d9888ebb7fcac3d4e4431b3f9f596e75..50371d620eb2a41954412a3f1dd79bc33c18756e 100644 (file)
@@ -14,7 +14,7 @@
 mod tests;
 
 use hir::{Name, Semantics};
-use ide_db::{FxHashMap, RootDatabase};
+use ide_db::{FxHashMap, RootDatabase, SymbolKind};
 use syntax::{
     ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T,
 };
@@ -24,7 +24,7 @@
         escape::highlight_escape_string, format::highlight_format_string, highlights::Highlights,
         macro_::MacroHighlighter, tags::Highlight,
     },
-    FileId, HlMod, HlTag,
+    FileId, HlMod, HlOperator, HlPunct, HlTag,
 };
 
 pub(crate) use html::highlight_as_html;
@@ -36,6 +36,26 @@ pub struct HlRange {
     pub binding_hash: Option<u64>,
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct HighlightConfig {
+    /// Whether to highlight strings
+    pub strings: bool,
+    /// Whether to highlight punctuation
+    pub punctuation: bool,
+    /// Whether to specialize punctuation highlights
+    pub specialize_punctuation: bool,
+    /// Whether to highlight operator
+    pub operator: bool,
+    /// Whether to specialize operator highlights
+    pub specialize_operator: bool,
+    /// Whether to inject highlights into doc comments
+    pub inject_doc_comment: bool,
+    /// Whether to highlight the macro call bang
+    pub macro_bang: bool,
+    /// Whether to highlight unresolved things be their syntax
+    pub syntactic_name_ref_highlighting: bool,
+}
+
 // Feature: Semantic Syntax Highlighting
 //
 // rust-analyzer highlights the code semantically.
@@ -155,9 +175,9 @@ pub struct HlRange {
 // image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[]
 pub(crate) fn highlight(
     db: &RootDatabase,
+    config: HighlightConfig,
     file_id: FileId,
     range_to_highlight: Option<TextRange>,
-    syntactic_name_ref_highlighting: bool,
 ) -> Vec<HlRange> {
     let _p = profile::span("highlight");
     let sema = Semantics::new(db);
@@ -183,26 +203,18 @@ pub(crate) fn highlight(
         Some(it) => it.krate(),
         None => return hl.to_vec(),
     };
-    traverse(
-        &mut hl,
-        &sema,
-        file_id,
-        &root,
-        krate,
-        range_to_highlight,
-        syntactic_name_ref_highlighting,
-    );
+    traverse(&mut hl, &sema, config, file_id, &root, krate, range_to_highlight);
     hl.to_vec()
 }
 
 fn traverse(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
+    config: HighlightConfig,
     file_id: FileId,
     root: &SyntaxNode,
     krate: hir::Crate,
     range_to_highlight: TextRange,
-    syntactic_name_ref_highlighting: bool,
 ) {
     let is_unlinked = sema.to_module_def(file_id).is_none();
     let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
@@ -323,9 +335,11 @@ fn item(&self) -> &ast::Item {
             Enter(it) => it,
             Leave(NodeOrToken::Token(_)) => continue,
             Leave(NodeOrToken::Node(node)) => {
-                // Doc comment highlighting injection, we do this when leaving the node
-                // so that we overwrite the highlighting of the doc comment itself.
-                inject::doc_comment(hl, sema, file_id, &node);
+                if config.inject_doc_comment {
+                    // Doc comment highlighting injection, we do this when leaving the node
+                    // so that we overwrite the highlighting of the doc comment itself.
+                    inject::doc_comment(hl, sema, config, file_id, &node);
+                }
                 continue;
             }
         };
@@ -400,7 +414,8 @@ fn item(&self) -> &ast::Item {
                 let string_to_highlight = ast::String::cast(descended_token.clone());
                 if let Some((string, expanded_string)) = string.zip(string_to_highlight) {
                     if string.is_raw() {
-                        if inject::ra_fixture(hl, sema, &string, &expanded_string).is_some() {
+                        if inject::ra_fixture(hl, sema, config, &string, &expanded_string).is_some()
+                        {
                             continue;
                         }
                     }
@@ -421,7 +436,7 @@ fn item(&self) -> &ast::Item {
                 sema,
                 krate,
                 &mut bindings_shadow_count,
-                syntactic_name_ref_highlighting,
+                config.syntactic_name_ref_highlighting,
                 name_like,
             ),
             NodeOrToken::Token(token) => highlight::token(sema, token).zip(Some(None)),
@@ -439,6 +454,29 @@ fn item(&self) -> &ast::Item {
                 // something unresolvable. FIXME: There should be a way to prevent that
                 continue;
             }
+
+            // apply config filtering
+            match &mut highlight.tag {
+                HlTag::StringLiteral if !config.strings => continue,
+                // If punctuation is disabled, make the macro bang part of the macro call again.
+                tag @ HlTag::Punctuation(HlPunct::MacroBang) => {
+                    if !config.macro_bang {
+                        *tag = HlTag::Symbol(SymbolKind::Macro);
+                    } else if !config.specialize_punctuation {
+                        *tag = HlTag::Punctuation(HlPunct::Other);
+                    }
+                }
+                HlTag::Punctuation(_) if !config.punctuation => continue,
+                tag @ HlTag::Punctuation(_) if !config.specialize_punctuation => {
+                    *tag = HlTag::Punctuation(HlPunct::Other);
+                }
+                HlTag::Operator(_) if !config.operator && highlight.mods.is_empty() => continue,
+                tag @ HlTag::Operator(_) if !config.specialize_operator => {
+                    *tag = HlTag::Operator(HlOperator::Other);
+                }
+                _ => (),
+            }
+
             if inside_attribute {
                 highlight |= HlMod::Attribute
             }
index 9777c014c7a1648f933f88ead4341f2b14e1a903..e91fd7f12571649cee96e51e652165cad39bc993 100644 (file)
@@ -5,7 +5,10 @@
 use stdx::format_to;
 use syntax::AstNode;
 
-use crate::{syntax_highlighting::highlight, FileId, RootDatabase};
+use crate::{
+    syntax_highlighting::{highlight, HighlightConfig},
+    FileId, RootDatabase,
+};
 
 pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String {
     let parse = db.parse(file_id);
@@ -20,7 +23,21 @@ fn rainbowify(seed: u64) -> String {
         )
     }
 
-    let hl_ranges = highlight(db, file_id, None, false);
+    let hl_ranges = highlight(
+        db,
+        HighlightConfig {
+            strings: true,
+            punctuation: true,
+            specialize_punctuation: true,
+            specialize_operator: true,
+            operator: true,
+            inject_doc_comment: true,
+            macro_bang: true,
+            syntactic_name_ref_highlighting: false,
+        },
+        file_id,
+        None,
+    );
     let text = parse.tree().syntax().to_string();
     let mut buf = String::new();
     buf.push_str(STYLE);
index f376f9fda7a57799c0be9b774a81508a065d2893..9139528c7ed96d08685e6bb646e50aa7482bf5e4 100644 (file)
 
 use crate::{
     doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def},
-    syntax_highlighting::{highlights::Highlights, injector::Injector},
+    syntax_highlighting::{highlights::Highlights, injector::Injector, HighlightConfig},
     Analysis, HlMod, HlRange, HlTag, RootDatabase,
 };
 
 pub(super) fn ra_fixture(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
+    config: HighlightConfig,
     literal: &ast::String,
     expanded: &ast::String,
 ) -> Option<()> {
@@ -63,7 +64,13 @@ pub(super) fn ra_fixture(
 
     let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text());
 
-    for mut hl_range in analysis.highlight(tmp_file_id).unwrap() {
+    for mut hl_range in analysis
+        .highlight(
+            HighlightConfig { syntactic_name_ref_highlighting: false, ..config },
+            tmp_file_id,
+        )
+        .unwrap()
+    {
         for range in inj.map_range_up(hl_range.range) {
             if let Some(range) = literal.map_range_up(range) {
                 hl_range.range = range;
@@ -86,6 +93,7 @@ pub(super) fn ra_fixture(
 pub(super) fn doc_comment(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
+    config: HighlightConfig,
     src_file_id: FileId,
     node: &SyntaxNode,
 ) {
@@ -206,7 +214,14 @@ pub(super) fn doc_comment(
 
     let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text());
 
-    if let Ok(ranges) = analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)) {
+    if let Ok(ranges) = analysis.with_db(|db| {
+        super::highlight(
+            db,
+            HighlightConfig { syntactic_name_ref_highlighting: true, ..config },
+            tmp_file_id,
+            None,
+        )
+    }) {
         for HlRange { range, highlight, binding_hash } in ranges {
             for range in inj.map_range_up(range) {
                 hl.add(HlRange { range, highlight: highlight | HlMod::Injected, binding_hash });
index 5262770f30317f9312cc156f5664f1185ceba8f9..3949f1189bd5ed47d946d46dec67cc2102c7bd40 100644 (file)
@@ -199,7 +199,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 impl HlMod {
-    const ALL: &'static [HlMod; HlMod::Unsafe as u8 as usize + 1] = &[
+    const ALL: &'static [HlMod; 19] = &[
         HlMod::Associated,
         HlMod::Async,
         HlMod::Attribute,
@@ -296,7 +296,7 @@ pub(crate) fn new(tag: HlTag) -> Highlight {
         Highlight { tag, mods: HlMods::default() }
     }
     pub fn is_empty(&self) -> bool {
-        self.tag == HlTag::None && self.mods == HlMods::default()
+        self.tag == HlTag::None && self.mods.is_empty()
     }
 }
 
@@ -330,6 +330,10 @@ fn bitor(mut self, rhs: HlMod) -> Highlight {
 }
 
 impl HlMods {
+    pub fn is_empty(&self) -> bool {
+        self.0 == 0
+    }
+
     pub fn contains(self, m: HlMod) -> bool {
         self.0 & m.mask() == m.mask()
     }
index a747b4bc1f9c052796ab8b13dac6820c8e556b41..eef5baea9839239e3d1b0e8220f102d24cec7db0 100644 (file)
@@ -56,7 +56,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="field declaration">bar</span><span class="colon">:</span> <span class="builtin_type">bool</span><span class="comma">,</span>
 <span class="brace">}</span>
 
-<span class="comment documentation">/// This is an impl with a code block.</span>
+<span class="comment documentation">/// This is an impl of </span><span class="struct documentation injected intra_doc_link">[`Foo`]</span><span class="comment documentation"> with a code block.</span>
 <span class="comment documentation">///</span>
 <span class="comment documentation">/// ```</span>
 <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span>
index 382735cb368df3cac89ca0bb72559896b944f28c..46cc667fc454f4f08f842017232a1b28e506e2fd 100644 (file)
@@ -4,7 +4,18 @@
 use ide_db::SymbolKind;
 use test_utils::{bench, bench_fixture, skip_slow_tests, AssertLinear};
 
-use crate::{fixture, FileRange, HlTag, TextRange};
+use crate::{fixture, FileRange, HighlightConfig, HlTag, TextRange};
+
+const HL_CONFIG: HighlightConfig = HighlightConfig {
+    strings: true,
+    punctuation: true,
+    specialize_punctuation: true,
+    specialize_operator: true,
+    operator: true,
+    inject_doc_comment: true,
+    macro_bang: true,
+    syntactic_name_ref_highlighting: false,
+};
 
 #[test]
 fn attributes() {
@@ -613,7 +624,7 @@ struct Foo {
     bar: bool,
 }
 
-/// This is an impl with a code block.
+/// This is an impl of [`Foo`] with a code block.
 ///
 /// ```
 /// fn foo() {
@@ -996,7 +1007,10 @@ struct Foo {
 
     // The "x"
     let highlights = &analysis
-        .highlight_range(FileRange { file_id, range: TextRange::at(45.into(), 1.into()) })
+        .highlight_range(
+            HL_CONFIG,
+            FileRange { file_id, range: TextRange::at(45.into(), 1.into()) },
+        )
         .unwrap();
 
     assert_eq!(&highlights[0].highlight.to_string(), "field.declaration.public");
@@ -1011,7 +1025,7 @@ macro_rules! test {}
 }"#
         .trim(),
     );
-    let _ = analysis.highlight(file_id).unwrap();
+    let _ = analysis.highlight(HL_CONFIG, file_id).unwrap();
 }
 
 /// Highlights the code given by the `ra_fixture` argument, renders the
@@ -1035,7 +1049,7 @@ fn benchmark_syntax_highlighting_long_struct() {
     let hash = {
         let _pt = bench("syntax highlighting long struct");
         analysis
-            .highlight(file_id)
+            .highlight(HL_CONFIG, file_id)
             .unwrap()
             .iter()
             .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct))
@@ -1061,7 +1075,7 @@ fn syntax_highlighting_not_quadratic() {
             let time = Instant::now();
 
             let hash = analysis
-                .highlight(file_id)
+                .highlight(HL_CONFIG, file_id)
                 .unwrap()
                 .iter()
                 .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct))
@@ -1086,7 +1100,7 @@ fn benchmark_syntax_highlighting_parser() {
     let hash = {
         let _pt = bench("syntax highlighting parser");
         analysis
-            .highlight(file_id)
+            .highlight(HL_CONFIG, file_id)
             .unwrap()
             .iter()
             .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function))
index bf7b7efe28228885712908e998c30b31135573d5..17a1e385b77248b4ed974d271745a3ffeddf5919 100644 (file)
@@ -3,8 +3,9 @@
 use dot::{Id, LabelText};
 use ide_db::{
     base_db::{CrateGraph, CrateId, Dependency, SourceDatabase, SourceDatabaseExt},
-    FxHashSet, RootDatabase,
+    RootDatabase,
 };
+use stdx::hash::NoHashHashSet;
 
 // Feature: View Crate Graph
 //
@@ -41,7 +42,7 @@ pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result<String,
 
 struct DotCrateGraph {
     graph: Arc<CrateGraph>,
-    crates_to_render: FxHashSet<CrateId>,
+    crates_to_render: NoHashHashSet<CrateId>,
 }
 
 type Edge<'a> = (CrateId, &'a Dependency);
index 7e21a808da0a481af06c98aa2829ccdc7f27a17d..bc1224af9b212c639bcf80026661554887f19d07 100644 (file)
@@ -13,6 +13,8 @@
         T![.],
     ]));
 
+const PAT_TOP_FIRST: TokenSet = PATTERN_FIRST.union(TokenSet::new(&[T![|]]));
+
 pub(crate) fn pattern(p: &mut Parser<'_>) {
     pattern_r(p, PAT_RECOVERY_SET);
 }
@@ -228,6 +230,7 @@ fn path_or_macro_pat(p: &mut Parser<'_>) -> CompletedMarker {
 //     let S(_) = ();
 //     let S(_,) = ();
 //     let S(_, .. , x) = ();
+//     let S(| a) = ();
 // }
 fn tuple_pat_fields(p: &mut Parser<'_>) {
     assert!(p.at(T!['(']));
@@ -363,6 +366,7 @@ fn ref_pat(p: &mut Parser<'_>) -> CompletedMarker {
 //     let (a,) = ();
 //     let (..) = ();
 //     let () = ();
+//     let (| a | a, | b) = ((),());
 // }
 fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker {
     assert!(p.at(T!['(']));
@@ -373,13 +377,13 @@ fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker {
     let mut has_rest = false;
     while !p.at(EOF) && !p.at(T![')']) {
         has_pat = true;
-        if !p.at_ts(PATTERN_FIRST) {
+        if !p.at_ts(PAT_TOP_FIRST) {
             p.error("expected a pattern");
             break;
         }
         has_rest |= p.at(T![..]);
 
-        pattern(p);
+        pattern_top(p);
         if !p.at(T![')']) {
             has_comma = true;
             p.expect(T![,]);
@@ -393,6 +397,7 @@ fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker {
 // test slice_pat
 // fn main() {
 //     let [a, b, ..] = [];
+//     let [| a, ..] = [];
 // }
 fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker {
     assert!(p.at(T!['[']));
@@ -405,12 +410,12 @@ fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker {
 
 fn pat_list(p: &mut Parser<'_>, ket: SyntaxKind) {
     while !p.at(EOF) && !p.at(ket) {
-        if !p.at_ts(PATTERN_FIRST) {
+        if !p.at_ts(PAT_TOP_FIRST) {
             p.error("expected a pattern");
             break;
         }
 
-        pattern(p);
+        pattern_top(p);
         if !p.at(ket) {
             p.expect(T![,]);
         }
index 235a9d7f404cf43602ac36d809c0fb4c44ddbbdc..dff72ba886fe82db58644325c4f72f57e8f543a5 100644 (file)
@@ -37,6 +37,29 @@ SOURCE_FILE
             L_BRACK "["
             R_BRACK "]"
           SEMICOLON ";"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          SLICE_PAT
+            L_BRACK "["
+            PIPE "|"
+            WHITESPACE " "
+            IDENT_PAT
+              NAME
+                IDENT "a"
+            COMMA ","
+            WHITESPACE " "
+            REST_PAT
+              DOT2 ".."
+            R_BRACK "]"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          ARRAY_EXPR
+            L_BRACK "["
+            R_BRACK "]"
+          SEMICOLON ";"
         WHITESPACE "\n"
         R_CURLY "}"
   WHITESPACE "\n"
index 7955973b952a770d71d5fe786f83fde238e8e8e0..855ba89b1e9d9ec911ba50b82cce76ac9f2a21c6 100644 (file)
@@ -1,3 +1,4 @@
 fn main() {
     let [a, b, ..] = [];
+    let [| a, ..] = [];
 }
index 3cdaf32b5721c24103d18014a6aebda85ec6ab0a..55baf2fdcb4f6a525a166c6c1f40fc049ee7d519 100644 (file)
@@ -100,6 +100,29 @@ SOURCE_FILE
             L_PAREN "("
             R_PAREN ")"
           SEMICOLON ";"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          TUPLE_STRUCT_PAT
+            PATH
+              PATH_SEGMENT
+                NAME_REF
+                  IDENT "S"
+            L_PAREN "("
+            PIPE "|"
+            WHITESPACE " "
+            IDENT_PAT
+              NAME
+                IDENT "a"
+            R_PAREN ")"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          TUPLE_EXPR
+            L_PAREN "("
+            R_PAREN ")"
+          SEMICOLON ";"
         WHITESPACE "\n"
         R_CURLY "}"
   WHITESPACE "\n"
index 0dfe63629679baa0eef52b815e49ffa5dd6cfac8..8ec6f4ca93e031ed6f3365e859f0b42ab959e328 100644 (file)
@@ -3,4 +3,5 @@ fn foo() {
     let S(_) = ();
     let S(_,) = ();
     let S(_, .. , x) = ();
+    let S(| a) = ();
 }
index cebe98c43aa62ed8ac6f1e43de72d73d098361fa..1a01e0f69381feff531618d16b6f6cce6b85901a 100644 (file)
@@ -85,6 +85,46 @@ SOURCE_FILE
             L_PAREN "("
             R_PAREN ")"
           SEMICOLON ";"
+        WHITESPACE "\n    "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          TUPLE_PAT
+            L_PAREN "("
+            PIPE "|"
+            WHITESPACE " "
+            OR_PAT
+              IDENT_PAT
+                NAME
+                  IDENT "a"
+              WHITESPACE " "
+              PIPE "|"
+              WHITESPACE " "
+              IDENT_PAT
+                NAME
+                  IDENT "a"
+            COMMA ","
+            WHITESPACE " "
+            PIPE "|"
+            WHITESPACE " "
+            IDENT_PAT
+              NAME
+                IDENT "b"
+            R_PAREN ")"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          TUPLE_EXPR
+            L_PAREN "("
+            TUPLE_EXPR
+              L_PAREN "("
+              R_PAREN ")"
+            COMMA ","
+            TUPLE_EXPR
+              L_PAREN "("
+              R_PAREN ")"
+            R_PAREN ")"
+          SEMICOLON ";"
         WHITESPACE "\n"
         R_CURLY "}"
   WHITESPACE "\n"
index ba719879d4c1acad2e13ddef6392072e1532e35a..fbd7f48f66bd93da02e9d44cd51d47feae0e2015 100644 (file)
@@ -3,4 +3,5 @@ fn main() {
     let (a,) = ();
     let (..) = ();
     let () = ();
+    let (| a | a, | b) = ((),());
 }
index 5746eac0b3790923886a9d90f020743c9cc44a38..e39026ac70bfd52e4d78b7b6a08a85d6938306ac 100644 (file)
@@ -24,7 +24,6 @@ tt = { path = "../tt", version = "0.0.0" }
 mbe = { path = "../mbe", version = "0.0.0" }
 paths = { path = "../paths", version = "0.0.0" }
 proc-macro-api = { path = "../proc-macro-api", version = "0.0.0" }
-crossbeam = "0.8.1"
 
 [dev-dependencies]
 expect-test = "1.4.0"
index 52eb7ce17d6aeb482d41846a7781b0601ff8131a..e4e43e97dde82eee29821dfb138cc75d14f7f297 100644 (file)
@@ -37,23 +37,6 @@ pub struct SourceFile {
 type Level = super::proc_macro::Level;
 type LineColumn = super::proc_macro::LineColumn;
 
-/// A structure representing a diagnostic message and associated children
-/// messages.
-#[derive(Clone, Debug)]
-pub struct Diagnostic {
-    level: Level,
-    message: String,
-    spans: Vec<Span>,
-    children: Vec<Diagnostic>,
-}
-
-impl Diagnostic {
-    /// Creates a new diagnostic with the given `level` and `message`.
-    pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
-        Diagnostic { level, message: message.into(), spans: vec![], children: vec![] }
-    }
-}
-
 pub struct FreeFunctions;
 
 #[derive(Default)]
@@ -65,8 +48,6 @@ impl server::Types for RustAnalyzer {
     type FreeFunctions = FreeFunctions;
     type TokenStream = TokenStream;
     type SourceFile = SourceFile;
-    type MultiSpan = Vec<Span>;
-    type Diagnostic = Diagnostic;
     type Span = Span;
     type Symbol = Symbol;
 }
@@ -90,6 +71,10 @@ fn literal_from_str(
             span: tt::TokenId::unspecified(),
         })
     }
+
+    fn emit_diagnostic(&mut self, _: bridge::Diagnostic<Self::Span>) {
+        // FIXME handle diagnostic
+    }
 }
 
 impl server::TokenStream for RustAnalyzer {
@@ -282,30 +267,6 @@ fn is_real(&mut self, _file: &Self::SourceFile) -> bool {
     }
 }
 
-impl server::Diagnostic for RustAnalyzer {
-    fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
-        let mut diag = Diagnostic::new(level, msg);
-        diag.spans = spans;
-        diag
-    }
-
-    fn sub(
-        &mut self,
-        _diag: &mut Self::Diagnostic,
-        _level: Level,
-        _msg: &str,
-        _spans: Self::MultiSpan,
-    ) {
-        // FIXME handle diagnostic
-        //
-    }
-
-    fn emit(&mut self, _diag: Self::Diagnostic) {
-        // FIXME handle diagnostic
-        // diag.emit()
-    }
-}
-
 impl server::Span for RustAnalyzer {
     fn debug(&mut self, span: Self::Span) -> String {
         format!("{:?}", span.0)
@@ -372,18 +333,6 @@ fn before(&mut self, _self_: Self::Span) -> Self::Span {
     }
 }
 
-impl server::MultiSpan for RustAnalyzer {
-    fn new(&mut self) -> Self::MultiSpan {
-        // FIXME handle span
-        vec![]
-    }
-
-    fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) {
-        //TODP
-        other.push(span)
-    }
-}
-
 impl server::Symbol for RustAnalyzer {
     fn normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> {
         // FIXME: nfc-normalize and validate idents
index 4c205b9cadac3abd8311f9a7c1ae4d4f113f1b63..3679bfc43c980a85a40909698dbe9fc7f27f9715 100644 (file)
@@ -26,6 +26,7 @@
     ffi::OsString,
     fs,
     path::{Path, PathBuf},
+    thread,
     time::SystemTime,
 };
 
@@ -65,18 +66,16 @@ pub fn expand(&mut self, task: ExpandMacro) -> Result<FlatTree, PanicMessage> {
 
         let macro_body = task.macro_body.to_subtree();
         let attributes = task.attributes.map(|it| it.to_subtree());
-        // FIXME: replace this with std's scoped threads once they stabilize
-        // (then remove dependency on crossbeam)
-        let result = crossbeam::scope(|s| {
-            let res = match s
-                .builder()
+        let result = thread::scope(|s| {
+            let thread = thread::Builder::new()
                 .stack_size(EXPANDER_STACK_SIZE)
                 .name(task.macro_name.clone())
-                .spawn(|_| {
+                .spawn_scoped(s, || {
                     expander
                         .expand(&task.macro_name, &macro_body, attributes.as_ref())
                         .map(|it| FlatTree::new(&it))
-                }) {
+                });
+            let res = match thread {
                 Ok(handle) => handle.join(),
                 Err(e) => std::panic::resume_unwind(Box::new(e)),
             };
@@ -86,10 +85,6 @@ pub fn expand(&mut self, task: ExpandMacro) -> Result<FlatTree, PanicMessage> {
                 Err(e) => std::panic::resume_unwind(e),
             }
         });
-        let result = match result {
-            Ok(result) => result,
-            Err(e) => std::panic::resume_unwind(e),
-        };
 
         prev_env.rollback();
 
index 8d0fa757c2e176baf6c0904927bfe252a9e4772d..9ccb6e9101ef440c4604350b1901060375df66ae 100644 (file)
@@ -185,10 +185,10 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        2,
+                        1,
                     ): CrateData {
                         root_file_id: FileId(
-                            3,
+                            2,
                         ),
                         edition: Edition2018,
                         version: Some(
@@ -197,9 +197,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "an_example",
+                                    "hello_world",
                                 ),
-                                canonical_name: "an-example",
+                                canonical_name: "hello-world",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -260,77 +260,85 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        4,
+                        2,
                     ): CrateData {
                         root_file_id: FileId(
-                            5,
+                            3,
                         ),
-                        edition: Edition2015,
+                        edition: Edition2018,
                         version: Some(
-                            "0.2.98",
+                            "0.1.0",
                         ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "libc",
+                                    "an_example",
                                 ),
-                                canonical_name: "libc",
+                                canonical_name: "an-example",
                             },
                         ),
                         cfg_options: CfgOptions(
                             [
                                 "debug_assertions",
-                                "feature=default",
-                                "feature=std",
                             ],
                         ),
                         potential_cfg_options: CfgOptions(
                             [
                                 "debug_assertions",
-                                "feature=align",
-                                "feature=const-extern-fn",
-                                "feature=default",
-                                "feature=extra_traits",
-                                "feature=rustc-dep-of-std",
-                                "feature=std",
-                                "feature=use_std",
                             ],
                         ),
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
                                 "CARGO_PKG_VERSION_MAJOR": "0",
-                                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
-                                "CARGO_PKG_VERSION": "0.2.98",
+                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                                "CARGO_PKG_VERSION": "0.1.0",
                                 "CARGO_PKG_AUTHORS": "",
-                                "CARGO_CRATE_NAME": "libc",
+                                "CARGO_CRATE_NAME": "hello_world",
                                 "CARGO_PKG_LICENSE_FILE": "",
                                 "CARGO_PKG_HOMEPAGE": "",
                                 "CARGO_PKG_DESCRIPTION": "",
-                                "CARGO_PKG_NAME": "libc",
-                                "CARGO_PKG_VERSION_PATCH": "98",
+                                "CARGO_PKG_NAME": "hello-world",
+                                "CARGO_PKG_VERSION_PATCH": "0",
                                 "CARGO": "cargo",
                                 "CARGO_PKG_REPOSITORY": "",
-                                "CARGO_PKG_VERSION_MINOR": "2",
+                                "CARGO_PKG_VERSION_MINOR": "1",
                                 "CARGO_PKG_VERSION_PRE": "",
                             },
                         },
-                        dependencies: [],
+                        dependencies: [
+                            Dependency {
+                                crate_id: CrateId(
+                                    0,
+                                ),
+                                name: CrateName(
+                                    "hello_world",
+                                ),
+                                prelude: true,
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    4,
+                                ),
+                                name: CrateName(
+                                    "libc",
+                                ),
+                                prelude: true,
+                            },
+                        ],
                         proc_macro: Err(
                             "crate has not (yet) been built",
                         ),
                         origin: CratesIo {
-                            repo: Some(
-                                "https://github.com/rust-lang/libc",
-                            ),
+                            repo: None,
                         },
                         is_proc_macro: false,
                     },
                     CrateId(
-                        1,
+                        3,
                     ): CrateData {
                         root_file_id: FileId(
-                            2,
+                            4,
                         ),
                         edition: Edition2018,
                         version: Some(
@@ -339,9 +347,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "hello_world",
+                                    "it",
                                 ),
-                                canonical_name: "hello-world",
+                                canonical_name: "it",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -402,77 +410,69 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        3,
+                        4,
                     ): CrateData {
                         root_file_id: FileId(
-                            4,
+                            5,
                         ),
-                        edition: Edition2018,
+                        edition: Edition2015,
                         version: Some(
-                            "0.1.0",
+                            "0.2.98",
                         ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "it",
+                                    "libc",
                                 ),
-                                canonical_name: "it",
+                                canonical_name: "libc",
                             },
                         ),
                         cfg_options: CfgOptions(
                             [
                                 "debug_assertions",
+                                "feature=default",
+                                "feature=std",
                             ],
                         ),
                         potential_cfg_options: CfgOptions(
                             [
                                 "debug_assertions",
+                                "feature=align",
+                                "feature=const-extern-fn",
+                                "feature=default",
+                                "feature=extra_traits",
+                                "feature=rustc-dep-of-std",
+                                "feature=std",
+                                "feature=use_std",
                             ],
                         ),
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
                                 "CARGO_PKG_VERSION_MAJOR": "0",
-                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
-                                "CARGO_PKG_VERSION": "0.1.0",
+                                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+                                "CARGO_PKG_VERSION": "0.2.98",
                                 "CARGO_PKG_AUTHORS": "",
-                                "CARGO_CRATE_NAME": "hello_world",
+                                "CARGO_CRATE_NAME": "libc",
                                 "CARGO_PKG_LICENSE_FILE": "",
                                 "CARGO_PKG_HOMEPAGE": "",
                                 "CARGO_PKG_DESCRIPTION": "",
-                                "CARGO_PKG_NAME": "hello-world",
-                                "CARGO_PKG_VERSION_PATCH": "0",
+                                "CARGO_PKG_NAME": "libc",
+                                "CARGO_PKG_VERSION_PATCH": "98",
                                 "CARGO": "cargo",
                                 "CARGO_PKG_REPOSITORY": "",
-                                "CARGO_PKG_VERSION_MINOR": "1",
+                                "CARGO_PKG_VERSION_MINOR": "2",
                                 "CARGO_PKG_VERSION_PRE": "",
                             },
                         },
-                        dependencies: [
-                            Dependency {
-                                crate_id: CrateId(
-                                    0,
-                                ),
-                                name: CrateName(
-                                    "hello_world",
-                                ),
-                                prelude: true,
-                            },
-                            Dependency {
-                                crate_id: CrateId(
-                                    4,
-                                ),
-                                name: CrateName(
-                                    "libc",
-                                ),
-                                prelude: true,
-                            },
-                        ],
+                        dependencies: [],
                         proc_macro: Err(
                             "crate has not (yet) been built",
                         ),
                         origin: CratesIo {
-                            repo: None,
+                            repo: Some(
+                                "https://github.com/rust-lang/libc",
+                            ),
                         },
                         is_proc_macro: false,
                     },
@@ -567,10 +567,10 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        2,
+                        1,
                     ): CrateData {
                         root_file_id: FileId(
-                            3,
+                            2,
                         ),
                         edition: Edition2018,
                         version: Some(
@@ -579,9 +579,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "an_example",
+                                    "hello_world",
                                 ),
-                                canonical_name: "an-example",
+                                canonical_name: "hello-world",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -644,77 +644,10 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        4,
-                    ): CrateData {
-                        root_file_id: FileId(
-                            5,
-                        ),
-                        edition: Edition2015,
-                        version: Some(
-                            "0.2.98",
-                        ),
-                        display_name: Some(
-                            CrateDisplayName {
-                                crate_name: CrateName(
-                                    "libc",
-                                ),
-                                canonical_name: "libc",
-                            },
-                        ),
-                        cfg_options: CfgOptions(
-                            [
-                                "debug_assertions",
-                                "feature=default",
-                                "feature=std",
-                            ],
-                        ),
-                        potential_cfg_options: CfgOptions(
-                            [
-                                "debug_assertions",
-                                "feature=align",
-                                "feature=const-extern-fn",
-                                "feature=default",
-                                "feature=extra_traits",
-                                "feature=rustc-dep-of-std",
-                                "feature=std",
-                                "feature=use_std",
-                            ],
-                        ),
-                        env: Env {
-                            entries: {
-                                "CARGO_PKG_LICENSE": "",
-                                "CARGO_PKG_VERSION_MAJOR": "0",
-                                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
-                                "CARGO_PKG_VERSION": "0.2.98",
-                                "CARGO_PKG_AUTHORS": "",
-                                "CARGO_CRATE_NAME": "libc",
-                                "CARGO_PKG_LICENSE_FILE": "",
-                                "CARGO_PKG_HOMEPAGE": "",
-                                "CARGO_PKG_DESCRIPTION": "",
-                                "CARGO_PKG_NAME": "libc",
-                                "CARGO_PKG_VERSION_PATCH": "98",
-                                "CARGO": "cargo",
-                                "CARGO_PKG_REPOSITORY": "",
-                                "CARGO_PKG_VERSION_MINOR": "2",
-                                "CARGO_PKG_VERSION_PRE": "",
-                            },
-                        },
-                        dependencies: [],
-                        proc_macro: Err(
-                            "crate has not (yet) been built",
-                        ),
-                        origin: CratesIo {
-                            repo: Some(
-                                "https://github.com/rust-lang/libc",
-                            ),
-                        },
-                        is_proc_macro: false,
-                    },
-                    CrateId(
-                        1,
+                        2,
                     ): CrateData {
                         root_file_id: FileId(
-                            2,
+                            3,
                         ),
                         edition: Edition2018,
                         version: Some(
@@ -723,9 +656,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "hello_world",
+                                    "an_example",
                                 ),
-                                canonical_name: "hello-world",
+                                canonical_name: "an-example",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -864,92 +797,91 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                         },
                         is_proc_macro: false,
                     },
-                },
-            }"#]],
-    )
-}
-
-#[test]
-fn cargo_hello_world_project_model() {
-    let crate_graph = load_cargo("hello-world-metadata.json");
-    check_crate_graph(
-        crate_graph,
-        expect![[r#"
-            CrateGraph {
-                arena: {
                     CrateId(
-                        0,
+                        4,
                     ): CrateData {
                         root_file_id: FileId(
-                            1,
+                            5,
                         ),
-                        edition: Edition2018,
+                        edition: Edition2015,
                         version: Some(
-                            "0.1.0",
+                            "0.2.98",
                         ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "hello_world",
+                                    "libc",
                                 ),
-                                canonical_name: "hello-world",
+                                canonical_name: "libc",
                             },
                         ),
                         cfg_options: CfgOptions(
                             [
                                 "debug_assertions",
-                                "test",
+                                "feature=default",
+                                "feature=std",
                             ],
                         ),
                         potential_cfg_options: CfgOptions(
                             [
                                 "debug_assertions",
-                                "test",
+                                "feature=align",
+                                "feature=const-extern-fn",
+                                "feature=default",
+                                "feature=extra_traits",
+                                "feature=rustc-dep-of-std",
+                                "feature=std",
+                                "feature=use_std",
                             ],
                         ),
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
                                 "CARGO_PKG_VERSION_MAJOR": "0",
-                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
-                                "CARGO_PKG_VERSION": "0.1.0",
+                                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+                                "CARGO_PKG_VERSION": "0.2.98",
                                 "CARGO_PKG_AUTHORS": "",
-                                "CARGO_CRATE_NAME": "hello_world",
+                                "CARGO_CRATE_NAME": "libc",
                                 "CARGO_PKG_LICENSE_FILE": "",
                                 "CARGO_PKG_HOMEPAGE": "",
                                 "CARGO_PKG_DESCRIPTION": "",
-                                "CARGO_PKG_NAME": "hello-world",
-                                "CARGO_PKG_VERSION_PATCH": "0",
+                                "CARGO_PKG_NAME": "libc",
+                                "CARGO_PKG_VERSION_PATCH": "98",
                                 "CARGO": "cargo",
                                 "CARGO_PKG_REPOSITORY": "",
-                                "CARGO_PKG_VERSION_MINOR": "1",
+                                "CARGO_PKG_VERSION_MINOR": "2",
                                 "CARGO_PKG_VERSION_PRE": "",
                             },
                         },
-                        dependencies: [
-                            Dependency {
-                                crate_id: CrateId(
-                                    4,
-                                ),
-                                name: CrateName(
-                                    "libc",
-                                ),
-                                prelude: true,
-                            },
-                        ],
+                        dependencies: [],
                         proc_macro: Err(
                             "crate has not (yet) been built",
                         ),
                         origin: CratesIo {
-                            repo: None,
+                            repo: Some(
+                                "https://github.com/rust-lang/libc",
+                            ),
                         },
                         is_proc_macro: false,
                     },
+                },
+            }"#]],
+    )
+}
+
+#[test]
+fn cargo_hello_world_project_model() {
+    let crate_graph = load_cargo("hello-world-metadata.json");
+    check_crate_graph(
+        crate_graph,
+        expect![[r#"
+            CrateGraph {
+                arena: {
                     CrateId(
-                        2,
+                        0,
                     ): CrateData {
                         root_file_id: FileId(
-                            3,
+                            1,
                         ),
                         edition: Edition2018,
                         version: Some(
@@ -958,9 +890,9 @@ fn cargo_hello_world_project_model() {
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "an_example",
+                                    "hello_world",
                                 ),
-                                canonical_name: "an-example",
+                                canonical_name: "hello-world",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -995,15 +927,6 @@ fn cargo_hello_world_project_model() {
                             },
                         },
                         dependencies: [
-                            Dependency {
-                                crate_id: CrateId(
-                                    0,
-                                ),
-                                name: CrateName(
-                                    "hello_world",
-                                ),
-                                prelude: true,
-                            },
                             Dependency {
                                 crate_id: CrateId(
                                     4,
@@ -1023,77 +946,87 @@ fn cargo_hello_world_project_model() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        4,
+                        1,
                     ): CrateData {
                         root_file_id: FileId(
-                            5,
+                            2,
                         ),
-                        edition: Edition2015,
+                        edition: Edition2018,
                         version: Some(
-                            "0.2.98",
+                            "0.1.0",
                         ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "libc",
+                                    "hello_world",
                                 ),
-                                canonical_name: "libc",
+                                canonical_name: "hello-world",
                             },
                         ),
                         cfg_options: CfgOptions(
                             [
                                 "debug_assertions",
-                                "feature=default",
-                                "feature=std",
+                                "test",
                             ],
                         ),
                         potential_cfg_options: CfgOptions(
                             [
                                 "debug_assertions",
-                                "feature=align",
-                                "feature=const-extern-fn",
-                                "feature=default",
-                                "feature=extra_traits",
-                                "feature=rustc-dep-of-std",
-                                "feature=std",
-                                "feature=use_std",
+                                "test",
                             ],
                         ),
                         env: Env {
                             entries: {
                                 "CARGO_PKG_LICENSE": "",
                                 "CARGO_PKG_VERSION_MAJOR": "0",
-                                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
-                                "CARGO_PKG_VERSION": "0.2.98",
+                                "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                                "CARGO_PKG_VERSION": "0.1.0",
                                 "CARGO_PKG_AUTHORS": "",
-                                "CARGO_CRATE_NAME": "libc",
+                                "CARGO_CRATE_NAME": "hello_world",
                                 "CARGO_PKG_LICENSE_FILE": "",
                                 "CARGO_PKG_HOMEPAGE": "",
                                 "CARGO_PKG_DESCRIPTION": "",
-                                "CARGO_PKG_NAME": "libc",
-                                "CARGO_PKG_VERSION_PATCH": "98",
+                                "CARGO_PKG_NAME": "hello-world",
+                                "CARGO_PKG_VERSION_PATCH": "0",
                                 "CARGO": "cargo",
                                 "CARGO_PKG_REPOSITORY": "",
-                                "CARGO_PKG_VERSION_MINOR": "2",
+                                "CARGO_PKG_VERSION_MINOR": "1",
                                 "CARGO_PKG_VERSION_PRE": "",
                             },
                         },
-                        dependencies: [],
+                        dependencies: [
+                            Dependency {
+                                crate_id: CrateId(
+                                    0,
+                                ),
+                                name: CrateName(
+                                    "hello_world",
+                                ),
+                                prelude: true,
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    4,
+                                ),
+                                name: CrateName(
+                                    "libc",
+                                ),
+                                prelude: true,
+                            },
+                        ],
                         proc_macro: Err(
                             "crate has not (yet) been built",
                         ),
                         origin: CratesIo {
-                            repo: Some(
-                                "https://github.com/rust-lang/libc",
-                            ),
+                            repo: None,
                         },
                         is_proc_macro: false,
                     },
                     CrateId(
-                        1,
+                        2,
                     ): CrateData {
                         root_file_id: FileId(
-                            2,
+                            3,
                         ),
                         edition: Edition2018,
                         version: Some(
@@ -1102,9 +1035,9 @@ fn cargo_hello_world_project_model() {
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "hello_world",
+                                    "an_example",
                                 ),
-                                canonical_name: "hello-world",
+                                canonical_name: "an-example",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -1243,6 +1176,73 @@ fn cargo_hello_world_project_model() {
                         },
                         is_proc_macro: false,
                     },
+                    CrateId(
+                        4,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            5,
+                        ),
+                        edition: Edition2015,
+                        version: Some(
+                            "0.2.98",
+                        ),
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "libc",
+                                ),
+                                canonical_name: "libc",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [
+                                "debug_assertions",
+                                "feature=default",
+                                "feature=std",
+                            ],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [
+                                "debug_assertions",
+                                "feature=align",
+                                "feature=const-extern-fn",
+                                "feature=default",
+                                "feature=extra_traits",
+                                "feature=rustc-dep-of-std",
+                                "feature=std",
+                                "feature=use_std",
+                            ],
+                        ),
+                        env: Env {
+                            entries: {
+                                "CARGO_PKG_LICENSE": "",
+                                "CARGO_PKG_VERSION_MAJOR": "0",
+                                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+                                "CARGO_PKG_VERSION": "0.2.98",
+                                "CARGO_PKG_AUTHORS": "",
+                                "CARGO_CRATE_NAME": "libc",
+                                "CARGO_PKG_LICENSE_FILE": "",
+                                "CARGO_PKG_HOMEPAGE": "",
+                                "CARGO_PKG_DESCRIPTION": "",
+                                "CARGO_PKG_NAME": "libc",
+                                "CARGO_PKG_VERSION_PATCH": "98",
+                                "CARGO": "cargo",
+                                "CARGO_PKG_REPOSITORY": "",
+                                "CARGO_PKG_VERSION_MINOR": "2",
+                                "CARGO_PKG_VERSION_PRE": "",
+                            },
+                        },
+                        dependencies: [],
+                        proc_macro: Err(
+                            "crate has not (yet) been built",
+                        ),
+                        origin: CratesIo {
+                            repo: Some(
+                                "https://github.com/rust-lang/libc",
+                            ),
+                        },
+                        is_proc_macro: false,
+                    },
                 },
             }"#]],
     )
@@ -1301,19 +1301,53 @@ fn rust_project_hello_world_project_model() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        10,
+                        1,
                     ): CrateData {
                         root_file_id: FileId(
-                            11,
+                            2,
                         ),
                         edition: Edition2018,
                         version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "unwind",
+                                    "core",
                                 ),
-                                canonical_name: "unwind",
+                                canonical_name: "core",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [],
+                        proc_macro: Err(
+                            "no proc macro loaded for sysroot crate",
+                        ),
+                        origin: Lang(
+                            Core,
+                        ),
+                        is_proc_macro: false,
+                    },
+                    CrateId(
+                        2,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            3,
+                        ),
+                        edition: Edition2018,
+                        version: None,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "panic_abort",
+                                ),
+                                canonical_name: "panic_abort",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -1335,19 +1369,19 @@ fn rust_project_hello_world_project_model() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        7,
+                        3,
                     ): CrateData {
                         root_file_id: FileId(
-                            8,
+                            4,
                         ),
                         edition: Edition2018,
                         version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "std_detect",
+                                    "panic_unwind",
                                 ),
-                                canonical_name: "std_detect",
+                                canonical_name: "panic_unwind",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -1413,19 +1447,19 @@ fn rust_project_hello_world_project_model() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        1,
+                        5,
                     ): CrateData {
                         root_file_id: FileId(
-                            2,
+                            6,
                         ),
                         edition: Edition2018,
                         version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "core",
+                                    "profiler_builtins",
                                 ),
-                                canonical_name: "core",
+                                canonical_name: "profiler_builtins",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -1442,24 +1476,24 @@ fn rust_project_hello_world_project_model() {
                             "no proc macro loaded for sysroot crate",
                         ),
                         origin: Lang(
-                            Core,
+                            Other,
                         ),
                         is_proc_macro: false,
                     },
                     CrateId(
-                        11,
+                        6,
                     ): CrateData {
                         root_file_id: FileId(
-                            12,
+                            7,
                         ),
                         edition: Edition2018,
                         version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "hello_world",
+                                    "std",
                                 ),
-                                canonical_name: "hello_world",
+                                canonical_name: "std",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -1472,6 +1506,15 @@ fn rust_project_hello_world_project_model() {
                             entries: {},
                         },
                         dependencies: [
+                            Dependency {
+                                crate_id: CrateId(
+                                    0,
+                                ),
+                                name: CrateName(
+                                    "alloc",
+                                ),
+                                prelude: true,
+                            },
                             Dependency {
                                 crate_id: CrateId(
                                     1,
@@ -1483,19 +1526,46 @@ fn rust_project_hello_world_project_model() {
                             },
                             Dependency {
                                 crate_id: CrateId(
-                                    0,
+                                    2,
                                 ),
                                 name: CrateName(
-                                    "alloc",
+                                    "panic_abort",
                                 ),
                                 prelude: true,
                             },
                             Dependency {
                                 crate_id: CrateId(
-                                    6,
+                                    3,
                                 ),
                                 name: CrateName(
-                                    "std",
+                                    "panic_unwind",
+                                ),
+                                prelude: true,
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    5,
+                                ),
+                                name: CrateName(
+                                    "profiler_builtins",
+                                ),
+                                prelude: true,
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    7,
+                                ),
+                                name: CrateName(
+                                    "std_detect",
+                                ),
+                                prelude: true,
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    8,
+                                ),
+                                name: CrateName(
+                                    "term",
                                 ),
                                 prelude: true,
                             },
@@ -1506,31 +1576,40 @@ fn rust_project_hello_world_project_model() {
                                 name: CrateName(
                                     "test",
                                 ),
-                                prelude: false,
+                                prelude: true,
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    10,
+                                ),
+                                name: CrateName(
+                                    "unwind",
+                                ),
+                                prelude: true,
                             },
                         ],
                         proc_macro: Err(
-                            "no proc macro dylib present",
+                            "no proc macro loaded for sysroot crate",
+                        ),
+                        origin: Lang(
+                            Std,
                         ),
-                        origin: CratesIo {
-                            repo: None,
-                        },
                         is_proc_macro: false,
                     },
                     CrateId(
-                        8,
+                        7,
                     ): CrateData {
                         root_file_id: FileId(
-                            9,
+                            8,
                         ),
                         edition: Edition2018,
                         version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "term",
+                                    "std_detect",
                                 ),
-                                canonical_name: "term",
+                                canonical_name: "std_detect",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -1552,19 +1631,19 @@ fn rust_project_hello_world_project_model() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        5,
+                        8,
                     ): CrateData {
                         root_file_id: FileId(
-                            6,
+                            9,
                         ),
                         edition: Edition2018,
                         version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "profiler_builtins",
+                                    "term",
                                 ),
-                                canonical_name: "profiler_builtins",
+                                canonical_name: "term",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -1586,19 +1665,19 @@ fn rust_project_hello_world_project_model() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        2,
+                        9,
                     ): CrateData {
                         root_file_id: FileId(
-                            3,
+                            10,
                         ),
                         edition: Edition2018,
                         version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "panic_abort",
+                                    "test",
                                 ),
-                                canonical_name: "panic_abort",
+                                canonical_name: "test",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -1615,24 +1694,24 @@ fn rust_project_hello_world_project_model() {
                             "no proc macro loaded for sysroot crate",
                         ),
                         origin: Lang(
-                            Other,
+                            Test,
                         ),
                         is_proc_macro: false,
                     },
                     CrateId(
-                        9,
+                        10,
                     ): CrateData {
                         root_file_id: FileId(
-                            10,
+                            11,
                         ),
                         edition: Edition2018,
                         version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "test",
+                                    "unwind",
                                 ),
-                                canonical_name: "test",
+                                canonical_name: "unwind",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -1649,24 +1728,24 @@ fn rust_project_hello_world_project_model() {
                             "no proc macro loaded for sysroot crate",
                         ),
                         origin: Lang(
-                            Test,
+                            Other,
                         ),
                         is_proc_macro: false,
                     },
                     CrateId(
-                        6,
+                        11,
                     ): CrateData {
                         root_file_id: FileId(
-                            7,
+                            12,
                         ),
                         edition: Edition2018,
                         version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "std",
+                                    "hello_world",
                                 ),
-                                canonical_name: "std",
+                                canonical_name: "hello_world",
                             },
                         ),
                         cfg_options: CfgOptions(
@@ -1679,15 +1758,6 @@ fn rust_project_hello_world_project_model() {
                             entries: {},
                         },
                         dependencies: [
-                            Dependency {
-                                crate_id: CrateId(
-                                    0,
-                                ),
-                                name: CrateName(
-                                    "alloc",
-                                ),
-                                prelude: true,
-                            },
                             Dependency {
                                 crate_id: CrateId(
                                     1,
@@ -1699,46 +1769,19 @@ fn rust_project_hello_world_project_model() {
                             },
                             Dependency {
                                 crate_id: CrateId(
-                                    2,
-                                ),
-                                name: CrateName(
-                                    "panic_abort",
-                                ),
-                                prelude: true,
-                            },
-                            Dependency {
-                                crate_id: CrateId(
-                                    3,
-                                ),
-                                name: CrateName(
-                                    "panic_unwind",
-                                ),
-                                prelude: true,
-                            },
-                            Dependency {
-                                crate_id: CrateId(
-                                    5,
-                                ),
-                                name: CrateName(
-                                    "profiler_builtins",
-                                ),
-                                prelude: true,
-                            },
-                            Dependency {
-                                crate_id: CrateId(
-                                    7,
+                                    0,
                                 ),
                                 name: CrateName(
-                                    "std_detect",
+                                    "alloc",
                                 ),
                                 prelude: true,
                             },
                             Dependency {
                                 crate_id: CrateId(
-                                    8,
+                                    6,
                                 ),
                                 name: CrateName(
-                                    "term",
+                                    "std",
                                 ),
                                 prelude: true,
                             },
@@ -1749,58 +1792,15 @@ fn rust_project_hello_world_project_model() {
                                 name: CrateName(
                                     "test",
                                 ),
-                                prelude: true,
-                            },
-                            Dependency {
-                                crate_id: CrateId(
-                                    10,
-                                ),
-                                name: CrateName(
-                                    "unwind",
-                                ),
-                                prelude: true,
+                                prelude: false,
                             },
                         ],
                         proc_macro: Err(
-                            "no proc macro loaded for sysroot crate",
-                        ),
-                        origin: Lang(
-                            Std,
-                        ),
-                        is_proc_macro: false,
-                    },
-                    CrateId(
-                        3,
-                    ): CrateData {
-                        root_file_id: FileId(
-                            4,
-                        ),
-                        edition: Edition2018,
-                        version: None,
-                        display_name: Some(
-                            CrateDisplayName {
-                                crate_name: CrateName(
-                                    "panic_unwind",
-                                ),
-                                canonical_name: "panic_unwind",
-                            },
-                        ),
-                        cfg_options: CfgOptions(
-                            [],
-                        ),
-                        potential_cfg_options: CfgOptions(
-                            [],
+                            "no proc macro dylib present",
                         ),
-                        env: Env {
-                            entries: {},
+                        origin: CratesIo {
+                            repo: None,
                         },
-                        dependencies: [],
-                        proc_macro: Err(
-                            "no proc macro loaded for sysroot crate",
-                        ),
-                        origin: Lang(
-                            Other,
-                        ),
                         is_proc_macro: false,
                     },
                 },
index 8d6f50f5587c5ad0e8248702e66ba69c9187eced..818bbed6af2ec73600d2bde661d2f420d48969f7 100644 (file)
@@ -13,7 +13,7 @@
 use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
-use stdx::always;
+use stdx::{always, hash::NoHashHashMap};
 
 use crate::{
     build_scripts::BuildScriptOutput,
@@ -471,7 +471,7 @@ fn project_json_to_crate_graph(
         .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load));
 
     let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
-    let crates: FxHashMap<CrateId, CrateId> = project
+    let crates: NoHashHashMap<CrateId, CrateId> = project
         .crates()
         .filter_map(|(crate_id, krate)| {
             let file_path = &krate.root_module;
index 07771d1b392ce1a2481d08f2c156078ca20f07f6..5392589186d1db8bcb563f90808b16f29ebd79d9 100644 (file)
@@ -22,7 +22,8 @@ anyhow = "1.0.57"
 crossbeam-channel = "0.5.5"
 dissimilar = "1.0.4"
 itertools = "0.10.3"
-lsp-types = { version = "0.93.0", features = ["proposed"] }
+scip = "0.1.1"
+lsp-types = { version = "0.93.1", features = ["proposed"] }
 parking_lot = "0.12.1"
 xflags = "0.2.4"
 oorandom = "11.1.3"
@@ -88,5 +89,5 @@ in-rust-tree = [
     "proc-macro-srv/sysroot-abi",
     "sourcegen/in-rust-tree",
     "ide/in-rust-tree",
-    "syntax/in-rust-tree"
+    "syntax/in-rust-tree",
 ]
index e9de23cb395d1fbec1b2ceab4aa942618fedcd5f..f6a6802972525c09002f18bdc81bacb60a39d3dd 100644 (file)
@@ -93,6 +93,7 @@ fn try_main() -> Result<()> {
         flags::RustAnalyzerCmd::Ssr(cmd) => cmd.run()?,
         flags::RustAnalyzerCmd::Search(cmd) => cmd.run()?,
         flags::RustAnalyzerCmd::Lsif(cmd) => cmd.run()?,
+        flags::RustAnalyzerCmd::Scip(cmd) => cmd.run()?,
     }
     Ok(())
 }
index 6ccdaa86dd628786d33a9142e3b199f2dbd5bfa2..60ba67e25f93bc08679072f4a25de7bf10bdaf7c 100644 (file)
@@ -9,6 +9,7 @@
 mod diagnostics;
 mod ssr;
 mod lsif;
+mod scip;
 
 mod progress_report;
 
index 080e2fb4438816717f38985da19aa681cf0817ad..aa32654fbdca1efc3afc748e8ac59fb5b28e4c85 100644 (file)
         cmd lsif
             required path: PathBuf
         {}
+
+        cmd scip
+            required path: PathBuf
+        {}
     }
 }
 
@@ -140,6 +144,7 @@ pub enum RustAnalyzerCmd {
     Search(Search),
     ProcMacro(ProcMacro),
     Lsif(Lsif),
+    Scip(Scip),
 }
 
 #[derive(Debug)]
@@ -207,6 +212,11 @@ pub struct Lsif {
     pub path: PathBuf,
 }
 
+#[derive(Debug)]
+pub struct Scip {
+    pub path: PathBuf,
+}
+
 impl RustAnalyzer {
     pub const HELP: &'static str = Self::HELP_;
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
new file mode 100644 (file)
index 0000000..65cc993
--- /dev/null
@@ -0,0 +1,448 @@
+//! SCIP generator
+
+use std::{
+    collections::{HashMap, HashSet},
+    time::Instant,
+};
+
+use crate::line_index::{LineEndings, LineIndex, OffsetEncoding};
+use hir::Name;
+use ide::{
+    LineCol, MonikerDescriptorKind, MonikerResult, StaticIndex, StaticIndexedFile, TextRange,
+    TokenId,
+};
+use ide_db::LineIndexDatabase;
+use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
+use scip::types as scip_types;
+use std::env;
+
+use crate::cli::{
+    flags,
+    load_cargo::{load_workspace, LoadCargoConfig},
+    Result,
+};
+
+impl flags::Scip {
+    pub fn run(self) -> Result<()> {
+        eprintln!("Generating SCIP start...");
+        let now = Instant::now();
+        let cargo_config = CargoConfig::default();
+
+        let no_progress = &|s| (eprintln!("rust-analyzer: Loading {}", s));
+        let load_cargo_config = LoadCargoConfig {
+            load_out_dirs_from_check: true,
+            with_proc_macro: true,
+            prefill_caches: true,
+        };
+        let path = vfs::AbsPathBuf::assert(env::current_dir()?.join(&self.path));
+        let rootpath = path.normalize();
+        let manifest = ProjectManifest::discover_single(&path)?;
+
+        let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;
+
+        let (host, vfs, _) = load_workspace(workspace, &load_cargo_config)?;
+        let db = host.raw_database();
+        let analysis = host.analysis();
+
+        let si = StaticIndex::compute(&analysis);
+
+        let mut index = scip_types::Index {
+            metadata: Some(scip_types::Metadata {
+                version: scip_types::ProtocolVersion::UnspecifiedProtocolVersion.into(),
+                tool_info: Some(scip_types::ToolInfo {
+                    name: "rust-analyzer".to_owned(),
+                    version: "0.1".to_owned(),
+                    arguments: vec![],
+                    ..Default::default()
+                })
+                .into(),
+                project_root: format!(
+                    "file://{}",
+                    path.normalize()
+                        .as_os_str()
+                        .to_str()
+                        .ok_or(anyhow::anyhow!("Unable to normalize project_root path"))?
+                        .to_string()
+                ),
+                text_document_encoding: scip_types::TextEncoding::UTF8.into(),
+                ..Default::default()
+            })
+            .into(),
+            ..Default::default()
+        };
+
+        let mut symbols_emitted: HashSet<TokenId> = HashSet::default();
+        let mut tokens_to_symbol: HashMap<TokenId, String> = HashMap::new();
+
+        for file in si.files {
+            let mut local_count = 0;
+            let mut new_local_symbol = || {
+                let new_symbol = scip::types::Symbol::new_local(local_count);
+                local_count += 1;
+
+                new_symbol
+            };
+
+            let StaticIndexedFile { file_id, tokens, .. } = file;
+            let relative_path = match get_relative_filepath(&vfs, &rootpath, file_id) {
+                Some(relative_path) => relative_path,
+                None => continue,
+            };
+
+            let line_index = LineIndex {
+                index: db.line_index(file_id),
+                encoding: OffsetEncoding::Utf8,
+                endings: LineEndings::Unix,
+            };
+
+            let mut doc = scip_types::Document {
+                relative_path,
+                language: "rust".to_string(),
+                ..Default::default()
+            };
+
+            tokens.into_iter().for_each(|(range, id)| {
+                let token = si.tokens.get(id).unwrap();
+
+                let mut occurrence = scip_types::Occurrence::default();
+                occurrence.range = text_range_to_scip_range(&line_index, range);
+                occurrence.symbol = match tokens_to_symbol.get(&id) {
+                    Some(symbol) => symbol.clone(),
+                    None => {
+                        let symbol = match &token.moniker {
+                            Some(moniker) => moniker_to_symbol(&moniker),
+                            None => new_local_symbol(),
+                        };
+
+                        let symbol = scip::symbol::format_symbol(symbol);
+                        tokens_to_symbol.insert(id, symbol.clone());
+                        symbol
+                    }
+                };
+
+                if let Some(def) = token.definition {
+                    if def.range == range {
+                        occurrence.symbol_roles |= scip_types::SymbolRole::Definition as i32;
+                    }
+
+                    if !symbols_emitted.contains(&id) {
+                        symbols_emitted.insert(id);
+
+                        let mut symbol_info = scip_types::SymbolInformation::default();
+                        symbol_info.symbol = occurrence.symbol.clone();
+                        if let Some(hover) = &token.hover {
+                            if !hover.markup.as_str().is_empty() {
+                                symbol_info.documentation = vec![hover.markup.as_str().to_string()];
+                            }
+                        }
+
+                        doc.symbols.push(symbol_info)
+                    }
+                }
+
+                doc.occurrences.push(occurrence);
+            });
+
+            if doc.occurrences.is_empty() {
+                continue;
+            }
+
+            index.documents.push(doc);
+        }
+
+        scip::write_message_to_file("index.scip", index)
+            .map_err(|err| anyhow::anyhow!("Failed to write scip to file: {}", err))?;
+
+        eprintln!("Generating SCIP finished {:?}", now.elapsed());
+        Ok(())
+    }
+}
+
+fn get_relative_filepath(
+    vfs: &vfs::Vfs,
+    rootpath: &vfs::AbsPathBuf,
+    file_id: ide::FileId,
+) -> Option<String> {
+    Some(vfs.file_path(file_id).as_path()?.strip_prefix(&rootpath)?.as_ref().to_str()?.to_string())
+}
+
+// SCIP Ranges have a (very large) optimization that ranges if they are on the same line
+// only encode as a vector of [start_line, start_col, end_col].
+//
+// This transforms a line index into the optimized SCIP Range.
+fn text_range_to_scip_range(line_index: &LineIndex, range: TextRange) -> Vec<i32> {
+    let LineCol { line: start_line, col: start_col } = line_index.index.line_col(range.start());
+    let LineCol { line: end_line, col: end_col } = line_index.index.line_col(range.end());
+
+    if start_line == end_line {
+        vec![start_line as i32, start_col as i32, end_col as i32]
+    } else {
+        vec![start_line as i32, start_col as i32, end_line as i32, end_col as i32]
+    }
+}
+
+fn new_descriptor_str(
+    name: &str,
+    suffix: scip_types::descriptor::Suffix,
+) -> scip_types::Descriptor {
+    scip_types::Descriptor {
+        name: name.to_string(),
+        disambiguator: "".to_string(),
+        suffix: suffix.into(),
+        ..Default::default()
+    }
+}
+
+fn new_descriptor(name: Name, suffix: scip_types::descriptor::Suffix) -> scip_types::Descriptor {
+    let mut name = name.to_string();
+    if name.contains("'") {
+        name = format!("`{}`", name);
+    }
+
+    new_descriptor_str(name.as_str(), suffix)
+}
+
+/// Loosely based on `def_to_moniker`
+///
+/// Only returns a Symbol when it's a non-local symbol.
+///     So if the visibility isn't outside of a document, then it will return None
+fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol {
+    use scip_types::descriptor::Suffix::*;
+
+    let package_name = moniker.package_information.name.clone();
+    let version = moniker.package_information.version.clone();
+    let descriptors = moniker
+        .identifier
+        .description
+        .iter()
+        .map(|desc| {
+            new_descriptor(
+                desc.name.clone(),
+                match desc.desc {
+                    MonikerDescriptorKind::Namespace => Namespace,
+                    MonikerDescriptorKind::Type => Type,
+                    MonikerDescriptorKind::Term => Term,
+                    MonikerDescriptorKind::Method => Method,
+                    MonikerDescriptorKind::TypeParameter => TypeParameter,
+                    MonikerDescriptorKind::Parameter => Parameter,
+                    MonikerDescriptorKind::Macro => Macro,
+                    MonikerDescriptorKind::Meta => Meta,
+                },
+            )
+        })
+        .collect();
+
+    scip_types::Symbol {
+        scheme: "rust-analyzer".into(),
+        package: Some(scip_types::Package {
+            manager: "cargo".to_string(),
+            name: package_name,
+            version,
+            ..Default::default()
+        })
+        .into(),
+        descriptors,
+        ..Default::default()
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use hir::Semantics;
+    use ide::{AnalysisHost, FilePosition};
+    use ide_db::defs::IdentClass;
+    use ide_db::{base_db::fixture::ChangeFixture, helpers::pick_best_token};
+    use scip::symbol::format_symbol;
+    use syntax::SyntaxKind::*;
+    use syntax::{AstNode, T};
+
+    fn position(ra_fixture: &str) -> (AnalysisHost, FilePosition) {
+        let mut host = AnalysisHost::default();
+        let change_fixture = ChangeFixture::parse(ra_fixture);
+        host.raw_database_mut().apply_change(change_fixture.change);
+        let (file_id, range_or_offset) =
+            change_fixture.file_position.expect("expected a marker ($0)");
+        let offset = range_or_offset.expect_offset();
+        (host, FilePosition { file_id, offset })
+    }
+
+    /// If expected == "", then assert that there are no symbols (this is basically local symbol)
+    #[track_caller]
+    fn check_symbol(ra_fixture: &str, expected: &str) {
+        let (host, position) = position(ra_fixture);
+
+        let FilePosition { file_id, offset } = position;
+
+        let db = host.raw_database();
+        let sema = &Semantics::new(db);
+        let file = sema.parse(file_id).syntax().clone();
+        let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
+            IDENT
+            | INT_NUMBER
+            | LIFETIME_IDENT
+            | T![self]
+            | T![super]
+            | T![crate]
+            | T![Self]
+            | COMMENT => 2,
+            kind if kind.is_trivia() => 0,
+            _ => 1,
+        })
+        .expect("OK OK");
+
+        let navs = sema
+            .descend_into_macros(original_token.clone())
+            .into_iter()
+            .filter_map(|token| {
+                IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| {
+                    it.into_iter().flat_map(|def| {
+                        let module = def.module(db).unwrap();
+                        let current_crate = module.krate();
+
+                        match MonikerResult::from_def(sema.db, def, current_crate) {
+                            Some(moniker_result) => Some(moniker_to_symbol(&moniker_result)),
+                            None => None,
+                        }
+                    })
+                })
+            })
+            .flatten()
+            .collect::<Vec<_>>();
+
+        if expected == "" {
+            assert_eq!(0, navs.len(), "must have no symbols {:?}", navs);
+            return;
+        }
+
+        assert_eq!(1, navs.len(), "must have one symbol {:?}", navs);
+
+        let res = navs.get(0).unwrap();
+        let formatted = format_symbol(res.clone());
+        assert_eq!(formatted, expected);
+    }
+
+    #[test]
+    fn basic() {
+        check_symbol(
+            r#"
+//- /lib.rs crate:main deps:foo
+use foo::example_mod::func;
+fn main() {
+    func$0();
+}
+//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
+pub mod example_mod {
+    pub fn func() {}
+}
+"#,
+            "rust-analyzer cargo foo 0.1.0 example_mod/func().",
+        );
+    }
+
+    #[test]
+    fn symbol_for_trait() {
+        check_symbol(
+            r#"
+//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
+pub mod module {
+    pub trait MyTrait {
+        pub fn func$0() {}
+    }
+}
+"#,
+            "rust-analyzer cargo foo 0.1.0 module/MyTrait#func().",
+        );
+    }
+
+    #[test]
+    fn symbol_for_trait_constant() {
+        check_symbol(
+            r#"
+    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
+    pub mod module {
+        pub trait MyTrait {
+            const MY_CONST$0: u8;
+        }
+    }
+    "#,
+            "rust-analyzer cargo foo 0.1.0 module/MyTrait#MY_CONST.",
+        );
+    }
+
+    #[test]
+    fn symbol_for_trait_type() {
+        check_symbol(
+            r#"
+    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
+    pub mod module {
+        pub trait MyTrait {
+            type MyType$0;
+        }
+    }
+    "#,
+            // "foo::module::MyTrait::MyType",
+            "rust-analyzer cargo foo 0.1.0 module/MyTrait#[MyType]",
+        );
+    }
+
+    #[test]
+    fn symbol_for_trait_impl_function() {
+        check_symbol(
+            r#"
+    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
+    pub mod module {
+        pub trait MyTrait {
+            pub fn func() {}
+        }
+
+        struct MyStruct {}
+
+        impl MyTrait for MyStruct {
+            pub fn func$0() {}
+        }
+    }
+    "#,
+            // "foo::module::MyStruct::MyTrait::func",
+            "rust-analyzer cargo foo 0.1.0 module/MyStruct#MyTrait#func().",
+        );
+    }
+
+    #[test]
+    fn symbol_for_field() {
+        check_symbol(
+            r#"
+    //- /lib.rs crate:main deps:foo
+    use foo::St;
+    fn main() {
+        let x = St { a$0: 2 };
+    }
+    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
+    pub struct St {
+        pub a: i32,
+    }
+    "#,
+            "rust-analyzer cargo foo 0.1.0 St#a.",
+        );
+    }
+
+    #[test]
+    fn local_symbol_for_local() {
+        check_symbol(
+            r#"
+    //- /lib.rs crate:main deps:foo
+    use foo::module::func;
+    fn main() {
+        func();
+    }
+    //- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
+    pub mod module {
+        pub fn func() {
+            let x$0 = 2;
+        }
+    }
+    "#,
+            "",
+        );
+    }
+}
index 6649f42b4ef9e6cade85b71105ecda9b535dda32..54dcb42d99c789ea142e8873dee91d246114692e 100644 (file)
@@ -12,8 +12,8 @@
 use flycheck::FlycheckConfig;
 use ide::{
     AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
-    HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig, JoinLinesConfig,
-    Snippet, SnippetScope,
+    HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig,
+    JoinLinesConfig, Snippet, SnippetScope,
 };
 use ide_db::{
     imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
@@ -385,6 +385,34 @@ struct ConfigData {
         /// available on a nightly build.
         rustfmt_rangeFormatting_enable: bool = "false",
 
+        /// Inject additional highlighting into doc comments.
+        ///
+        /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra
+        /// doc links.
+        semanticHighlighting_doc_comment_inject_enable: bool = "true",
+        /// Use semantic tokens for operators.
+        ///
+        /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when
+        /// they are tagged with modifiers.
+        semanticHighlighting_operator_enable: bool = "true",
+        /// Use specialized semantic tokens for operators.
+        ///
+        /// When enabled, rust-analyzer will emit special token types for operator tokens instead
+        /// of the generic `operator` token type.
+        semanticHighlighting_operator_specialization_enable: bool = "false",
+        /// Use semantic tokens for punctuations.
+        ///
+        /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when
+        /// they are tagged with modifiers or have a special role.
+        semanticHighlighting_punctuation_enable: bool = "false",
+        /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro
+        /// calls.
+        semanticHighlighting_punctuation_separate_macro_bang: bool = "false",
+        /// Use specialized semantic tokens for punctuations.
+        ///
+        /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead
+        /// of the generic `punctuation` token type.
+        semanticHighlighting_punctuation_specialization_enable: bool = "false",
         /// Use semantic tokens for strings.
         ///
         /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars.
@@ -1171,8 +1199,19 @@ pub fn hover_actions(&self) -> HoverActionsConfig {
         }
     }
 
-    pub fn highlighting_strings(&self) -> bool {
-        self.data.semanticHighlighting_strings_enable
+    pub fn highlighting_config(&self) -> HighlightConfig {
+        HighlightConfig {
+            strings: self.data.semanticHighlighting_strings_enable,
+            punctuation: self.data.semanticHighlighting_punctuation_enable,
+            specialize_punctuation: self
+                .data
+                .semanticHighlighting_punctuation_specialization_enable,
+            macro_bang: self.data.semanticHighlighting_punctuation_separate_macro_bang,
+            operator: self.data.semanticHighlighting_operator_enable,
+            specialize_operator: self.data.semanticHighlighting_operator_specialization_enable,
+            inject_doc_comment: self.data.semanticHighlighting_doc_comment_inject_enable,
+            syntactic_name_ref_highlighting: false,
+        }
     }
 
     pub fn hover(&self) -> HoverConfig {
index 09150c77d7dd1d9de53adaff2a67382132e32711..f516c194da467f7afee60a4f123aeff25c06b26d 100644 (file)
@@ -4,11 +4,12 @@
 use std::{mem, sync::Arc};
 
 use ide::FileId;
-use rustc_hash::{FxHashMap, FxHashSet};
+use ide_db::FxHashMap;
+use stdx::hash::{NoHashHashMap, NoHashHashSet};
 
 use crate::lsp_ext;
 
-pub(crate) type CheckFixes = Arc<FxHashMap<usize, FxHashMap<FileId, Vec<Fix>>>>;
+pub(crate) type CheckFixes = Arc<NoHashHashMap<usize, NoHashHashMap<FileId, Vec<Fix>>>>;
 
 #[derive(Debug, Default, Clone)]
 pub struct DiagnosticsMapConfig {
@@ -19,12 +20,12 @@ pub struct DiagnosticsMapConfig {
 
 #[derive(Debug, Default, Clone)]
 pub(crate) struct DiagnosticCollection {
-    // FIXME: should be FxHashMap<FileId, Vec<ra_id::Diagnostic>>
-    pub(crate) native: FxHashMap<FileId, Vec<lsp_types::Diagnostic>>,
+    // FIXME: should be NoHashHashMap<FileId, Vec<ra_id::Diagnostic>>
+    pub(crate) native: NoHashHashMap<FileId, Vec<lsp_types::Diagnostic>>,
     // FIXME: should be Vec<flycheck::Diagnostic>
-    pub(crate) check: FxHashMap<usize, FxHashMap<FileId, Vec<lsp_types::Diagnostic>>>,
+    pub(crate) check: NoHashHashMap<usize, NoHashHashMap<FileId, Vec<lsp_types::Diagnostic>>>,
     pub(crate) check_fixes: CheckFixes,
-    changes: FxHashSet<FileId>,
+    changes: NoHashHashSet<FileId>,
 }
 
 #[derive(Debug, Clone)]
@@ -105,7 +106,7 @@ pub(crate) fn diagnostics_for(
         native.chain(check)
     }
 
-    pub(crate) fn take_changes(&mut self) -> Option<FxHashSet<FileId>> {
+    pub(crate) fn take_changes(&mut self) -> Option<NoHashHashSet<FileId>> {
         if self.changes.is_empty() {
             return None;
         }
index c55bbbbe6ef7c2c442e8593179daebe778e70303..706e1742dffde38a695d9119413849ad8fb497ac 100644 (file)
@@ -14,6 +14,7 @@
 use proc_macro_api::ProcMacroServer;
 use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
 use rustc_hash::FxHashMap;
+use stdx::hash::NoHashHashMap;
 use vfs::AnchoredPathBuf;
 
 use crate::{
@@ -67,7 +68,7 @@ pub(crate) struct GlobalState {
     pub(crate) flycheck_sender: Sender<flycheck::Message>,
     pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
 
-    pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
+    pub(crate) vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
     pub(crate) vfs_config_version: u32,
     pub(crate) vfs_progress_config_version: u32,
     pub(crate) vfs_progress_n_total: usize,
@@ -113,7 +114,7 @@ pub(crate) struct GlobalStateSnapshot {
     pub(crate) check_fixes: CheckFixes,
     mem_docs: MemDocs,
     pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
-    vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
+    vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
     pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
 }
 
@@ -157,7 +158,7 @@ pub(crate) fn new(sender: Sender<lsp_server::Message>, config: Config) -> Global
             flycheck_sender,
             flycheck_receiver,
 
-            vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
+            vfs: Arc::new(RwLock::new((vfs::Vfs::default(), NoHashHashMap::default()))),
             vfs_config_version: 0,
             vfs_progress_config_version: 0,
             vfs_progress_n_total: 0,
index e0bcc80b31cb9893192d53408f31b08f3fb34c8e..d89f0f5a3cf456d24c7889deec9355b3098e7a34 100644 (file)
@@ -1504,10 +1504,8 @@ 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(file_id)?;
-    let highlight_strings = snap.config.highlighting_strings();
-    let semantic_tokens =
-        to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings);
+    let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
+    let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 
     // Unconditionally cache the tokens
     snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens.clone());
@@ -1525,10 +1523,8 @@ 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(file_id)?;
-    let highlight_strings = snap.config.highlighting_strings();
-    let semantic_tokens =
-        to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings);
+    let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
+    let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 
     let mut cache = snap.semantic_tokens_cache.lock();
     let cached_tokens = cache.entry(params.text_document.uri).or_default();
@@ -1556,10 +1552,8 @@ pub(crate) fn handle_semantic_tokens_range(
     let text = snap.analysis.file_text(frange.file_id)?;
     let line_index = snap.file_line_index(frange.file_id)?;
 
-    let highlights = snap.analysis.highlight_range(frange)?;
-    let highlight_strings = snap.config.highlighting_strings();
-    let semantic_tokens =
-        to_proto::semantic_tokens(&text, &line_index, highlights, highlight_strings);
+    let highlights = snap.analysis.highlight_range(snap.config.highlighting_config(), frange)?;
+    let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
     Ok(Some(semantic_tokens.into()))
 }
 
index f187547019a13524416a7676c72c30e85fa748b9..3cfbc2e4e45037cbaefb2a5116987ba995bfaa3a 100644 (file)
@@ -328,8 +328,33 @@ fn handle_event(&mut self, event: Event) -> Result<()> {
                 }
 
                 let uri = file_id_to_url(&self.vfs.read().0, file_id);
-                let diagnostics =
+                let mut diagnostics =
                     self.diagnostics.diagnostics_for(file_id).cloned().collect::<Vec<_>>();
+
+                // VSCode assumes diagnostic messages to be non-empty strings, so we need to patch
+                // empty diagnostics. Neither the docs of VSCode nor the LSP spec say whether
+                // diagnostic messages are actually allowed to be empty or not and patching this
+                // in the VSCode client does not work as the assertion happens in the protocol
+                // conversion. So this hack is here to stay, and will be considered a hack
+                // until the LSP decides to state that empty messages are allowed.
+
+                // See https://github.com/rust-lang/rust-analyzer/issues/11404
+                // See https://github.com/rust-lang/rust-analyzer/issues/13130
+                let patch_empty = |message: &mut String| {
+                    if message.is_empty() {
+                        *message = " ".to_string();
+                    }
+                };
+
+                for d in &mut diagnostics {
+                    patch_empty(&mut d.message);
+                    if let Some(dri) = &mut d.related_information {
+                        for dri in dri {
+                            patch_empty(&mut dri.message);
+                        }
+                    }
+                }
+
                 let version = from_proto::vfs_path(&uri)
                     .map(|path| self.mem_docs.get(&path).map(|it| it.version))
                     .unwrap_or_default();
@@ -529,6 +554,13 @@ fn handle_flycheck_msg(&mut self, message: flycheck::Message) {
                     }
                     flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)),
                     flycheck::Progress::DidCancel => (Progress::End, None),
+                    flycheck::Progress::DidFailToRestart(err) => {
+                        self.show_and_log_error(
+                            "cargo check failed".to_string(),
+                            Some(err.to_string()),
+                        );
+                        return;
+                    }
                     flycheck::Progress::DidFinish(result) => {
                         if let Err(err) = result {
                             self.show_and_log_error(
index 6c78b5df1a7050472d9cacb304bb799792aa4ee0..c48410ed55e98472d4f0bc774703225e80048cad 100644 (file)
 };
 
 macro_rules! define_semantic_token_types {
-    ($(($ident:ident, $string:literal)),*$(,)?) => {
-        $(pub(crate) const $ident: SemanticTokenType = SemanticTokenType::new($string);)*
+    (
+        standard {
+            $($standard:ident),*$(,)?
+        }
+        custom {
+            $(($custom:ident, $string:literal)),*$(,)?
+        }
+
+    ) => {
+        $(pub(crate) const $standard: SemanticTokenType = SemanticTokenType::$standard;)*
+        $(pub(crate) const $custom: SemanticTokenType = SemanticTokenType::new($string);)*
 
         pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[
-            SemanticTokenType::COMMENT,
-            SemanticTokenType::KEYWORD,
-            SemanticTokenType::STRING,
-            SemanticTokenType::NUMBER,
-            SemanticTokenType::REGEXP,
-            SemanticTokenType::OPERATOR,
-            SemanticTokenType::NAMESPACE,
-            SemanticTokenType::TYPE,
-            SemanticTokenType::STRUCT,
-            SemanticTokenType::CLASS,
-            SemanticTokenType::INTERFACE,
-            SemanticTokenType::ENUM,
-            SemanticTokenType::ENUM_MEMBER,
-            SemanticTokenType::TYPE_PARAMETER,
-            SemanticTokenType::FUNCTION,
-            SemanticTokenType::METHOD,
-            SemanticTokenType::PROPERTY,
-            SemanticTokenType::MACRO,
-            SemanticTokenType::VARIABLE,
-            SemanticTokenType::PARAMETER,
-            $($ident),*
+            $(SemanticTokenType::$standard,)*
+            $($custom),*
         ];
     };
 }
 
 define_semantic_token_types![
-    (ANGLE, "angle"),
-    (ARITHMETIC, "arithmetic"),
-    (ATTRIBUTE, "attribute"),
-    (ATTRIBUTE_BRACKET, "attributeBracket"),
-    (BITWISE, "bitwise"),
-    (BOOLEAN, "boolean"),
-    (BRACE, "brace"),
-    (BRACKET, "bracket"),
-    (BUILTIN_ATTRIBUTE, "builtinAttribute"),
-    (BUILTIN_TYPE, "builtinType"),
-    (CHAR, "character"),
-    (COLON, "colon"),
-    (COMMA, "comma"),
-    (COMPARISON, "comparison"),
-    (CONST_PARAMETER, "constParameter"),
-    (DERIVE, "derive"),
-    (DERIVE_HELPER, "deriveHelper"),
-    (DOT, "dot"),
-    (ESCAPE_SEQUENCE, "escapeSequence"),
-    (FORMAT_SPECIFIER, "formatSpecifier"),
-    (GENERIC, "generic"),
-    (LABEL, "label"),
-    (LIFETIME, "lifetime"),
-    (LOGICAL, "logical"),
-    (MACRO_BANG, "macroBang"),
-    (OPERATOR, "operator"),
-    (PARENTHESIS, "parenthesis"),
-    (PUNCTUATION, "punctuation"),
-    (SELF_KEYWORD, "selfKeyword"),
-    (SELF_TYPE_KEYWORD, "selfTypeKeyword"),
-    (SEMICOLON, "semicolon"),
-    (TYPE_ALIAS, "typeAlias"),
-    (TOOL_MODULE, "toolModule"),
-    (UNION, "union"),
-    (UNRESOLVED_REFERENCE, "unresolvedReference"),
+    standard {
+        COMMENT,
+        DECORATOR,
+        ENUM_MEMBER,
+        ENUM,
+        FUNCTION,
+        INTERFACE,
+        KEYWORD,
+        MACRO,
+        METHOD,
+        NAMESPACE,
+        NUMBER,
+        OPERATOR,
+        PARAMETER,
+        PROPERTY,
+        STRING,
+        STRUCT,
+        TYPE_PARAMETER,
+        VARIABLE,
+    }
+
+    custom {
+        (ANGLE, "angle"),
+        (ARITHMETIC, "arithmetic"),
+        (ATTRIBUTE, "attribute"),
+        (ATTRIBUTE_BRACKET, "attributeBracket"),
+        (BITWISE, "bitwise"),
+        (BOOLEAN, "boolean"),
+        (BRACE, "brace"),
+        (BRACKET, "bracket"),
+        (BUILTIN_ATTRIBUTE, "builtinAttribute"),
+        (BUILTIN_TYPE, "builtinType"),
+        (CHAR, "character"),
+        (COLON, "colon"),
+        (COMMA, "comma"),
+        (COMPARISON, "comparison"),
+        (CONST_PARAMETER, "constParameter"),
+        (DERIVE, "derive"),
+        (DERIVE_HELPER, "deriveHelper"),
+        (DOT, "dot"),
+        (ESCAPE_SEQUENCE, "escapeSequence"),
+        (FORMAT_SPECIFIER, "formatSpecifier"),
+        (GENERIC, "generic"),
+        (LABEL, "label"),
+        (LIFETIME, "lifetime"),
+        (LOGICAL, "logical"),
+        (MACRO_BANG, "macroBang"),
+        (PARENTHESIS, "parenthesis"),
+        (PUNCTUATION, "punctuation"),
+        (SELF_KEYWORD, "selfKeyword"),
+        (SELF_TYPE_KEYWORD, "selfTypeKeyword"),
+        (SEMICOLON, "semicolon"),
+        (TYPE_ALIAS, "typeAlias"),
+        (TOOL_MODULE, "toolModule"),
+        (UNION, "union"),
+        (UNRESOLVED_REFERENCE, "unresolvedReference"),
+    }
 ];
 
 macro_rules! define_semantic_token_modifiers {
-    ($(($ident:ident, $string:literal)),*$(,)?) => {
-        $(pub(crate) const $ident: SemanticTokenModifier = SemanticTokenModifier::new($string);)*
+    (
+        standard {
+            $($standard:ident),*$(,)?
+        }
+        custom {
+            $(($custom:ident, $string:literal)),*$(,)?
+        }
+
+    ) => {
+
+        $(pub(crate) const $standard: SemanticTokenModifier = SemanticTokenModifier::$standard;)*
+        $(pub(crate) const $custom: SemanticTokenModifier = SemanticTokenModifier::new($string);)*
 
         pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[
-            SemanticTokenModifier::DOCUMENTATION,
-            SemanticTokenModifier::DECLARATION,
-            SemanticTokenModifier::DEFINITION,
-            SemanticTokenModifier::STATIC,
-            SemanticTokenModifier::ABSTRACT,
-            SemanticTokenModifier::DEPRECATED,
-            SemanticTokenModifier::READONLY,
-            SemanticTokenModifier::DEFAULT_LIBRARY,
-            $($ident),*
+            $(SemanticTokenModifier::$standard,)*
+            $($custom),*
         ];
     };
 }
 
 define_semantic_token_modifiers![
-    (ASYNC, "async"),
-    (ATTRIBUTE_MODIFIER, "attribute"),
-    (CALLABLE, "callable"),
-    (CONSTANT, "constant"),
-    (CONSUMING, "consuming"),
-    (CONTROL_FLOW, "controlFlow"),
-    (CRATE_ROOT, "crateRoot"),
-    (INJECTED, "injected"),
-    (INTRA_DOC_LINK, "intraDocLink"),
-    (LIBRARY, "library"),
-    (MUTABLE, "mutable"),
-    (PUBLIC, "public"),
-    (REFERENCE, "reference"),
-    (TRAIT_MODIFIER, "trait"),
-    (UNSAFE, "unsafe"),
+    standard {
+        DOCUMENTATION,
+        DECLARATION,
+        STATIC,
+        DEFAULT_LIBRARY,
+    }
+    custom {
+        (ASYNC, "async"),
+        (ATTRIBUTE_MODIFIER, "attribute"),
+        (CALLABLE, "callable"),
+        (CONSTANT, "constant"),
+        (CONSUMING, "consuming"),
+        (CONTROL_FLOW, "controlFlow"),
+        (CRATE_ROOT, "crateRoot"),
+        (INJECTED, "injected"),
+        (INTRA_DOC_LINK, "intraDocLink"),
+        (LIBRARY, "library"),
+        (MUTABLE, "mutable"),
+        (PUBLIC, "public"),
+        (REFERENCE, "reference"),
+        (TRAIT_MODIFIER, "trait"),
+        (UNSAFE, "unsafe"),
+    }
 ];
 
 #[derive(Default)]
index e7115b0732e20c6922627cd3675172cae612c686..102cd602950439a4188b5006116353dd164299f8 100644 (file)
@@ -517,7 +517,6 @@ pub(crate) fn semantic_tokens(
     text: &str,
     line_index: &LineIndex,
     highlights: Vec<HlRange>,
-    highlight_strings: bool,
 ) -> lsp_types::SemanticTokens {
     let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string();
     let mut builder = semantic_tokens::SemanticTokensBuilder::new(id);
@@ -526,10 +525,8 @@ pub(crate) fn semantic_tokens(
         if highlight_range.highlight.is_empty() {
             continue;
         }
+
         let (ty, mods) = semantic_token_type_and_modifiers(highlight_range.highlight);
-        if !highlight_strings && ty == lsp_types::SemanticTokenType::STRING {
-            continue;
-        }
         let token_index = semantic_tokens::type_index(ty);
         let modifier_bitset = mods.0;
 
@@ -561,55 +558,55 @@ fn semantic_token_type_and_modifiers(
     let mut mods = semantic_tokens::ModifierSet::default();
     let type_ = match highlight.tag {
         HlTag::Symbol(symbol) => match symbol {
-            SymbolKind::Attribute => semantic_tokens::ATTRIBUTE,
+            SymbolKind::Attribute => semantic_tokens::DECORATOR,
             SymbolKind::Derive => semantic_tokens::DERIVE,
             SymbolKind::DeriveHelper => semantic_tokens::DERIVE_HELPER,
-            SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE,
+            SymbolKind::Module => semantic_tokens::NAMESPACE,
             SymbolKind::Impl => semantic_tokens::TYPE_ALIAS,
-            SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY,
-            SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER,
+            SymbolKind::Field => semantic_tokens::PROPERTY,
+            SymbolKind::TypeParam => semantic_tokens::TYPE_PARAMETER,
             SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER,
             SymbolKind::LifetimeParam => semantic_tokens::LIFETIME,
             SymbolKind::Label => semantic_tokens::LABEL,
-            SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER,
+            SymbolKind::ValueParam => semantic_tokens::PARAMETER,
             SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD,
             SymbolKind::SelfType => semantic_tokens::SELF_TYPE_KEYWORD,
-            SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE,
+            SymbolKind::Local => semantic_tokens::VARIABLE,
             SymbolKind::Function => {
                 if highlight.mods.contains(HlMod::Associated) {
-                    lsp_types::SemanticTokenType::METHOD
+                    semantic_tokens::METHOD
                 } else {
-                    lsp_types::SemanticTokenType::FUNCTION
+                    semantic_tokens::FUNCTION
                 }
             }
             SymbolKind::Const => {
                 mods |= semantic_tokens::CONSTANT;
-                mods |= lsp_types::SemanticTokenModifier::STATIC;
-                lsp_types::SemanticTokenType::VARIABLE
+                mods |= semantic_tokens::STATIC;
+                semantic_tokens::VARIABLE
             }
             SymbolKind::Static => {
-                mods |= lsp_types::SemanticTokenModifier::STATIC;
-                lsp_types::SemanticTokenType::VARIABLE
+                mods |= semantic_tokens::STATIC;
+                semantic_tokens::VARIABLE
             }
-            SymbolKind::Struct => lsp_types::SemanticTokenType::STRUCT,
-            SymbolKind::Enum => lsp_types::SemanticTokenType::ENUM,
-            SymbolKind::Variant => lsp_types::SemanticTokenType::ENUM_MEMBER,
+            SymbolKind::Struct => semantic_tokens::STRUCT,
+            SymbolKind::Enum => semantic_tokens::ENUM,
+            SymbolKind::Variant => semantic_tokens::ENUM_MEMBER,
             SymbolKind::Union => semantic_tokens::UNION,
             SymbolKind::TypeAlias => semantic_tokens::TYPE_ALIAS,
-            SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE,
-            SymbolKind::Macro => lsp_types::SemanticTokenType::MACRO,
+            SymbolKind::Trait => semantic_tokens::INTERFACE,
+            SymbolKind::Macro => semantic_tokens::MACRO,
             SymbolKind::BuiltinAttr => semantic_tokens::BUILTIN_ATTRIBUTE,
             SymbolKind::ToolModule => semantic_tokens::TOOL_MODULE,
         },
         HlTag::AttributeBracket => semantic_tokens::ATTRIBUTE_BRACKET,
         HlTag::BoolLiteral => semantic_tokens::BOOLEAN,
         HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE,
-        HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER,
+        HlTag::ByteLiteral | HlTag::NumericLiteral => semantic_tokens::NUMBER,
         HlTag::CharLiteral => semantic_tokens::CHAR,
-        HlTag::Comment => lsp_types::SemanticTokenType::COMMENT,
+        HlTag::Comment => semantic_tokens::COMMENT,
         HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
         HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
-        HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD,
+        HlTag::Keyword => semantic_tokens::KEYWORD,
         HlTag::None => semantic_tokens::GENERIC,
         HlTag::Operator(op) => match op {
             HlOperator::Bitwise => semantic_tokens::BITWISE,
@@ -618,7 +615,7 @@ fn semantic_token_type_and_modifiers(
             HlOperator::Comparison => semantic_tokens::COMPARISON,
             HlOperator::Other => semantic_tokens::OPERATOR,
         },
-        HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING,
+        HlTag::StringLiteral => semantic_tokens::STRING,
         HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE,
         HlTag::Punctuation(punct) => match punct {
             HlPunct::Bracket => semantic_tokens::BRACKET,
@@ -643,16 +640,16 @@ fn semantic_token_type_and_modifiers(
             HlMod::Consuming => semantic_tokens::CONSUMING,
             HlMod::ControlFlow => semantic_tokens::CONTROL_FLOW,
             HlMod::CrateRoot => semantic_tokens::CRATE_ROOT,
-            HlMod::DefaultLibrary => lsp_types::SemanticTokenModifier::DEFAULT_LIBRARY,
-            HlMod::Definition => lsp_types::SemanticTokenModifier::DECLARATION,
-            HlMod::Documentation => lsp_types::SemanticTokenModifier::DOCUMENTATION,
+            HlMod::DefaultLibrary => semantic_tokens::DEFAULT_LIBRARY,
+            HlMod::Definition => semantic_tokens::DECLARATION,
+            HlMod::Documentation => semantic_tokens::DOCUMENTATION,
             HlMod::Injected => semantic_tokens::INJECTED,
             HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK,
             HlMod::Library => semantic_tokens::LIBRARY,
             HlMod::Mutable => semantic_tokens::MUTABLE,
             HlMod::Public => semantic_tokens::PUBLIC,
             HlMod::Reference => semantic_tokens::REFERENCE,
-            HlMod::Static => lsp_types::SemanticTokenModifier::STATIC,
+            HlMod::Static => semantic_tokens::STATIC,
             HlMod::Trait => semantic_tokens::TRAIT_MODIFIER,
             HlMod::Unsafe => semantic_tokens::UNSAFE,
         };
diff --git a/src/tools/rust-analyzer/crates/stdx/src/hash.rs b/src/tools/rust-analyzer/crates/stdx/src/hash.rs
new file mode 100644 (file)
index 0000000..9909d71
--- /dev/null
@@ -0,0 +1,80 @@
+//! A none hashing [`Hasher`] implementation.
+use std::{
+    hash::{BuildHasher, Hasher},
+    marker::PhantomData,
+};
+
+pub type NoHashHashMap<K, V> = std::collections::HashMap<K, V, NoHashHasherBuilder<K>>;
+pub type NoHashHashSet<K> = std::collections::HashSet<K, NoHashHasherBuilder<K>>;
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct NoHashHasherBuilder<T>(PhantomData<T>);
+
+impl<T> Default for NoHashHasherBuilder<T> {
+    fn default() -> Self {
+        Self(Default::default())
+    }
+}
+
+pub trait NoHashHashable {}
+impl NoHashHashable for usize {}
+impl NoHashHashable for u32 {}
+
+pub struct NoHashHasher(u64);
+
+impl<T: NoHashHashable> BuildHasher for NoHashHasherBuilder<T> {
+    type Hasher = NoHashHasher;
+    fn build_hasher(&self) -> Self::Hasher {
+        NoHashHasher(0)
+    }
+}
+
+impl Hasher for NoHashHasher {
+    fn finish(&self) -> u64 {
+        self.0
+    }
+
+    fn write(&mut self, _: &[u8]) {
+        unimplemented!("NoHashHasher should only be used for hashing primitive integers")
+    }
+
+    fn write_u8(&mut self, i: u8) {
+        self.0 = i as u64;
+    }
+
+    fn write_u16(&mut self, i: u16) {
+        self.0 = i as u64;
+    }
+
+    fn write_u32(&mut self, i: u32) {
+        self.0 = i as u64;
+    }
+
+    fn write_u64(&mut self, i: u64) {
+        self.0 = i as u64;
+    }
+
+    fn write_usize(&mut self, i: usize) {
+        self.0 = i as u64;
+    }
+
+    fn write_i8(&mut self, i: i8) {
+        self.0 = i as u64;
+    }
+
+    fn write_i16(&mut self, i: i16) {
+        self.0 = i as u64;
+    }
+
+    fn write_i32(&mut self, i: i32) {
+        self.0 = i as u64;
+    }
+
+    fn write_i64(&mut self, i: i64) {
+        self.0 = i as u64;
+    }
+
+    fn write_isize(&mut self, i: isize) {
+        self.0 = i as u64;
+    }
+}
index b4d45206c44ea6fabb1b4cd8a73983d0e7e0e45c..51e109798d1df3c22f119920424fd11969986936 100644 (file)
@@ -7,6 +7,7 @@
 use std::{io as sio, iter};
 
 mod macros;
+pub mod hash;
 pub mod process;
 pub mod panic_context;
 pub mod non_empty_vec;
index c6377348784a46a2eea7de09d11968b8e6c079e2..d7549a2841539bb1e9df66e5592d99b5d7c8a809 100644 (file)
@@ -12,6 +12,7 @@ doctest = false
 [dependencies]
 rustc-hash = "1.1.0"
 fst = "0.4.7"
+indexmap = "1.9.1"
 
 paths = { path = "../paths", version = "0.0.0" }
-indexmap = "1.9.1"
+stdx = { path = "../stdx", version = "0.0.0" }
index 6a89263e53988723aaa0623a036c3f1e69ff1c51..e0ef737b3fc09efe338e12ac996d8faf3690134a 100644 (file)
@@ -6,6 +6,7 @@
 
 use fst::{IntoStreamer, Streamer};
 use rustc_hash::FxHashMap;
+use stdx::hash::NoHashHashMap;
 
 use crate::{AnchoredPath, FileId, Vfs, VfsPath};
 
@@ -13,7 +14,7 @@
 #[derive(Default, Clone, Eq, PartialEq)]
 pub struct FileSet {
     files: FxHashMap<VfsPath, FileId>,
-    paths: FxHashMap<FileId, VfsPath>,
+    paths: NoHashHashMap<FileId, VfsPath>,
 }
 
 impl FileSet {
index 7badb1c363b44b46cfa0b74766a6fd74eae9d878..afc9a0fa6fb206b1a0c41024137639f016518697 100644 (file)
 /// Handle to a file in [`Vfs`]
 ///
 /// Most functions in rust-analyzer use this when they need to refer to a file.
-#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
+#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
 pub struct FileId(pub u32);
 
+impl stdx::hash::NoHashHashable for FileId {}
+impl std::hash::Hash for FileId {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+    }
+}
+
 /// Storage for all files read by rust-analyzer.
 ///
 /// For more information see the [crate-level](crate) documentation.
index 751ec79af0fd4f2bcb644017d6209eaecde5e4fb..72b925726479e014c18142acb6b4546bffc2b2b8 100644 (file)
@@ -587,6 +587,52 @@ Enables the use of rustfmt's unstable range formatting command for the
 `textDocument/rangeFormatting` request. The rustfmt option is unstable and only
 available on a nightly build.
 --
+[[rust-analyzer.semanticHighlighting.doc.comment.inject.enable]]rust-analyzer.semanticHighlighting.doc.comment.inject.enable (default: `true`)::
++
+--
+Inject additional highlighting into doc comments.
+
+When enabled, rust-analyzer will highlight rust source in doc comments as well as intra
+doc links.
+--
+[[rust-analyzer.semanticHighlighting.operator.enable]]rust-analyzer.semanticHighlighting.operator.enable (default: `true`)::
++
+--
+Use semantic tokens for operators.
+
+When disabled, rust-analyzer will emit semantic tokens only for operator tokens when
+they are tagged with modifiers.
+--
+[[rust-analyzer.semanticHighlighting.operator.specialization.enable]]rust-analyzer.semanticHighlighting.operator.specialization.enable (default: `false`)::
++
+--
+Use specialized semantic tokens for operators.
+
+When enabled, rust-analyzer will emit special token types for operator tokens instead
+of the generic `operator` token type.
+--
+[[rust-analyzer.semanticHighlighting.punctuation.enable]]rust-analyzer.semanticHighlighting.punctuation.enable (default: `false`)::
++
+--
+Use semantic tokens for punctuations.
+
+When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when
+they are tagged with modifiers or have a special role.
+--
+[[rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang]]rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang (default: `false`)::
++
+--
+When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro
+calls.
+--
+[[rust-analyzer.semanticHighlighting.punctuation.specialization.enable]]rust-analyzer.semanticHighlighting.punctuation.specialization.enable (default: `false`)::
++
+--
+Use specialized semantic tokens for punctuations.
+
+When enabled, rust-analyzer will emit special token types for punctuation tokens instead
+of the generic `punctuation` token type.
+--
 [[rust-analyzer.semanticHighlighting.strings.enable]]rust-analyzer.semanticHighlighting.strings.enable (default: `true`)::
 +
 --
index c482fcbed0e01ccea9ab998dad16a7649f6fb61a..9bd3b6a692b1a7514263ca06c4b39e97281f42df 100644 (file)
@@ -861,3 +861,14 @@ For example, if you want to run https://crates.io/crates/cargo-watch[`cargo watc
     "isBackground": true
 }
 ```
+
+==== Live Share
+
+VS Code Live Share has partial support for rust-analyzer.
+
+Live Share _requires_ the official Microsoft build of VS Code, OSS builds will not work correctly.
+
+The host's rust-analyzer instance will be shared with all guests joining the session.
+The guests do not have to have the rust-analyzer extension installed for this to work.
+
+If you are joining a Live Share session and _do_ have rust-analyzer installed locally, commands from the command palette will not work correctly since they will attempt to communicate with the local server.
index 67eabc313c832b75478a5d303e57104f21df50a8..767c5875bf7e7e844c1178675ee082288ff1ac29 100644 (file)
                     "default": false,
                     "type": "boolean"
                 },
+                "rust-analyzer.semanticHighlighting.doc.comment.inject.enable": {
+                    "markdownDescription": "Inject additional highlighting into doc comments.\n\nWhen enabled, rust-analyzer will highlight rust source in doc comments as well as intra\ndoc links.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.semanticHighlighting.operator.enable": {
+                    "markdownDescription": "Use semantic tokens for operators.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for operator tokens when\nthey are tagged with modifiers.",
+                    "default": true,
+                    "type": "boolean"
+                },
+                "rust-analyzer.semanticHighlighting.operator.specialization.enable": {
+                    "markdownDescription": "Use specialized semantic tokens for operators.\n\nWhen enabled, rust-analyzer will emit special token types for operator tokens instead\nof the generic `operator` token type.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.semanticHighlighting.punctuation.enable": {
+                    "markdownDescription": "Use semantic tokens for punctuations.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when\nthey are tagged with modifiers or have a special role.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang": {
+                    "markdownDescription": "When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro\ncalls.",
+                    "default": false,
+                    "type": "boolean"
+                },
+                "rust-analyzer.semanticHighlighting.punctuation.specialization.enable": {
+                    "markdownDescription": "Use specialized semantic tokens for punctuations.\n\nWhen enabled, rust-analyzer will emit special token types for punctuation tokens instead\nof the generic `punctuation` token type.",
+                    "default": false,
+                    "type": "boolean"
+                },
                 "rust-analyzer.semanticHighlighting.strings.enable": {
                     "markdownDescription": "Use semantic tokens for strings.\n\nIn some editors (e.g. vscode) semantic tokens override other highlighting grammars.\nBy disabling semantic tokens for strings, other grammars can be used to highlight\ntheir contents.",
                     "default": true,
index 27ab31db8db4fc668b91953bae3d45cca59dc6e2..05d4d08f70b62d17436dcb32715011bb53449dd6 100644 (file)
@@ -5,7 +5,6 @@ import * as Is from "vscode-languageclient/lib/common/utils/is";
 import { assert } from "./util";
 import { WorkspaceEdit } from "vscode";
 import { Workspace } from "./ctx";
-import { updateConfig } from "./config";
 import { substituteVariablesInEnv } from "./config";
 import { outputChannel, traceOutputChannel } from "./main";
 import { randomUUID } from "crypto";
@@ -86,11 +85,6 @@ export async function createClient(
 
     let initializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
 
-    // Update outdated user configs
-    await updateConfig(initializationOptions).catch((err) => {
-        void vscode.window.showErrorMessage(`Failed updating old config keys: ${err.message}`);
-    });
-
     if (workspace.kind === "Detached Files") {
         initializationOptions = {
             detachedFiles: workspace.files.map((file) => file.uri.fsPath),
@@ -105,22 +99,6 @@ export async function createClient(
         traceOutputChannel: traceOutputChannel(),
         outputChannel: outputChannel(),
         middleware: {
-            async handleDiagnostics(uri, diagnostics, next) {
-                // Workaround for https://github.com/microsoft/vscode/issues/155531
-                for (const diagnostic of diagnostics) {
-                    if (!diagnostic.message) {
-                        diagnostic.message = " ";
-                    }
-                    if (diagnostic.relatedInformation) {
-                        for (const relatedInformation of diagnostic.relatedInformation) {
-                            if (!relatedInformation.message) {
-                                relatedInformation.message = " ";
-                            }
-                        }
-                    }
-                }
-                next(uri, diagnostics);
-            },
             async provideHover(
                 document: vscode.TextDocument,
                 position: vscode.Position,
index b83582a344a9841ae61063a88f0cbde0864ef4e9..a9c0f079b3da9350eeb3624fbed5247b465da7d9 100644 (file)
@@ -3,8 +3,6 @@ import * as vscode from "vscode";
 import { Env } from "./client";
 import { log } from "./util";
 
-export type UpdatesChannel = "stable" | "nightly";
-
 export type RunnableEnvCfg =
     | undefined
     | Record<string, string>
@@ -175,100 +173,6 @@ export class Config {
     }
 }
 
-export async function updateConfig(config: vscode.WorkspaceConfiguration) {
-    const renames = [
-        ["assist.allowMergingIntoGlobImports", "imports.merge.glob"],
-        ["assist.exprFillDefault", "assist.expressionFillDefault"],
-        ["assist.importEnforceGranularity", "imports.granularity.enforce"],
-        ["assist.importGranularity", "imports.granularity.group"],
-        ["assist.importMergeBehavior", "imports.granularity.group"],
-        ["assist.importMergeBehaviour", "imports.granularity.group"],
-        ["assist.importGroup", "imports.group.enable"],
-        ["assist.importPrefix", "imports.prefix"],
-        ["primeCaches.enable", "cachePriming.enable"],
-        ["cache.warmup", "cachePriming.enable"],
-        ["cargo.loadOutDirsFromCheck", "cargo.buildScripts.enable"],
-        ["cargo.runBuildScripts", "cargo.buildScripts.enable"],
-        ["cargo.runBuildScriptsCommand", "cargo.buildScripts.overrideCommand"],
-        ["cargo.useRustcWrapperForBuildScripts", "cargo.buildScripts.useRustcWrapper"],
-        ["completion.snippets", "completion.snippets.custom"],
-        ["diagnostics.enableExperimental", "diagnostics.experimental.enable"],
-        ["experimental.procAttrMacros", "procMacro.attributes.enable"],
-        ["highlighting.strings", "semanticHighlighting.strings.enable"],
-        ["highlightRelated.breakPoints", "highlightRelated.breakPoints.enable"],
-        ["highlightRelated.exitPoints", "highlightRelated.exitPoints.enable"],
-        ["highlightRelated.yieldPoints", "highlightRelated.yieldPoints.enable"],
-        ["highlightRelated.references", "highlightRelated.references.enable"],
-        ["hover.documentation", "hover.documentation.enable"],
-        ["hover.linksInHover", "hover.links.enable"],
-        ["hoverActions.linksInHover", "hover.links.enable"],
-        ["hoverActions.debug", "hover.actions.debug.enable"],
-        ["hoverActions.enable", "hover.actions.enable.enable"],
-        ["hoverActions.gotoTypeDef", "hover.actions.gotoTypeDef.enable"],
-        ["hoverActions.implementations", "hover.actions.implementations.enable"],
-        ["hoverActions.references", "hover.actions.references.enable"],
-        ["hoverActions.run", "hover.actions.run.enable"],
-        ["inlayHints.chainingHints", "inlayHints.chainingHints.enable"],
-        ["inlayHints.closureReturnTypeHints", "inlayHints.closureReturnTypeHints.enable"],
-        ["inlayHints.hideNamedConstructorHints", "inlayHints.typeHints.hideNamedConstructor"],
-        ["inlayHints.parameterHints", "inlayHints.parameterHints.enable"],
-        ["inlayHints.reborrowHints", "inlayHints.reborrowHints.enable"],
-        ["inlayHints.typeHints", "inlayHints.typeHints.enable"],
-        ["lruCapacity", "lru.capacity"],
-        ["runnables.cargoExtraArgs", "runnables.extraArgs"],
-        ["runnables.overrideCargo", "runnables.command"],
-        ["rustcSource", "rustc.source"],
-        ["rustfmt.enableRangeFormatting", "rustfmt.rangeFormatting.enable"],
-    ];
-
-    for (const [oldKey, newKey] of renames) {
-        const inspect = config.inspect(oldKey);
-        if (inspect !== undefined) {
-            const valMatrix = [
-                {
-                    val: inspect.globalValue,
-                    langVal: inspect.globalLanguageValue,
-                    target: vscode.ConfigurationTarget.Global,
-                },
-                {
-                    val: inspect.workspaceFolderValue,
-                    langVal: inspect.workspaceFolderLanguageValue,
-                    target: vscode.ConfigurationTarget.WorkspaceFolder,
-                },
-                {
-                    val: inspect.workspaceValue,
-                    langVal: inspect.workspaceLanguageValue,
-                    target: vscode.ConfigurationTarget.Workspace,
-                },
-            ];
-            for (const { val, langVal, target } of valMatrix) {
-                const patch = (val: unknown) => {
-                    // some of the updates we do only append "enable" or "custom"
-                    // that means on the next run we would find these again, but as objects with
-                    // these properties causing us to destroy the config
-                    // so filter those already updated ones out
-                    return (
-                        val !== undefined &&
-                        !(
-                            typeof val === "object" &&
-                            val !== null &&
-                            (oldKey === "completion.snippets" || !val.hasOwnProperty("custom"))
-                        )
-                    );
-                };
-                if (patch(val)) {
-                    await config.update(newKey, val, target, false);
-                    await config.update(oldKey, undefined, target, false);
-                }
-                if (patch(langVal)) {
-                    await config.update(newKey, langVal, target, true);
-                    await config.update(oldKey, undefined, target, true);
-                }
-            }
-        }
-    }
-}
-
 export function substituteVariablesInEnv(env: Env): Env {
     const missingDeps = new Set<string>();
     // vscode uses `env:ENV_NAME` for env vars resolution, and it's easier
index a9847dd2a6521ba013d76b4c7562ff89334397c9..e9b62e0cc2578b876747093577439bfec057192e 100644 (file)
@@ -33,7 +33,7 @@ export function outputChannel() {
 }
 
 export interface RustAnalyzerExtensionApi {
-    client: lc.LanguageClient;
+    client?: lc.LanguageClient;
 }
 
 export async function activate(
@@ -48,6 +48,23 @@ export async function activate(
 }
 
 async function tryActivate(context: vscode.ExtensionContext): Promise<RustAnalyzerExtensionApi> {
+    // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
+    // only those are in use.
+    // (r-a still somewhat works with Live Share, because commands are tunneled to the host)
+    const folders = (vscode.workspace.workspaceFolders || []).filter(
+        (folder) => folder.uri.scheme === "file"
+    );
+    const rustDocuments = vscode.workspace.textDocuments.filter((document) =>
+        isRustDocument(document)
+    );
+
+    if (folders.length === 0 && rustDocuments.length === 0) {
+        // FIXME: Ideally we would choose not to activate at all (and avoid registering
+        // non-functional editor commands), but VS Code doesn't seem to have a good way of doing
+        // that
+        return {};
+    }
+
     const config = new Config(context);
     const state = new PersistentState(context.globalState);
     const serverPath = await bootstrap(context, config, state).catch((err) => {
@@ -60,18 +77,11 @@ async function tryActivate(context: vscode.ExtensionContext): Promise<RustAnalyz
         throw new Error(message);
     });
 
-    if ((vscode.workspace.workspaceFolders || []).length === 0) {
-        const rustDocuments = vscode.workspace.textDocuments.filter((document) =>
-            isRustDocument(document)
-        );
-        if (rustDocuments.length > 0) {
-            ctx = await Ctx.create(config, context, serverPath, {
-                kind: "Detached Files",
-                files: rustDocuments,
-            });
-        } else {
-            throw new Error("no rust files are opened");
-        }
+    if (folders.length === 0) {
+        ctx = await Ctx.create(config, context, serverPath, {
+            kind: "Detached Files",
+            files: rustDocuments,
+        });
     } else {
         // Note: we try to start the server before we activate type hints so that it
         // registers its `onDidChangeDocument` handler before us.
index 4a59c4c0fad050a65372a56b2c2281cdd4ca0423..36d728456f77c48248c34102ad2ab5f6fc1da12b 100644 (file)
@@ -15,7 +15,7 @@ pub(crate) fn socket_transport(
     stream: TcpStream,
 ) -> (Sender<Message>, Receiver<Message>, IoThreads) {
     let (reader_receiver, reader) = make_reader(stream.try_clone().unwrap());
-    let (writer_sender, writer) = make_write(stream.try_clone().unwrap());
+    let (writer_sender, writer) = make_write(stream);
     let io_threads = make_io_threads(reader, writer);
     (writer_sender, reader_receiver, io_threads)
 }
index 5770bb7bc33cebfc1ad4610aa0d2871ea79e356d..05e1eb2bfb00695a6f981f917b20eeaa83880329 100644 (file)
     "time",
     "tinystr",
     "tinyvec",
+    "thin-vec",
     "tracing",
     "tracing-attributes",
     "tracing-core",
     "unicode-width",
     "unicode-xid",
     "vcpkg",
+    "valuable",
     "version_check",
     "wasi",
     "winapi",
index 8a90bc0e3c143c91f8d9ca8c2cc87e396da1ef11..89d1574726f090597e9a130fa3c1ebfa935857f5 100644 (file)
@@ -195,6 +195,13 @@ trigger_files = [
     "compiler/rustc_macros/src/diagnostics"
 ]
 
+[autolabel."A-query-system"]
+trigger_files = [
+    "compiler/rustc_query_system",
+    "compiler/rustc_query_impl",
+    "compiler/rustc_macros/src/query.rs"
+]
+
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "#{number} {title}"